Introduction
In my previous article, I have clearly explained about Blazor, Data Binding, and prerequisites that are required to get started with Blazor. In this article, we are going to use the MudBlazor material component to create rich UI pages. To develop the crud application we are going to use Cards, Tables, Icons Buttons, Pagination, Searching, and other components to accomplish our task.
If you want to learn more about Blazor, I strongly suggest visiting our Blazor Articles where you can read about Blazor Server Side, Blazor webAssembly development, and other topics as well.
Contents
- Introducing MudBlazor.
- Prerequisites
- Setting up the project - .Net 5
- Installing and Configuring MudBlazor
- Setting up the connection with SQL Db by using EfCore
- Blazor CRUD operations using service layer & Repository Pattern
- Building the UI with MudBlazor components
- Conclusion
Introducing MudBlazor
MudBlazor is "a Material Design Component framework" for Blazor to ease up the web development framework without struggling with CSS and javascript. If you're looking for Date pickers, progress bars, Ratings, etc.
MudBlazor has your back and nearly all of the components use just C# (no Javascript, except where it's strictly necessary). The vision of MudBlazor is to keep it clean, simple, and with a highly customizable modern design. No Javascript, just Blazor, and CSS. The team has documented the library in a very understandable way. You can check the documentation here.
Prerequisites
- SDK - .Net 5.0
- IDE - Visual Studio 2019
Setting up the project - .Net 5.0
Open the Visual Studio and search for Blazor App. Click on the Next button,
Define the project name, path, and solution name. Click on the Create button,
After that a new window will pop up to choose the target framework (.Net 5.0) from the dropdown and make sure to select the Blazor server App and in the Advanced section "Configure the Https" is checked.
Installing and Configuring the MudBlazor
Open up the package manager console and try running the following command to install the MudBlazor in our project.
Install-Package MudBlazor
After the package is installed, open up the startup.cs file and try adding the services inside the ConfigureServices() method, so this adds all the common services that are required by the MudBlazor component.
services.AddMudServices();
Now we need to add the references of CSS and js files of MudBlazor inside the Pages /_Host razor page,
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
Here we need to import the MudBlazor package inside the _Imports.razor file,
@using MudBlazor
Once after that, we need to add the providers which we are consuming from the MudBlazor package. Open up the Shared/MainLayout.razor and add the below code at the end of the file,
<MudThemeProvider />
<MudSnackbarProvider />
Setting up the connection with SQL Db by using EfCore
In order to make a connection to SQL Database with Efcore here, we require the following packages to establish the connection by using the Code first approach. We can install the required packages by using the Nuget Package Manager or by using the Package manager console.
NuGet Packages
Commands - PM Console
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore.Tools
Let's get started by defining the Classes Inside the Models folder. Here we are creating the new folder named Models and inside that will create a Student class with the minimum properties to make the implementation easy.
Student.cs
using System.ComponentModel.DataAnnotations;
namespace MudBlazor_CRUD.Models
{
public class Student
{
[Key]
public int StudentID { get; set; }
public string StudentName { get; set; }
public string StudentAge { get; set; }
public string Address { get; set; }
public string ContactNo { get; set; }
}
}
Key - attribute acts as a primary key for our Id property.
Next, let's add the DbContext class to our application. This helps us to access the Database tables which will be generated by our Models via the application. Create a separate folder named as ApplicationDbContext and inside that will create an AppDbContext class to define our DbContext.
AppDbContext.cs
using Microsoft.EntityFrameworkCore;
using MudBlazor_CRUD.Models;
namespace MudBlazor_CRUD.ApplicationDbContext
{
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Student> Students { get; set; }
}
}
Let's add the connection string of our SQL Database in the appsettings.json file,
"ConnectionStrings": {
"myconn": "server= Local Database Server Name; database=MudBlazorCRUD;Trusted_Connection=True;"
}
Now let's add the DbContext to our application service container to access all the tables from the respective database by using the following code,
#region Connection String
services.AddDbContext<AppDbContext>(item => item.UseSqlServer(Configuration.GetConnectionString("myconn")));
#endregion
Finally, let's add the migrations and update our Database. Run the below commands one after another in the package manager console,
add-migration 'initial'
update-database
Here is our Database and the Student table got created in our local database.
Blazor Crud operations using service layer and Repository pattern
ASP.Net Core is designed to support dependency injection. Now we create a generic repository interface for the entity operations so that we can see the loosely coupled application. Create a folder named UnitofWork and inside that will maintain our Repository layer and its interface.
Below is the code snippet,
Repository.cs
using Microsoft.EntityFrameworkCore;
using MudBlazor_CRUD.ApplicationDbContext;
using MudBlazor_CRUD.Models;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MudBlazor_CRUD.UnitofWork
{
public class Repository<T> : IRepository<T> where T : Student
{
#region property
private readonly AppDbContext _applicationDbContext;
private DbSet<T> entities;
#endregion
#region Constructor
public Repository(AppDbContext applicationDbContext)
{
_applicationDbContext = applicationDbContext;
entities = _applicationDbContext.Set<T>();
}
#endregion
public void Delete(T entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
entities.Remove(entity);
_applicationDbContext.SaveChanges();
}
public List<T> GetAll()
{
return entities.ToList();
}
public void Insert(T entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
entities.Add(entity);
_applicationDbContext.SaveChanges();
}
public void Remove(T entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
entities.Remove(entity);
}
public void SaveChanges()
{
_applicationDbContext.SaveChanges();
}
public void Update(T entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
entities.Update(entity);
_applicationDbContext.SaveChanges();
}
}
}
Create the repository class to perform the database operations which inherit the IRepository interface.
IRepository.cs
using MudBlazor_CRUD.Models;
using System.Collections.Generic;
namespace MudBlazor_CRUD.UnitofWork
{
public interface IRepository<T> where T : Student
{
List<T> GetAll();
void Insert(T entity);
void Update(T entity);
void Delete(T entity);
void Remove(T entity);
void SaveChanges();
}
}
Let's define the services that contain the Core Business Logic as part of our project which connects with the Repositorylayer and performs all the Database operations. Here I created the Services folder to have our Core Services defined.
StudentServices.cs
using MudBlazor_CRUD.ApplicationDbContext;
using MudBlazor_CRUD.Models;
using MudBlazor_CRUD.UnitofWork;
using System.Collections.Generic;
using System.Linq;
namespace MudBlazor_CRUD.Services
{
public class StudentService : IStudentService
{
#region Property
private IRepository<Student> _repository;
private AppDbContext _appDbContext;
#endregion
#region Constructor
public StudentService(IRepository<Student> repository, AppDbContext appDbContext)
{
_repository = repository;
_appDbContext = appDbContext;
}
#endregion
public List<Student> GetStudents() => _repository.GetAll();
public void InsertStudent(Student customer)
{
if (customer.StudentID is 0) _repository.Insert(customer);
else _repository.Update(customer);
}
public void DeleteStudent(int id)
{
Student student = _appDbContext.Students.FirstOrDefault(c => c.StudentID.Equals(id));
_repository.Remove(student);
_repository.SaveChanges();
}
}
}
IStudentService.cs
using MudBlazor_CRUD.Models;
using System.Collections.Generic;
namespace MudBlazor_CRUD.Services
{
public interface IStudentService
{
List<Student> GetStudents();
void InsertStudent(Student customer);
void DeleteStudent(int id);
}
}
Here is a clear description of all our services,
- GetStudents - To Fetch all the Student records from the Database.
- InsertStudent - To insert a student record in the table and in the same way to update the same student record if there is any modification that comes with UI.
- DeleteStudent - Hard Deletion of record from the table.
Now to finish off with the service layer. we have to register this interface and class in the Startup.cs file. Inside the ConfigureServices() method add the following code,
services.AddScoped<IStudentService, StudentService>();
Also, we need to register the Repository Layer in the same ConfigureServices() function inside the Startup class,
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
Building the UI with MudBlazor components
To have the UI in place we have to create a Razor page in the Pages/StudentInfo.razor where will have the operations and below is the code snippet to invoke the Crud operations from the Service layer.
StudentInfo.razor
@code{
private string searchString = "";
private Student student = new(); //C# 9 Syntax
private List<Student> students = new();
protected override async Task OnInitializedAsync()
{
GetAllStudents();
}
private List<Student> GetAllStudents()
{
students = _studentService.GetStudents();
return students;
}
private bool Search(Student student)
{
if (student.StudentName is not null && student.StudentAge is not null && student.Address is not null && student.ContactNo is not null &&
student.StudentName.Contains(searchString, StringComparison.OrdinalIgnoreCase)
|| student.StudentAge.Contains(searchString, StringComparison.OrdinalIgnoreCase)
|| student.Address.Contains(searchString, StringComparison.OrdinalIgnoreCase)
|| student.ContactNo.Contains(searchString, StringComparison.OrdinalIgnoreCase))
{
return true;
}
return false;
}
private void Save()
{
_studentService.InsertCustomer(student);
snackBar.Add("Student record saved", Severity.Success);
GetAllStudents();
}
private void Edit(int id)
{
student = students.FirstOrDefault(c => c.StudentID == id);
}
private void Delete(int id)
{
_studentService.DeleteCustomer(id);
snackBar.Add("Customer Data Deleted.", Severity.Success);
GetAllStudents();
}
}
Here is a brief description of the above code snippet,
- OnInitializedAsync() - As soon as the page is loaded the OnInitializedAsync method gets invoked by default. Inside that method we were calling the GetAllStudents() method to fetch the results from Database and populate them in the Mud Table in a sequential way.
- GetAllStudents() - Fetching of Data from Database through Service Layer.
- Search() - In the loaded table if we want to filter the data with any of the fields this search function will help.
- Save() - When the user enters the data in the form and clicks on the SaveStudent button this method will get fired and save or update those values in the Database
- Edit() - This fills the text boxes values based upon the data fetching from the list by using the Id.
- Delete() - This function helps in deleting the records from the Database through the service layer.
MudBlazor Form
We have been using the MudCards to design the page with the Textboxes and Save button and Mutable to display the records fetching from the Db.
Below is the code snippet,
@page "/student"
@using MudBlazor_CRUD.Models
@inject MudBlazor_CRUD.Services.IStudentService _studentService
@inject MudBlazor.ISnackbar snackBar
<MudCard Elevation="25">
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.h6">Add / Edit Students</MudText>
</CardHeaderContent>
</MudCardHeader>
<MudCardContent>
<MudTextField @bind-Value="student.StudentName" Label="Student Name" Variant="Variant.Text" Margin="Margin.Normal"></MudTextField>
<MudTextField @bind-Value="student.StudentAge" Label="Age" Variant="Variant.Text" Margin="Margin.Normal"></MudTextField>
<MudTextField @bind-Value="student.Address" Label="Address" Variant="Variant.Text" Margin="Margin.Normal"></MudTextField>
<MudTextField @bind-Value="student.ContactNo" Label="Contact Number" Variant="Variant.Text" Margin="Margin.Normal"></MudTextField>
<br />
<MudButton Variant="Variant.Filled" Color="Color.Success" OnClick="Save">Save Student</MudButton>
</MudCardContent>
</MudCard>
<br />
<MudTable Elevation="25" Items="GetAllStudents()" Filter="new Func<Student, bool>(Search)" @bind-customer="student">
<ToolBarContent>
<MudText Typo="Typo.h6">Students</MudText>
<MudToolBarSpacer />
<MudTextField @bind-Value="searchString" Placeholder="Search for Students..." Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"></MudTextField>
</ToolBarContent>
<HeaderContent>
<MudTh>Id</MudTh>
<MudTh>Student Name</MudTh>
<MudTh>Age</MudTh>
<MudTh>Address</MudTh>
<MudTh>ContactNo</MudTh>
<MudTh>Actions</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Id">@context.StudentID</MudTd>
<MudTd DataLabel="Student Name">@context.StudentName</MudTd>
<MudTd DataLabel="Age">@context.StudentAge</MudTd>
<MudTd DataLabel="Address">@context.Address</MudTd>
<MudTd DataLabel="ContactNo">@context.ContactNo</MudTd>
<MudTd DataLabel="">
<MudFab @onclick="@(()=>Edit(@context.StudentID))" Color="Color.Primary" Icon="@Icons.Material.Filled.Edit" Size="Size.Small" IconSize="Size.Small" />
<MudFab @onclick="@(()=>Delete(@context.StudentID))" Color="Color.Secondary" Icon="@Icons.Material.Filled.Delete" Size="Size.Small" IconSize="Size.Small" />
</MudTd>
</RowTemplate>
<PagerContent>
<MudTablePager PageSizeOptions="new int[] { 5,10,20,50}" />
</PagerContent>
</MudTable>
Line 1 - Routing the page with the student.
Line 3,4,5 - Importing the files and services and using the Snackbar feature providing by MudBlazor to act like Notification toasters.
Line 8 - 22: Card with headers, required text fields, and button to save the values.
Line 24- 52: We get to bind each of the available customer properties to corresponding columns and also mentioned above by giving an option to filter the data based on search functionality and also we have buttons known as edit and delete to perform the update or deletion.
Adding the page routing in the Shared/NavMenu razor page.
NavMenu.razor
<li class="nav-item px-3">
<NavLink class="nav-link" href="student">
<span class="oi oi-dashboard" aria-hidden="true"></span> Student Info
</NavLink>
</li>
That’s how to build Blazor CRUD using Mudblazor and Entity Framework Core with ease.
Final Output
After running the app and routing to the Student Info page below we can see our application would be getting a list of students, adding new student details, edit and delete existing students, and also pagination with a cool material UI provided by MudBlazor.
Conclusion
I hope this article helps you in the understanding of implementing the CRUD operations using MudBlazar using Blazor server-side and .Net 5. You can find the source code here.
Thank you for reading, please let me know your questions, thoughts, or feedback in the comments section. I appreciate your feedback and encouragement.
Keep learning....!