Introduction
In this article we will create a fully functional Blazor site with Add/Edit/Delete and display features. This is the first part of the article and it will be focussed around creating .NET Core APIs and repository layers using Entity Framework Core.
We will be saving our application data in SQL Server.
Prerequisites
This article assumes you have a basic working knowledge of Blazor web assembly and .NET Core.
Read my previous article on creating custom Blazor components and reusing them on Razor pages.
Through this article, we will cover the following topics.
- Creating Blazor Web assembly app, .NET Core hosted
- Connecting to SQL Server and data retrieval using Entity Framework Core
- Creating REST APIs and repository layers to save and read data
Output
Employee Home Page
Employee Detail Page
Implementation
This project requires VS 2019 installed on your machine.
Step 1. Creating a new Blazor web assembly project .NET Core hosted
Open Vs 2019 create a new Project and select Blazor Project Template.
Check the ASP.NET Core hosted check box.
Solution Structure
VS will create a new project with a solution structure as shown below.
Employee.Client project
This is a Blazor Web Assembly Project and all the client-side code will reside in this project.
This will include the below items.
- Blazor components
- Razor pages
- Client-side CSS libraries and Master Layout
- Services (Services are used to call .NET Core API)
The first part of the article is focused on building .NET CORE API which would be consumed by Blazor pages to bind and display data.
The details of Blazor data binding will be discussed in part two.
EmployeePortal.Server
This is the ASP.NET Core project. All our APIs and repositories will reside in this project.
It will also contain all the necessary configurations to connect to the SQL server.
EmployeePortal.Shared
This Project will include data models and it will be shared by our client and server projects.
Step 2. Connecting to SQL Server and data retrieval using Entity Framework Core.
Install EntityframeworkCore budget packages as shown below.
Create a new Employee class in a shared project
This is our Data Model.
[Table("Employee")]
public partial class Employee
{
public int EmployeeId
{
get;
set;
}
[Required]
[StringLength(50, ErrorMessage = "First name is too long.")]
public string FirstName
{
get;
set;
}
[Required]
[StringLength(50, ErrorMessage = "Last name is too long.")]
public string LastName
{
get;
set;
}
[Required]
[EmailAddress]
public string Email
{
get;
set;
}
public string Street
{
get;
set;
}
public string Zip
{
get;
set;
}
public string City
{
get;
set;
}
public string PhoneNumber
{
get;
set;
}
[StringLength(1000, ErrorMessage = "Comment length can't exceed 1000 characters.")]
public string Comment
{
get;
set;
}
}
Create a new Database in SQL Server Hrms
Create a new Employee as per the below schema.
Database Table script
CREATE TABLE [dbo].[Employee] (
[EmployeeId] INT IDENTITY(1,1) NOT NULL,
[FirstName] VARCHAR(256) NULL,
[LastName] VARCHAR(256) NULL,
[Email] VARCHAR(256) NULL,
[Street] VARCHAR(256) NULL,
[Zip] VARCHAR(256) NULL,
[City] VARCHAR(256) NULL,
[PhoneNumber] VARCHAR(256) NULL,
[Comment] VARCHAR(256) NULL
) ON [PRIMARY];
GO
Configuring SQL connection string
Under app settings in EmployeePortal.Server project configures to connect to SQL Server.
{
"ConnectionStrings": {
"DefaultConnection": "Server=\"\";Database=\"Hrms\";User Id=\"username\";Password=\"password\";MultipleActiveResultSets=true;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Create a new Database folder in Server Project and Add the Below files.
Employee Repository
The will contain all the method implementation to add/edit/get and delete employee data.
Register SQL connection and Employee Repository in Startup.cs file.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddControllersWithViews();
services.AddRazorPages();
services.AddScoped<IEmployeeRepository, EmployeeRepository>();
}
public class EmployeeRepository : IEmployeeRepository
{
private readonly AppDbContext _appDbContext;
public EmployeeRepository(AppDbContext appDbContext)
{
_appDbContext = appDbContext;
}
public IEnumerable<Employee> GetAllEmployees()
{
return _appDbContext.Employees.ToList();
}
public Employee AddEmployee(Employee employee)
{
var addedEntity = _appDbContext.Employees.Add(employee);
_appDbContext.SaveChanges();
return addedEntity.Entity;
}
public Employee GetEmployeeById(int employeeId)
{
return _appDbContext.Employees.FirstOrDefault(c => c.EmployeeId == employeeId);
}
public Employee UpdateEmployee(Employee employee)
{
var foundEmployee = _appDbContext.Employees.FirstOrDefault(e => e.EmployeeId == employee.EmployeeId);
if (foundEmployee != null)
{
foundEmployee.City = employee.City;
foundEmployee.Email = employee.Email;
foundEmployee.FirstName = employee.FirstName;
foundEmployee.LastName = employee.LastName;
foundEmployee.PhoneNumber = employee.PhoneNumber;
foundEmployee.Street = employee.Street;
foundEmployee.Zip = employee.Zip;
foundEmployee.Comment = employee.Comment;
_appDbContext.SaveChanges();
return foundEmployee;
}
return null;
}
public void DeleteEmployee(int employeeId)
{
var foundEmployee = _appDbContext.Employees.FirstOrDefault(e => e.EmployeeId == employeeId);
if (foundEmployee == null) return;
_appDbContext.Employees.Remove(foundEmployee);
_appDbContext.SaveChanges();
}
}
Employee Interface
The Interface contains method definitions of add/edit/get and delete employee data.
public interface IEmployeeRepository
{
IEnumerable<Employee> GetAllEmployees();
Employee AddEmployee(Employee employee);
Employee GetEmployeeById(int employeeId);
Employee UpdateEmployee(Employee employee);
void DeleteEmployee(int employeeId);
}
Appdbcontext
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Employee> Employees { get; set; }
}
Our Database Repository layer is ready to be consumed by .NET Core API. Let's go ahead and build the API.
Step 3. Creating, NET Core API
Add new Employee Controller in EmployeePortal.ServerProject.
The controller has the below-mentioned API methods.
- GetAllEmployees(): Get a method to get all employees from DB.
- CreateEmployee(): The post method takes the employee object and validates the model before saving the final data in the database.
- GetEmployeeById: Get method to get specific Employee. This method required EmployeeID as a parameter.
- UpdateEmployee: Put method used to update specific Employee. This method required EmployeeID as a parameter.
- DeleteEmployee: Delete method used to delete Employee. This method required EmployeeID as a parameter.
[Route("api/[controller]")]
[ApiController]
public class EmployeeController : Controller
{
private readonly IEmployeeRepository _employeeRepository;
public EmployeeController(IEmployeeRepository employeeRepository)
{
_employeeRepository = employeeRepository;
}
[HttpGet]
public IActionResult GetAllEmployees()
{
return Ok(_employeeRepository.GetAllEmployees());
}
[HttpPost]
public IActionResult CreateEmployee([FromBody] Employee employee)
{
if (employee == null) return BadRequest();
if (string.IsNullOrEmpty(employee.FirstName) || string.IsNullOrEmpty(employee.LastName))
{
ModelState.AddModelError("Name/FirstName", "The name or first name shouldn't be empty");
}
if (!ModelState.IsValid) return BadRequest(ModelState);
var createdEmployee = _employeeRepository.AddEmployee(employee);
return Created("employee", createdEmployee);
}
[HttpGet("{employeeId}")]
public IActionResult GetEmployeeById(int employeeId)
{
return Ok(_employeeRepository.GetEmployeeById(employeeId));
}
[HttpPut]
public IActionResult UpdateEmployee([FromBody] Employee employee)
{
if (employee == null) return BadRequest();
if (string.IsNullOrEmpty(employee.FirstName) || string.IsNullOrEmpty(employee.LastName))
{
ModelState.AddModelError("Name/FirstName", "The name or first name shouldn't be empty");
}
if (!ModelState.IsValid) return BadRequest(ModelState);
var employeeToUpdate = _employeeRepository.GetEmployeeById(employee.EmployeeId);
if (employeeToUpdate == null) return NotFound();
_employeeRepository.UpdateEmployee(employee);
return NoContent(); // success
}
[HttpDelete("{id}")]
public IActionResult DeleteEmployee(int id)
{
if (id == 0) return BadRequest();
var employeeToDelete = _employeeRepository.GetEmployeeById(id);
if (employeeToDelete == null) return NotFound();
_employeeRepository.DeleteEmployee(id);
return NoContent(); // success
}
}
Our API layer is ready to be consumed by Blazor Client. Api data binding in Blazor will be covered in part 2 of the article.
Summary
Through this article, we have learned how to create Blazor web assembly projects hosted in .NET Core and also build a data access layer using Entity Framework Core to retrieve and save our application data in SQL Server.
In our next article, we will create Blazor Razor components and build a user interface to display data from APIs and save user data back to SQL Server.
Thanks a lot for reading. I hope you liked this article. Please share your valuable suggestions and feedback. Write in the comment box in case you have any questions. Have a good day!