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.
![]()
![]()
![]()