ASP.NET Core – CRUD Using Blazor And Entity Framework Core
Introduction
Microsoft has recently announced the release of a new .NET web framework – Blazor. In this article, we are going to create a web application using Blazor with the help of Entity Framework Core. We will be creating a sample Employee Record Management System and perform CRUD using Blazor on it.
The source code has been updated to .NET Core 3.2 Preview-1. Get the source code from Github
Creating Table
We will use a DB table to store all the records of employees.
Open SQL Server and use the following script to create tblEmployee table
Create table tblEmployee(
EmployeeId int IDENTITY(1,1) NOT NULL,
Name varchar(20) NOT NULL,
City varchar(20) NOT NULL,
Department varchar(20) NOT NULL,
Gender varchar(6) NOT NULL
)
Now, let’s move on to create our web application.
Create Blazor Web Application
Open Visual Studio and select File >> New >> Project.
After selecting the project, a “New Project” dialog will open. Select .NET Core inside Visual C# menu from the left panel. Select “ASP.NET Core Web Application” from available project types. Put the name of the project as BlazorCrud and press OK.
After clicking on OK, a new dialog will open asking you to select the project template. You can observe two drop-down menus at the top left of the template window. Select “.NET Core” and “ASP.NET Core 2.0” from these dropdowns. Then, select “Blazor (ASP .NET Core hosted)” template and press OK.
Now, our Blazor solution will be created. You can observe the folder structure in Solution Explorer as shown in the below image.
You can observe that we have 3 project files created inside this solution.
BlazorCrud.Client – It has the client side code and contains the pages that will be rendered on the browser.
BlazorCrud.Server – It has the server side codes such as DB related operations and web API.
BlazorCrud.Shared – It contains the shared code that can be accessed by both client and server.
Run the application by pressing F5. A browser window will open and you can see a page similar to the one shown below.
Here you can see a navigation menu on the left side, which contains the navigation to the pages in our application. By default, we have “Counter” and “Fetch Data” pages provided in our application. These default pages will not affect our application but for the sake of this tutorial, we will delete fetchdata and counter pages from BlazorCrud.Client/Pages folder.
Adding the Model to the Application
Right click on BlazorCrud.Shared project and select Add >> New Folder. Name the folder as Models. We will add our model class in this folder only.
Right click on Models folder and select Add >> Class. Name your class Employee.cs. This class will contain our Employee model properties. Now our BlazorCrud.Shared project has the following structure.
Open Employee.cs and put the following code in it.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace BlazorCrud.Shared.Models
{
public class Employee
{
public int EmployeeId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Gender { get; set; }
[Required]
public string Department { get; set; }
[Required]
public string City { get; set; }
}
}
And hence our model has been created. Now we will create our data access layer.
Creating Data Access Layer for the Application
Right click on BlazorCrud.Server project and select Add >> New Folder. Name the folder as DataAccess. We will add our classes to handle database related operations inside this folder.
Right click on DataAccess folder and select Add >> Class. Name your class EmployeeContext.cs. This is our Entity Framework DBcontext class to interact with database. Open EmployeeContext.cs and put the following code into it.
using BlazorCrud.Shared.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BlazorCrud.Server.DataAccess
{
public class EmployeeContext : DbContext
{
public virtual DbSet<Employee> tblEmployee { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(@"Put Your Connection string here");
}
}
}
}
Do not forget to put your own connection string.
Add one more class to DataAccess folder and name it as EmployeeDataAccessLayer.cs. This class will handle our CRUD related DB operations. Open EmployeeDataAccessLayer.cs and put the following code into it.
using BlazorCrud.Shared.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BlazorCrud.Server.DataAccess
{
public class EmployeeDataAccessLayer
{
EmployeeContext db = new EmployeeContext();
//To Get all employees details
public IEnumerable<Employee> GetAllEmployees()
{
try
{
return db.tblEmployee.ToList();
}
catch
{
throw;
}
}
//To Add new employee record
public void AddEmployee(Employee employee)
{
try
{
db.tblEmployee.Add(employee);
db.SaveChanges();
}
catch
{
throw;
}
}
//To Update the records of a particluar employee
public void UpdateEmployee(Employee employee)
{
try
{
db.Entry(employee).State = EntityState.Modified;
db.SaveChanges();
}
catch
{
throw;
}
}
//Get the details of a particular employee
public Employee GetEmployeeData(int id)
{
try
{
Employee employee = db.tblEmployee.Find(id);
return employee;
}
catch
{
throw;
}
}
//To Delete the record of a particular employee
public void DeleteEmployee(int id)
{
try
{
Employee emp = db.tblEmployee.Find(id);
db.tblEmployee.Remove(emp);
db.SaveChanges();
}
catch
{
throw;
}
}
}
}
And hence our data access layer is complete. Now, we will proceed to create our web API Controller.
Adding the web API Controller to the Application
Right click on BlazorCrud.Server/Controllers folder and select Add >> New Item. An “Add New Item” dialog box will open. Select ASP.NET from the left panel, then select “API Controller Class” from templates panel and put the name as EmployeeController.cs. Press OK.
This will create our API EmployeeController class. We will call the methods of EmployeeDataAccessLayer class to fetch data and pass on the data to the client side.
Open EmployeeController.cs file and put the following code into it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BlazorCrud.Server.DataAccess;
using BlazorCrud.Shared.Models;
using Microsoft.AspNetCore.Mvc;
namespace BlazorCrud.Server.Controllers
{
public class EmployeeController : Controller
{
EmployeeDataAccessLayer objemployee = new EmployeeDataAccessLayer();
[HttpGet]
[Route("api/Employee/Index")]
public IEnumerable<Employee> Index()
{
return objemployee.GetAllEmployees();
}
[HttpPost]
[Route("api/Employee/Create")]
public void Create([FromBody] Employee employee)
{
if (ModelState.IsValid)
objemployee.AddEmployee(employee);
}
[HttpGet]
[Route("api/Employee/Details/{id}")]
public Employee Details(int id)
{
return objemployee.GetEmployeeData(id);
}
[HttpPut]
[Route("api/Employee/Edit")]
public void Edit([FromBody]Employee employee)
{
if (ModelState.IsValid)
objemployee.UpdateEmployee(employee);
}
[HttpDelete]
[Route("api/Employee/Delete/{id}")]
public void Delete(int id)
{
objemployee.DeleteEmployee(id);
}
}
}
At this point of time our BlazorCrud.Server project has the following structure.
We are done with our backend logic. So, we will now proceed to code our client side.
Adding Razor View to the Application
Right click on BlazorCrud.Client/Pages folder and select Add >> New Item. An “Add New Item” dialog box will open, select Web from the left panel. Select “Razor View” from templates panel and name it FetchEmployee.cshtml.
This will add a FetchEmployee.cshtml page to the BlazorCrud.Client/Pages folder. Similarly add 3 more pages AddEmployee.cshtml, EditEmployee.cshtml and DeleteEmployee.cshtml.
Now our BlazorCrud.Client project has the following structure.
Let’s add codes to these pages
FetchEmployee.cshtml
This page will be displaying all the employee records present in the database. Additionally, we will also provide action methods Edit and Delete on each record.
Open FetchEmployee.cshtml and put the following code in it.
Let’s understand this code. On the top, we have included BlazorEFApp.Shared.Models namespace so that we can use our Employee model class in this page.
We are defining the route of this page using @page directive. So, in this application, if we append “/fetchemployee” to base URL then we will be redirected to this page. We are also injecting HttpClient service to enable web API call.
Then we have defined the HTML part to display all the employees record in a tabular manner. We have also added two action links for Edit and Delete which will navigate to EditEmployee.cshtml and DeleteEmployee.cshtml pages respectively.
At the bottom of the page, we have a @functions section which contains our business logic. We have created an array variable empList of type Employee and populating it inside OnInitAsync method by calling our web API. This will bind to our HTML table on the page load.
AddEmployee.cshtml
This page is used to create a new employee record.
Open AddEmployee.cshtml and put the following code into it.
We are injecting the Microsoft.AspNetCore.Blazor.Services.IUriHelper service to enable URL redirection. The HTML part will generate a form to get inputs from the user. The attribute “bind” is used to bind the value entered in the textbox to the properties of Employee object.
In the @functions section we have defined two methods. The method CreateEmployee will be invoked on clicking “Submit” button and send a POST request to our API along with the Employee object emp.
The Cancel method will be invoked on clicking cancel button and redirect the user back to FetchEmployee page
EditEmployee.cshtml
This page is used to edit the details of an employee.
Open EditEmployee.cshtml and put the following code into it.
In this page we have defined the route as “/editemployee/{empID}”. empID is an URL parameter of type string declared in @functions section. We will use the [Parameter] attribute to mark the variable as a parameter. To navigate to this page, we need to pass the employee id in the URL which will be captured in empID variable.
If we do not mark the variable with the [Parameter] attribute, we will get an error “Object of type ‘BlazorCrud.Client.Pages.EditEmployee’ has a property matching the name ’empID’, but it does not have [ParameterAttribute] applied.” . This will not allow empID to bind to the employee id value passed in the parameter.
The HTML part is similar to that of AddEmployee.cshtml page. The attribute “bind” is used for two-way binding; i.e., binding the textbox values to employee object properties and vice versa.
Inside the @functions section we are fetching the employee records in OnInitAsync method based on the employeeID passed in the parameter. This will bind to the fields in the form on page load itself.
UpdateEmployee method will send a PUT request to our API along with the Employee object emp. The Cancel method will be invoked on clicking cancel button and redirect the user back to FetchEmployee page.
DeleteEmployee.cshtml
This page will be used to delete an employee record.
Open DeleteEmployee.cshtml and put the following code into it:
@using BlazorCrud.Shared.Models
@page "/delete/{empID}"
@inject HttpClient Http
@inject Microsoft.AspNetCore.Blazor.Services.IUriHelper UriHelper<h2>Delete</h2>
<h3>Are you sure you want to delete employee with id : @empID</h3>
<br /><div class="col-md-4">
<table class="table">
<tr>
<td>Name</td>
<td>@emp.Name</td>
</tr>
<tr>
<td>Gender</td>
<td>@emp.Gender</td>
</tr>
<tr>
<td>Department</td>
<td>@emp.Department</td>
</tr>
<tr>
<td>City</td>
<td>@emp.City</td>
</tr>
</table>
<div class="form-group">
<input type="submit" value="Delete" >
The route for this page is also parameterized since we are fetching the record of the employee on page load.
The HTML part will display the employee data and ask the user for a confirmation to delete the employee record.
Inside the @functions section we are fetching the employee records in OnInitAsync method based on the employeeID passed in the parameter. This will display the employee records as the page loads.
The Delete method will be invoked on clicking “Delete” button, which will send a delete request to our API along with the employee ID of the employee to be deleted. On successful deletion the user will be navigated back to FetchEmployee page.
Adding Link to Navigation menu
The last step is to define navigation menu for our application. Open BlazorCrud.Client/Shared/ NavMenu.cshtml file and put the following code in it.
And that’s it. We have created our first ASP.NET Core application using Blazor and Entity Framework Core.
Execution Demo
Launch the application.
A web page will open as shown in the image below. The navigation menu on the left showing navigation link for Home and Fetch Employee pages.
Click on Fetch employee in the navigation menu. It will redirect to FetchEmployee view and display all the employee data on the page. Notice the URL has “/fetchemployee” appended to it as we have defined it using @page directive.
Since we have not added any data, hence it is empty.
Click on CreateNew to navigate to AddEmployee view. Notice the URL has “/addemployee” appended to it as we have defined it using @page directive. Add a new Employee record as shown in the image below:
After inserting data in all the fields, click on “Save” button. The new employee record will be created and you will be redirected to the FetchEmployee view, displaying records of all the employees. Here, we can also see action methods Edit and Delete corresponding to each record.
If we want to edit an existing employee record, then click on Edit action link. It will open Edit view as shown below. Here we can change the employee data. Notice that we have passed employee id in the URL parameter.
Here we have changed the City of employee Swati from New Delhi to Chennai. Click on “Save” to return to the FetchEmployee view to see the updated changes as highlighted in the image below:
Now, we will perform Delete operation on the employee named Rahul. Click on Delete action link which will open Delete view asking for a confirmation to delete. Notice that we have passed employee id in the URL parameter.
Once we click on Delete button, it will delete the employee record and we will be redirected to the FetchEmployee view. Here, we can see that the employee with name Rahul has been removed from our record.
We have created an ASP.NET Core application using the new web framework – Blazor and Entity Framework Core with the help of Visual Studio 2017 and SQL Server 2012. We have also performed the CRUD operations on our application.
Employee.cs:
On 'using System.ComponentModel.DataAnnotations;' I got an error.
Solution Explorer > BlazorCrud.Shared > Add > Reference... > Browse to the dll; OK
AddEmployee.cshtml and EditEmployee.cshtml:
I had to remove the form tags to avoid default behaviour, preventing me from going back to FetchEmployee.cshtml
The Blazor framework is still in development stage. It is not stable and undergoing frequent changes which results in some issues.
Thanks for your great work, a very good way to learn Blazor
very good post ankit. I think my question is not related to this topic.but i want to know that how to Refresh ListBox with a only newly added record or modified record.Because i have a listbox on the page page with large number of records. so every time when i click on Add Button, It is not required to refresh all record to listbox, but only the record which is newly added from other user. I am new for web development.
I read your article on CRUD with blazor. realy very easy to understand. thanks a lot.
Thanks for quick reply. I have a Product listbox with more than 50000 records.
Is it possible that ListBox refresh with only newly inserted record ?
Because when i call page. OnInitAsync() Method refreshes all data of listbox
The OnInitAsync() method will be called on page reload only. I don't think that it is possible to refresh the drop down with only new data. if you add new records in database, it will load the whole DDL when the page is loaded.
Thanks ankit.
Very nice article
Hope your book is at the same level as this article.
My book on Blazor contains all the core concepts which will make you a Blazor expert. Get it from Amzon at https://amzn.to/2OToEji
Dear Sir, this is very good sharing to learn Blazor. kindly provide step by step CRUD Operation with latest Blazor extension Using .NET Core 3.0 and Visual Studio 2019.
Thanks for reading my blog. There is not much difference in coding when it comes to using Blazor with .NET Core 3.0. You can use the same set of code with .NET Core 3.0 and VS 19 also. Refer to (https://docs.microsoft.com/en-us/aspnet/core/blazor/get-started?view=aspnetcore-3.0) to set up the Blazor development environment with .NET core 3 and vs 19. Try to use the code explained in this article and let me know in case if you have any further issues.
Dear Sir, sorry for late reply - will try on Blazor with .NET Core 3.0. and VS 19 & inform u....
The Edit function does not work properly with the Cancel operation. The data in the view is changed, and it shouldn't.
This is an issue with the EF Core. Please update the GetAllEmployees() method in the EmployeeDataAccessLayer class by adding the following line:
View Comments
Employee.cs:
On 'using System.ComponentModel.DataAnnotations;' I got an error.
Solution Explorer > BlazorCrud.Shared > Add > Reference... > Browse to the dll; OK
AddEmployee.cshtml and EditEmployee.cshtml:
I had to remove the form tags to avoid default behaviour, preventing me from going back to FetchEmployee.cshtml
The Blazor framework is still in development stage. It is not stable and undergoing frequent changes which results in some issues.
Thanks for your great work, a very good way to learn Blazor
very good post ankit. I think my question is not related to this topic.but i want to know that how to Refresh ListBox with a only newly added record or modified record.Because i have a listbox on the page page with large number of records. so every time when i click on Add Button, It is not required to refresh all record to listbox, but only the record which is newly added from other user. I am new for web development.
I read your article on CRUD with blazor. realy very easy to understand. thanks a lot.
You donot need to load drop down list on click of Add button. Load the drop down inside OnInitAsync() method to load the list only on page load. Please refer to my article (https://ankitsharmablogs.com/cascading-dropdownlist-in-blazor-using-ef-core/)
Thanks for quick reply. I have a Product listbox with more than 50000 records.
Is it possible that ListBox refresh with only newly inserted record ?
Because when i call page. OnInitAsync() Method refreshes all data of listbox
The OnInitAsync() method will be called on page reload only. I don't think that it is possible to refresh the drop down with only new data. if you add new records in database, it will load the whole DDL when the page is loaded.
Thanks ankit.
Very nice article
Hope your book is at the same level as this article.
My book on Blazor contains all the core concepts which will make you a Blazor expert. Get it from Amzon at https://amzn.to/2OToEji
Dear Sir, this is very good sharing to learn Blazor. kindly provide step by step CRUD Operation with latest Blazor extension Using .NET Core 3.0 and Visual Studio 2019.
Thanks for reading my blog. There is not much difference in coding when it comes to using Blazor with .NET Core 3.0. You can use the same set of code with .NET Core 3.0 and VS 19 also. Refer to (https://docs.microsoft.com/en-us/aspnet/core/blazor/get-started?view=aspnetcore-3.0) to set up the Blazor development environment with .NET core 3 and vs 19. Try to use the code explained in this article and let me know in case if you have any further issues.
Dear Sir, sorry for late reply - will try on Blazor with .NET Core 3.0. and VS 19 & inform u....
The Edit function does not work properly with the Cancel operation. The data in the view is changed, and it shouldn't.
This is an issue with the EF Core. Please update the GetAllEmployees() method in the EmployeeDataAccessLayer class by adding the following line:
return db.tblEmployee.AsNoTracking().ToList();