Blazor WebAssembly CRUD

Blazor WebAssembly CRUD Application with Entity Framework

Setup The Blazor Application

Follow the Getting Started guide to set up your Blazor Application with Smart UI.
Make sure that that the application is ASP.NET Core hosted:
Creating project

Create SQL Data

The following steps detail how to create a SQL Database in Visual Studio 2022 and fill it with data. If you already have SQL Database, continue to Connect Blazor to SQL Data.

  1. To create a table, first you need to create a database for your application. Navigate to View -> SQL Server Object Explorer
  2. Inside the localdb -> Databases directory, create a new SQL database by right-clicking on the Databases folder. For the purpose of the Demo, we will create people.db People database
  3. To create a table, right-click on the database and select New Query.... Then paste the following SQL code to create a table of our clients:
    CREATE TABLE [dbo].[peopleTable] (
      [Id]      INT IDENTITY(1,1)  NOT NULL,
      [Name]    NCHAR (50) NULL,
      [Balance] FLOAT (50) NULL,
      [City]    NCHAR (50) NULL,
      [Country] NCHAR (50) NULL,
      PRIMARY KEY CLUSTERED ([Id] ASC)
    );
    
    INSERT INTO [dbo].[peopleTable] ([Id], [Name], [Balance], [City], [Country]) VALUES (1, N'Maria Anders', 130.0000, N'Berlin', N'Germany')
    INSERT INTO [dbo].[peopleTable] ([Id], [Name], [Balance], [City], [Country]) VALUES (2, N'Ana Trujillo', 230.0000, N'Mxico D.F.', N'Mexico')
    INSERT INTO [dbo].[peopleTable] ([Id], [Name], [Balance], [City], [Country]) VALUES (3, N'Antonio Moreno', 3500.0000, N'Mxico D.F.', N'Mexico')
    INSERT INTO [dbo].[peopleTable] ([Id], [Name], [Balance], [City], [Country]) VALUES (4, N'Thomas Hardy', 55.0000, N'London', N'UK')
    INSERT INTO [dbo].[peopleTable] ([Id], [Name], [Balance], [City], [Country]) VALUES (5, N'Christina Berglund', 1500.0000, N'Lule', N'Sweden')
    INSERT INTO [dbo].[peopleTable] ([Id], [Name], [Balance], [City], [Country]) VALUES (6, N'Hanna Moos', 650.0000, N'Mannheim', N'Germany')
    INSERT INTO [dbo].[peopleTable] ([Id], [Name], [Balance], [City], [Country]) VALUES (7, N'Frdrique Citeaux', 50.0000, N'Strasbourg', N'France')
    INSERT INTO [dbo].[peopleTable] ([Id], [Name], [Balance], [City], [Country]) VALUES (8, N'Martn Sommer', 0.0000, N'Madrid', N'Spain')
    Table records

Connect Blazor to SQL Data

The following steps detail how to connect your SQL Data to the Blazor Application. If your data is already connected, continue to Bind Grid to SQL Data

  1. Using the Visual Studio NuGet Package Manager, add the following dependancies to project:
    • Microsoft.EntityFrameworkCore.SqlServer
    • Microsoft.EntityFrameworkCore.Tools
    NuGet Package Manager
  2. Inside BlazorProject.Shared, create a new folder "Models", then create a new new item of type Class called Person.cs
    This is where we will define the properties of each individual Person from our SQL table:
    namespace BlazorProject.Shared.Models
    {
        public class Person
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public double Balance { get; set; }
            public string City { get; set; }
            public string Country { get; set; }
        }
    }
  3. Inside the same folder, create a new Class item called IDataAccessProvider.cs - this is the inerface, where we will store our CRUD methods: This is where we will create the LoadData function:
    namespace BlazorProject.Shared.Models   
    {
        public interface IDataAccessProvider
        {
            void AddClientRecord(Person person);
            void UpdateClientRecord(Person person);
            void DeleteClientRecord(int id);
            Person GetClientRecord(int id);
            List<Person> GetClientRecords();
        }
    }
    Models folder directory
  4. Navigate to BlazorProject.Shared, create a new folder "DataAccess", create a new item DomainModelSqlContext.cs, which will be our backend:
    using BlazorProject.Shared.Models;
    using Microsoft.EntityFrameworkCore;
    
    namespace BlazorProject.Server.DataAccess
    {
        public class DomainModelSqlContext : DbContext
        {
            public DomainModelSqlContext(DbContextOptions<DomainModelSqlContext> options) : base(options)
            {
            }
    
            public DbSet<Person> peopleTable { get; set; }
    
            protected override void OnModelCreating(ModelBuilder builder)
            {
                base.OnModelCreating(builder);
            }
    
            public override int SaveChanges()
            {
                ChangeTracker.DetectChanges();
                return base.SaveChanges();
            }
    
        }
    }

    In the same folder, create a new item called DataAccessSqlProvider.cs, which will execute the functions in our backend

    using BlazorProject.Shared.Models;
    
    namespace BlazorProject.Server.DataAccess
    {
        public class DataAccessSqlProvider : IDataAccessProvider
        {
            private readonly DomainModelSqlContext _context;
    
            public DataAccessSqlProvider(DomainModelSqlContext context)
            {
                _context = context;
            }
    
            public void AddClientRecord(Person person)
            {
                _context.peopleTable.Add(person);
                _context.SaveChanges();
            }
    
            public void UpdateClientRecord(Person person)
            {
                _context.peopleTable.Update(person);
                _context.SaveChanges();
            }
    
            public void DeleteClientRecord(int id)
            {
                var entity = _context.peopleTable.First(t => t.Id == id);
                _context.peopleTable.Remove(entity);
                _context.SaveChanges();
            }
    
            public Person GetClientRecord(int id)
            {
                return _context.peopleTable.First(t => t.Id == id);
            }
    
            public List<Person> GetClientRecords()
            {
                return _context.peopleTable.ToList();
            }
    
        }
    }
    Data Access folder
  5. To create our Web API controller, create a new item called ClientsController.cs inside the Controllers folder:

    using BlazorProject.Shared.Models;
    using Microsoft.AspNetCore.Mvc;
    
    namespace BlazorProject.Server.Controllers
    {
        public class ClientsController : Controller
        {
            private readonly IDataAccessProvider _dataAccessProvider;
    
            public ClientsController(IDataAccessProvider dataAccessProvider)
            {
                _dataAccessProvider = dataAccessProvider;
            }
    
            [HttpGet]
            [Route("api/Clients/Get")]
            public IEnumerable<Person> Get()
            {
                return _dataAccessProvider.GetClientRecords();
            }
    
            [HttpPost]
            [Route("api/Clients/Create")]
            public void Create([FromBody] Person person)
            {
                if (ModelState.IsValid)
                {
                    _dataAccessProvider.AddClientRecord(person);
                }
            }
    
            [HttpGet]
            [Route("api/CLients/Details/{id}")]
            public Person Details(int id)
            {
                return _dataAccessProvider.GetClientRecord(id);
            }
    
            [HttpPut]
            [Route("api/Clients/Edit")]
            public void Edit([FromBody] Person person)
            {
                if (ModelState.IsValid)
                {
                    _dataAccessProvider.UpdateClientRecord(person);
                }
            }
    
            [HttpDelete]
            [Route("api/Clients/Delete/{id}")]
            public void DeleteConfirmed(int id)
            {
                _dataAccessProvider.DeleteClientRecord(id);
            }
        }
    }
    Controllers folder
  6. Navigate to people.db using the SQL Server Object Explorer, right-click and select properties. Then copy the value of the "Connection string" property:
    Database properties

    Inside BlazorProject.Shared, navigate to appsettings.json and set ConnectionStrings.Default to the copied value:


    JSON appsettings
  7. Finally, open Program.cs and add the following services:
    using BlazorProject.Server.DataAccess;
    using BlazorProject.Shared.Models;
    using Microsoft.EntityFrameworkCore;
    
    ....
    
    ConfigurationManager configuration = builder.Configuration;
    builder.Services.AddDbContext<DomainModelSqlContext>(options => options.UseSqlServer(configuration.GetConnectionString("Default")));
    builder.Services.AddScoped<IDataAccessProvider, DataAccessSqlProvider>();
              

Bind Grid to SQL Data

  1. Add the Grid component to the Pages/Index.razor file of BlazorProject.Client and set the Columns to display:
    <Grid DataSource="@people" DataSourceSettings="@dataSourceSettings">
      <Columns>
        <Column DataField="Name" Label="Client Name"></Column>
        <Column DataField="Balance" Label="Acccount Balance"></Column>
        <Column DataField="City" Label="City"></Column>
        <Column DataField="Country" Label="Country"></Column>
      </Columns>
    </Grid>
  2. Inject the necessary libraries and the Models at the top of the page:
    @page "/"
    @inject HttpClient Http
    @using System.Net.Http.Json
    @using Smart.Blazor
    @using BlazorProject.Shared.Models
              
  3. Inside the @code block, create an HTTP request to the table when the page has loaded and set the people Array as a DataSource to the Grid. Then specify the DataSourceType inside a GridDataSourceSettings object and set it as a property of the Grid.
    Note that setting the DataType of the Columns is not mandatory, but it is recommended if you plan to use the Smart.Grid's Filtering & Sorting functionalities
    @page "/"
    @inject HttpClient Http
    @using System.Net.Http.Json
    @using Smart.Blazor
    @using BlazorProject.Shared.Models
    
    <PageTitle>Index</PageTitle>
    
    <h1>Blazor Web Assembly with SQL!</h1>
    
    @if(@people != null){
      <Grid DataSource="@people" DataSourceSettings="@dataSourceSettings">}
        <Columns>
            <Column DataField="Name" Label="Client Name"></Column>
            <Column DataField="Balance" Label="Acccount Balance"></Column>
            <Column DataField="City" Label="City"></Column>
            <Column DataField="Country" Label="Country"></Column>
        </Columns>
      </Grid>
    }
    else{
        <p>Loading...</p>
    }
    
    
    @code{
        GridDataSourceSettings dataSourceSettings = new GridDataSourceSettings()
        {
            DataFields = new List<IGridDataSourceSettingsDataField>()
    {
                new GridDataSourceSettingsDataField() { Name = "Id", DataType = GridDataSourceSettingsDataFieldDataType.Number },
                new GridDataSourceSettingsDataField() { Name = "Name", DataType = GridDataSourceSettingsDataFieldDataType.String },
                new GridDataSourceSettingsDataField() { Name = "Balance", DataType = GridDataSourceSettingsDataFieldDataType.Number },
                new GridDataSourceSettingsDataField() { Name = "City", DataType = GridDataSourceSettingsDataFieldDataType.String },
                new GridDataSourceSettingsDataField() { Name = "Country", DataType = GridDataSourceSettingsDataFieldDataType.String }
            },
            DataSourceType = GridDataSourceSettingsDataSourceType.Array
        };
    
        Person[] people;
    
        protected override async Task OnInitializedAsync()
        {
            people = await Http.GetFromJsonAsync<Person[]>("/api/Clients/Get");
        }
    }
Grid bound to SQL

CRUD with Blazor Grid

Once Blazor is connected with the database, it is not difficult to create a CRUD application using Smart.Grid

  • Add Create functionality

    Create a "Add new row" Button. Then create an AddRow() function that creates a new person and then fetches the updated SQL Table:

    <Button OnClick="AddRow">Add new row</Button>
    .....
    @code{
      .....
      private async Task AddRow()
        { 
            Person person = new Person()
            {
                Name = "John",
                Balance = 1000,
                City = "Paris",
                Country = "France"
    
            };
            await Http.PostAsJsonAsync("/api/Clients/Create", person);
            people = await Http.GetFromJsonAsync<Person[]>("/api/Clients/Get");
        }
    }
    New row added
  • Add Delete Functionality

    Add a "Delete last row" Button. Then create a DeleteLastRow() function that removes the last SQL Record and then fetches the updated SQL Table:

    <Button OnClick="DeleteLastRow">Delete row</Button>
    .....
    @code{
      .....
      private async Task DeleteLastRow()
      {
        int lastId = people[people.Length - 1].Id;
        await Http.DeleteAsync("api/Clients/Delete/" + lastId);
        people = await Http.GetFromJsonAsync<Person[]>("/api/Clients/Get");
      }
    }
    Last row deleted
  • Add Update Functionality

    To add Update functionality, first enable Grid Editing using the Editing property. We will use the OnEndEdit Event to update the SQL Table after every change:

    <Grid @ref="@grid" DataSource="@people" DataSourceSettings="@dataSourceSettings" OnEndEdit="OnEndEdit" Editing="@editing">
      <Columns>
        <Column DataField="Name" Label="Client Name"></Column>
        <Column DataField="Balance" Label="Acccount Balance"></Column>
        <Column DataField="City" Label="City"></Column>
        <Column DataField="Country" Label="Country"></Column>
      </Columns>
    </Grid>
    @code{
      Grid grid;
      GridEditing editing = new GridEditing()
      {
          Enabled = true,
          Mode = GridEditingMode.Cell
      };
      .....
    }

    Create a new OnEndEdit() function. Using the Event.detail, get the values of the edited row and use the Edit HTTP request to make changes in the SQL Table:

    private async Task OnEndEdit(Event ev)
    {
        GridEndEditEventDetail EventDetail = ev["Detail"];
        dynamic Editedrow = JObject.Parse((await grid.GetRowData(EventDetail.Row)).ToString());
    
        int EditedId = (Editedrow.Id).ToObject<int>();
        string EditedName = (Editedrow.Name).ToObject<string>();
        double EditedBalance = (Editedrow.Balance).ToObject<double>();
        string EditedCity = (Editedrow.City).ToObject<string>();
        string EditedCountry = (Editedrow.Country).ToObject<string>();
            Person person = new Person()
        {
            Id = EditedId,
            Name = EditedName,
            Balance = EditedBalance,
            City = EditedCity,
            Country = EditedCountry
    
        };
        await Http.PutAsJsonAsync("/api/Clients/Edit", person);
    } 
    Editing Grid

    We can see that the changes are reflected in the SQL Table:

    Updated SQL table