ASP.NET Core 6: Creating API for CRUD Operations using EntityFrameworkCore (Basic for new ASP.NET Core Learners): Part 2
In Part 1, we have gone through the basic understanding of creating an ASP.NET Core Web API project. In this part, we will see how we can use EntityFramework Core (EF Core) to build Data Access Layer and create WEB API.
EntityFramework Core
The EntityFramework Core is a cross-platform Object Relational Mapping (ORM). This provides an object model that manages database connections and mapping with tables of the database. The DbContext class provided in EF Core is used to manage database connections and performs commit transactions. The DbSet<T> generic in EF Core represent the entity class aka CLR Object mapping with a table of the database. Here we can say that T is an entity class mapped with the table of a database named T. The EF Core provides the following two approaches:
- Database First: The Entities and DataAccess layer is created based on the ready-to-use database
- Code-First: The Database and its tables are created using entities we create in the project
We can use EF Core with various databases like SQL Server, Oracle, MySQL, PostgreSQL, etc. In our application, we will use an SQL Server database with database first approach. The scripts of the database is provided in Part 1.
In the .NET Core application, we can use EF Core using the following packages
- Microsoft.EntityFrameworkCore
- Microsoft.EntityFrameworkCore.SqlServer
- Microsoft.EntityFrameworkCore.Relational
- Microsoft.EntityFrameworkCore.Design
- Microsoft.EntityFrameworkCore.Tools
"ConnectionStrings": { "AppConnStr": "Data Source=.; Initial Catalog=Company;Integrated Security=SSPI" }
namespace Core_EFApi.Services { public interface IService<TEntity, in TPk> where TEntity : class { Task<IEnumerable<TEntity>> GetAsync(); Task<TEntity> GetAsync(TPk id); Task<TEntity> CreateAsync(TEntity entity); Task<TEntity> UpdateAsync(TPk id, TEntity entity); Task DeleteAsync(TPk id); } }
using Core_EFApi.Models; using Microsoft.EntityFrameworkCore; namespace Core_EFApi.Services { public class DepartmentService : IService<Department, int> { CompanyContext ctx; public DepartmentService(CompanyContext ctx)
{
this.ctx = ctx; } async Task<Department> IService<Department, int>.CreateAsync(Department entity) { var result = await ctx.Departments.AddAsync(entity); await ctx.SaveChangesAsync(); return result.Entity; } async Task IService<Department, int>.DeleteAsync(int id) { var record = await ctx.Departments.FindAsync(id); if(record == null) return; ctx.Departments.Remove(record); await ctx.SaveChangesAsync(); } async Task<IEnumerable<Department>> IService<Department, int>.GetAsync() { return await ctx.Departments.ToListAsync(); } async Task<Department> IService<Department, int>.GetAsync(int id) { return await ctx.Departments.FindAsync(id); } async Task<Department> IService<Department, int>.UpdateAsync(int id, Department entity) { var record = await ctx.Departments.FindAsync(id); if (record == null) return null; record.DeptName = entity.DeptName; record.Capacity = entity.Capacity; record.Location = entity.Location; await ctx.SaveChangesAsync(); return record; } } }
builder.Services.AddDbContext<CompanyContext>(options => { options.UseSqlServer(builder.Configuration.GetConnectionString("AppConnStr")); }); builder.Services.AddScoped<IService<Department,int>, DepartmentService>();
using Core_EFApi.Models; using Core_EFApi.Services; using Microsoft.AspNetCore.Mvc; namespace Core_EFApi.Controllers { [Route("api/[controller]")] [ApiController] public class DepartmentContreoller : ControllerBase { private readonly IService<Department, int> deptServ; public DepartmentContreoller(IService<Department, int> serv) { deptServ = serv; } [HttpGet] public async Task<IActionResult> Get() { var response = await deptServ.GetAsync(); return Ok(response); } [HttpGet("{id}")] public async Task<IActionResult> Get(int id) { var response = await deptServ.GetAsync(id); return Ok(response); } [HttpPost] public async Task<IActionResult> Post(Department department) { var response = await deptServ.CreateAsync(department); return Ok(response); } [HttpPut("{id}")] public async Task<IActionResult> Put(int id, Department department) { var response = await deptServ.UpdateAsync(id, department); return Ok(response); } [HttpDelete("{id}")] public async Task<IActionResult> Delete(int id) { await deptServ.DeleteAsync(id); return Ok("Record is Deleted"); } } }
As shown in lisitng 5, the controller class is constructor injected with IService<Department,int> and hence it will be injected we an instance of the DepartmentService class which we have registered as a service as shown in lisitng 4. The API Controller class contains Get, Post, Put, and Delete methods decorated with the HttpGet, HttpPost, HttpPut, and HttpDelete attribute respectively. We have also defined Get() as overloaded method with one of the overloading accepts the id parameter. On this method we have applied HttpGet attribute with template paremeter passed to it. This will differenciate the Http Get request to these two overloaded methods. The Post, Put, and Delete methods will be invoked with corresponding Http request.
Now lest run the applcation, we will see the Swagger page in browser where we can test API methods as shown in Figure 5
Figure 5: The Swagger UI
Click on Get button, it will show the Try it out button, click on this button ther Execute button will be shown , on clicking on Execute button the data from teh Department table will be returned in JSON form as shown in Figure 6
Figure 6: The JSON data
Similarly, click on the Post button, this will the schema for entering Department data as shown in Figure 7
Figure 7: The Post request
Please note that, since Department contains collection of Employees, the relations is reflected here. To create new Department, modify this request by clicking Try it out button as shown in Figure 8
Figure 8: The Post request
Click on Execute button, the response will generated as shown in Figure 9
Figure 9: The Post response
Similarly, you can test Put and Delete requests. This is how ASP.NET Core Web API can be created. The inbuilt support for DI makes the application more maintainable.
Futrther Reading
Custom Middlewares in ASP.NET Core
Azure Active Directory Authentication
ASP.NET Core 6 Localization
ASP.NET Core 6: Implementing a Localization in ASP.NET Core 6 (webnethelper.com)
ASP.NET Core 6 API Role Based Security with Token and Policies
ASP.NET Core 6: Using Role Based Security for ASP.NET Core 6 WEB API (webnethelper.com)
Model Binders
Using Model Binders in ASP.NET Core (webnethelper.com)
The code for this article can be downloaded from this link.