Create a .NET 6 App On Blazor WASM For CRUD Operations With EF Core

Introduction

In this blog, we will learn about how to create a .NET Core 6.0 Blazor WebAssembly application that can do CRUD operations using EF Core.

Prerequisites

  • Visual Studio 2022 installed,
  • Microsoft SQL Server 18,
  • Basics of Asp.Net Web, Entity Framework

Source Code

This source code is publically available on GitHub link

Step1

Open Visual Studio 2022 Click on Create a New Project, choose a Blazor WebAssembly.

Click next, then setup your Project Name, then click next.

Then Choose Framework - .Net 6.0 (Long Term Support), check on checkbox called ASP.Net Core hosted, then click Create.

Step 2

A template of Blazor Application has been created, you can run and see the following output.

Our solution will have three projects Client, Server and Shared.

On Client project we will place the client-side razor pages and client-side libraries.

On Server project we will place Controller, Service, Repository, Entity class, DbContext for EF etc.

On Shared project we will place a DTO/View model for client-side pages.

Step 3

On Shared project create a class called PersonViewModel

Inside PersonViewModel place the following code:

public class PersonViewModel {
    public int Id {
        get;
        set;
    }
    [Required]
    [Display(Name = "First Name")]
    public string FirstName {
        get;
        set;
    }
    [Required]
    [Display(Name = "Last Name")]
    public string LastName {
        get;
        set;
    }
    [Required]
    [Display(Name = "Email")]
    public string Email {
        get;
        set;
    }
    [Required]
    [Display(Name = "Mobile Number")]
    public string MobileNo {
        get;
        set;
    }
}

Step 4

Inside Shared folder of client project there is a NavMenu.razor page edit this page to add NavMenu for Person.

Add the following code for new menu option Personal Info :

<div class="nav-item px-3">
    <NavLink class="nav-link" href="personList">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Personal Info
    </NavLink>
</div>	

Right Click on Pages > Add > Razor component.

Let’s create a component PersonList.razor

Inside PersonList.razor place the following code:

@page "/personlist"
@using BlazorCRUDApp.Shared
@inject HttpClient _httpClient
<h1>Personal Detail</h1>
<div>
    <a href="/addperson"> Create New Person</a>
    @if (personList != null)
    {
        <table class="table-bordered">
            <thead>
                <tr>
                    <th width = "30%">Name</th>
                    <th width = "20%">Email</th>
                    <th width = "20%">Mobile No</th>
                    <th width = "30%">Action</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var p in personList)
                {
                    <tr>
                        <td>
                            @p.FirstName @p.LastName
                        </td>
                    <td>@p.Email</td>
                    <td>@p.MobileNo</td>
                    <td>
                        <a href="/editperson/@p.Id">Edit</a> |
                        <a href="/deleteperson/@p.Id">Delete</a>
                    </td>
                    </tr>
                }
            </tbody>
        </table>
    }
</div>
@code {
    List<PersonViewModel> personList = new List<PersonViewModel>();
    protected override async Task OnInitializedAsync()
    {
        var response = await _httpClient.GetAsync("api/person");
        response.EnsureSuccessStatusCode();
        personList = await response.Content.ReadFromJsonAsync<List<PersonViewModel>>();
    }
}

Let’s create another component AddPerson.razor.

Inside AddPerson.razor place the following code:

@page "/addperson"
@using BlazorCRUDApp.Shared
@inject HttpClient Http
@inject NavigationManager NavigationManager
@inject IJSRuntime JsRuntime
<h2>Add Person</h2>
<div class="row">
        <div class="col-md-6">
                <div class="form-group">
                        <label for="FirstName"> First Name *</label>
                        <input form="FirstName" class="form-control" @bind="@person.FirstName" />
                    </div>
            </div>
        <div class="col-md-6">
                <div class="form-group">
                        <label for="LastName"> Last Name *</label>
                        <input form="LastName" class="form-control" @bind="@person.LastName" />
                    </div>
            </div>
        <div class="col-md-6">
                <div class="form-group">
                        <label for="Email"> Email *</label>
                        <input form="Email" class="form-control" @bind="@person.Email" />
                    </div>
            </div>
        <div class="col-md-6">
                <div class="form-group">
                        <label for="MobileNo"> Mobile No *</label>
                        <input form="mobileNo" class="form-control" @bind="@person.MobileNo" />
                    </div>
            </div>
</div>
<div class="row">
        <div class="col-md-4">
                <div class="form-group">
                        <input type="button" class="btn btn-primary" @onclick="@Save" value="Save" />
                        <input type="button" class="btn" @onclick="@Cancel" value="Cancel" />
                    </div>
            </div>
</div>
@code {
    PersonViewModel person = new PersonViewModel();
    protected override async Task OnInitializedAsync()
    {
    }
    protected async Task Save()
    {
        var response = await Http.PostAsJsonAsync("api/Person", @person);
        PersonViewModel personResponse = await response.Content.ReadFromJsonAsync<PersonViewModel>();
            if (personResponse?.Id > 0)
            {
                await JsRuntime.InvokeVoidAsync("alert", "Saved Successfully!");
                NavigationManager.NavigateTo("personlist");
            }
        }
        void Cancel()
        {
            NavigationManager.NavigateTo("personlist");
        }
    }

Let’s create another component EditPerson.razor.

Inside EditPerson.razor place the following code:

@page "/editperson/{Id}"
@using BlazorCRUDApp.Shared
@inject HttpClient Http
@inject NavigationManager NavigationManager
@inject IJSRuntime JsRuntime
<h2>Edit Person</h2>
<div class="row">
        <div class="col-md-6">
                <div class="form-group">
                        <label for="FirstName"> First Name *</label>
                        <input form="FirstName" class="form-control" @bind="@person.FirstName" />
                    </div>
            </div>
        <div class="col-md-6">
                <div class="form-group">
                        <label for="LastName"> Last Name *</label>
                        <input form="LastName" class="form-control" @bind="@person.LastName" />
                    </div>
            </div>
        <div class="col-md-6">
                <div class="form-group">
                        <label for="Email"> Email *</label>
                        <input form="Email" class="form-control" @bind="@person.Email" />
                    </div>
            </div>
        <div class="col-md-6">
                <div class="form-group">
                        <label for="MobileNo"> Mobile No *</label>
                        <input form="mobileNo" class="form-control" @bind="@person.MobileNo" />
                    </div>
            </div>
</div>
<div class="row">
        <div class="col-md-4">
                <div class="form-group">
                        <input type="button" class="btn btn-primary" @onclick="@Save" value="Save" />
                        <input type="button" class="btn" @onclick="@Cancel" value="Cancel" />
                    </div>
            </div>
</div>
@code {
    [Parameter]
    public string Id{ get; set; }
    PersonViewModel person = new PersonViewModel();
    protected override async Task OnInitializedAsync()
    {
        person = await Http.GetFromJsonAsync<PersonViewModel>("api/person/" + Id);
        }
        protected async Task Save()
        {
            var response = await Http.PutAsJsonAsync("api/Person/" + Id, @person);
            bool personResponse = await response.Content.ReadFromJsonAsync<bool>();
                if (personResponse)
                {
                    await JsRuntime.InvokeVoidAsync("alert", "Updated Successfully!");
                    NavigationManager.NavigateTo("personlist");
                }
            }
            void Cancel()
            {
                NavigationManager.NavigateTo("personlist");
            }
        }

Let’s create another component DeletePerson.razor.

Inside DeletePerson.razor place the following code:

@page "/deleteperson/{Id}"
@using BlazorCRUDApp.Shared
@inject HttpClient Http
@inject NavigationManager NavigationManager
@inject IJSRuntime JsRuntime
<h2>Delete Person</h2>
@if(person != null)
{
<p>Are you sure you want to delete this person with Name: <b>@person.FirstName @person.LastName</b></p>
<div class="row">
       <table class="table">
               <tr>
                       <td>Name</td>
                       <td>@person.FirstName @person.LastName</td>
                   </tr>
               <tr>
                       <td>Email</td>
                       <td>@person.Email</td>
                   </tr>
               <tr>
                       <td>Mobile Number</td>
                       <td>@person.MobileNo</td>
                   </tr>
           </table>
</div>   
}
<div class="row">
        <div class="col-md-4">
                <div class="form-group">
                        <input type="button" class="btn btn-primary" @onclick="@Delete" value="Delete" />
                        <input type="button" class="btn" @onclick="@Cancel" value="Cancel" />
                    </div>
            </div>
</div>
@code {
    [Parameter]
    public string Id{ get; set; }
    PersonViewModel person = new PersonViewModel();
    protected override async Task OnInitializedAsync()
    {
        person = await Http.GetFromJsonAsync<PersonViewModel>("api/person/" + Id);
        }
        protected async Task Delete()
        {
            var response = await Http.DeleteAsync("api/Person/" + Id);
            bool deleteResponse = await response.Content.ReadFromJsonAsync<bool>();
                if (deleteResponse)
                {
                    await JsRuntime.InvokeVoidAsync("alert", "Deleted Successfully!");
                    NavigationManager.NavigateTo("personlist");
                }
            }
            void Cancel()
            {
                NavigationManager.NavigateTo("personlist");
            }
        }

We have added four new components and changes on one component:

 

Step 5

On Server project add the following package reference for EF.

Then inside appsetting.json add the ConnectionString as:

"ConnectionStrings": {
    "DefaultConnection": "Data Source = DESKTOP-XXXXXX\SQLEXPRESS; Database = BlazorCRUDApp; Integrated Security = True; Connect Timeout = 30; Encrypt = False; TrustServerCertificate = False; ApplicationIntent = ReadWrite; MultiSubnetFailover = False"
  }

Add a new folder called AppDbContext, inside AppDbContext create a class called

ApplicationDbContext.cs and place a following code:

public class ApplicationDbContext:DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) :base(options){}
    public DbSet<Person> Persons { get; set; }
}

Add another folder Models, inside Models add a class called Person.cs and place the following code:

[Table("Person", Schema ="dbo")]
public class Person
{
    [Required]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    [Required]
    public string FirstName { get; set; }
    [Required]
    public string LastName { get; set; }
    [Required]
    public string Email { get;set; }
    [Required]
    public string MobileNo { get; set; }
}

Add another folder Repository, inside Repository add an Interface called IRepository.cs and implementation class called PersonRepository.cs. Inside an IRepository.cs place the following code:

public interface IRepository<T>{
    public Task<T> CreateAsync(T _object);
    public Task UpdateAsync(T _object);
    public Task<List<T>> GetAllAsync();
    public Task<T> GetByIdAsync(int Id);
    public Task DeleteAsync(int id);
}

Inside a PersonRepository.cs class place the following code:

public class PersonRepository: IRepository < Person > {
    ApplicationDbContext _dbContext;
    public PersonRepository(ApplicationDbContext applicationDbContext) {
        _dbContext = applicationDbContext;
    }
    public async Task < Person > CreateAsync(Person _object) {
        var obj = await _dbContext.Persons.AddAsync(_object);
        _dbContext.SaveChanges();
        return obj.Entity;
    }
    public async Task UpdateAsync(Person _object) {
        _dbContext.Persons.Update(_object);
        await _dbContext.SaveChangesAsync();
    }
    public async Task < List < Person >> GetAllAsync() {
        return await _dbContext.Persons.ToListAsync();
    }
    public async Task < Person > GetByIdAsync(int Id) {
        return await _dbContext.Persons.FirstOrDefaultAsync(x => x.Id == Id);
    }
    public async Task DeleteAsync(int id) {
        var data = _dbContext.Persons.FirstOrDefault(x => x.Id == id);
        _dbContext.Remove(data);
        await _dbContext.SaveChangesAsync();
    }
}

Add another folder Service, inside Service add an Interface called IPersonService.cs and implementation class called PersonService.cs. Inside an IPersonService.cs place the following code:

public interface IPersonService {
    Task < Person > AddPerson(Person person);
    Task < bool > UpdatePerson(int id, Person person);
    Task < bool > DeletePerson(int id);
    Task < List < Person >> GetAllPersons();
    Task < Person > GetPerson(int id);
}

Inside PersonService.cs place the following code:

public class PersonService: IPersonService {
    private readonly IRepository < Person > _person;
    public PersonService(IRepository < Person > person) {
        _person = person;
    }
    public async Task < Person > AddPerson(Person person) {
        return await _person.CreateAsync(person);
    }
    public async Task < bool > UpdatePerson(int id, Person person) {
        var data = await _person.GetByIdAsync(id);
        if (data != null) {
            data.FirstName = person.FirstName;
            data.LastName = person.LastName;
            data.Email = person.Email;
            data.MobileNo = person.MobileNo;
            await _person.UpdateAsync(data);
            return true;
        } else
            return false;
    }
    public async Task < bool > DeletePerson(int id) {
        await _person.DeleteAsync(id);
        return true;
    }
    public async Task < List < Person >> GetAllPersons() {
        return await _person.GetAllAsync();
    }
    public async Task < Person > GetPerson(int id) {
        return await _person.GetByIdAsync(id);
    }
}

Inside Controllers folder add API Controller called PersonController.cs, Inside PersonController.cs place the following code:

[Route("api/[controller]")]
[ApiController]
public class PersonController: ControllerBase
{
    private readonly IPersonService _personService;
    public PersonController(IPersonService personService)
        {
            _personService = personService;
        }
        [HttpGet]
    public async Task < List < Person >> GetAll()
        {
            return await _personService.GetAllPersons();
        }
        [HttpGet("{id}")]
    public async Task < Person > Get(int id)
        {
            return await _personService.GetPerson(id);
        }
        [HttpPost]
    public async Task < Person > AddPerson([FromBody] Person person)
        {
            return await _personService.AddPerson(person);
        }
        [HttpDelete("{id}")]
    public async Task < bool > DeletePerson(int id)
        {
            await _personService.DeletePerson(id);
            return true;
        }
        [HttpPut("{id}")]
    public async Task < bool > UpdatePerson(int id, [FromBody] Person Object)
    {
        await _personService.UpdatePerson(id, Object);
        return true;
    }
}

Go to Program.cs and add the following code:

// For entity Framework
builder.Services.AddDbContext < ApplicationDbContext > (options => {
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});
// For DI registration
builder.Services.AddTransient < IRepository < Person > , PersonRepository > ();
builder.Services.AddTransient < IPersonService, PersonService > ();

Our Server project folder structure will look like this.

After that, Go to package manager console for adding migration and update to database:

Add-migration mig1

Update-database

Then new database BlazorCRUDApp will be created with Person table.

Now run the Application and enjoy your Blazor WebAssembly CRUD Application.