Back to: ASP.NET Core Web API Tutorials
ASP.NET Core Minimal API using Entity Framework Core
In this article, I will discuss ASP.NET Core Minimal API using Entity Framework Core (EF Core) with examples. Please read our previous articles discussing How to Implement Asynchronous Programming in ASP.NET Core Minimal API with Examples. We will be working with the same project as we worked so far with ASP.NET Core Minimal API.
ASP.NET Core Minimal API using EF Core
To integrate Entity Framework Core (EF Core) for managing data (to perform database CRUD Operations) in an SQL Server database within an ASP.NET Core Minimal API, we need to follow the below steps:
- Add EF Core and SQL Server NuGet packages.
- Configure the DbContext.
- Update the Employee model and create the database context.
- Modify the EmployeeService to use EF Core.
- Update the endpoints to use the new service.
Add EF Core and SQL Server NuGet Packages:
We are going to use SQL Server as the database where we will store the Employee data and Entity Framework Core as the Data access technology. So, please install the following two packages using either Package Manager Console or NuGet Package Manager for the solution. You can execute the following command in the Package Manager Console to install the packages in your project:
- Install-Package Microsoft.EntityFrameworkCore.SqlServer
- Install-Package Microsoft.EntityFrameworkCore.Tools
These two packages allow us to use EF Core with SQL Server and to perform database migrations.
Define the Employee Model:
If not already defined, create an Employee model that EF Core will use to map to the database table. We have already created the following Employee model:
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace MinimalAPIDemo.Models { public class Employee { public int Id { get; set; } [Required(ErrorMessage = "Name is required")] [StringLength(100, ErrorMessage = "Name can't be longer than 100 characters")] public string Name { get; set; } [Required(ErrorMessage = "Position is required")] [StringLength(50, ErrorMessage = "Position can't be longer than 50 characters")] public string Position { get; set; } [Range(30000, 200000, ErrorMessage = "Salary must be between 30000 and 200000")] [Column(TypeName = "decimal(18,2)")] public decimal Salary { get; set; } } }
Configure the DbContext
Create a class file named ApplicationDbContext.cs within the Models folder, and then copy and paste the following code. As you can see, the following ApplicationDbContext includes a DbSet for Employees. This class is responsible for communicating with the database and performing the database CRUD operations.
using Microsoft.EntityFrameworkCore; namespace MinimalAPIDemo.Models { public class ApplicationDbContext : DbContext { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } public DbSet<Employee> Employees { get; set; } } }
Configure Connection String in appsettings.json:
We will store the connection string in the appsettings.json file. So, add the database connection string within the appsettings.json file. So, modify the appsettings.json file as follows:
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "ConnectionStrings": { "DefaultConnection": "Server=LAPTOP-6P5NK25R\\SQLSERVER2022DEV;Database=MinimalAPIDB;Trusted_Connection=True;TrustServerCertificate=True;" } }
Configure DbContext in the Program.cs File:
Register ApplicationDbContext in the Program.cs to use SQL Server and get the connection string from the appsettings.json file. So, please add the following code to the Program class.
// Add services to the container. builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
Modify the EmployeeService to Use Entity Framework Core
Update the IEmployeeService interface and EmployeeService implementation to use EF Core for database operations.
namespace MinimalAPIDemo.Models { public interface IEmployeeService { Task<IEnumerable<Employee>> GetAllEmployeesAsync(); Task<Employee> GetEmployeeByIdAsync(int id); Task<Employee> AddEmployeeAsync(Employee newEmployee); Task<Employee> UpdateEmployeeAsync(int id, Employee updatedEmployee); Task<bool> DeleteEmployeeAsync(int id); } }
EmployeeService Implementation:
using Microsoft.EntityFrameworkCore; namespace MinimalAPIDemo.Models { public class EmployeeService : IEmployeeService { private readonly ApplicationDbContext _context; public EmployeeService(ApplicationDbContext context) { _context = context; } public async Task<IEnumerable<Employee>> GetAllEmployeesAsync() { return await _context.Employees.ToListAsync(); } public async Task<Employee> GetEmployeeByIdAsync(int id) { return await _context.Employees.FindAsync(id); } public async Task<Employee> AddEmployeeAsync(Employee newEmployee) { _context.Employees.Add(newEmployee); await _context.SaveChangesAsync(); return newEmployee; } public async Task<Employee> UpdateEmployeeAsync(int id, Employee updatedEmployee) { var employee = await _context.Employees.FindAsync(id); if (employee == null) return null; employee.Name = updatedEmployee.Name; employee.Position = updatedEmployee.Position; employee.Salary = updatedEmployee.Salary; await _context.SaveChangesAsync(); return employee; } public async Task<bool> DeleteEmployeeAsync(int id) { var employee = await _context.Employees.FindAsync(id); if (employee == null) return false; _context.Employees.Remove(employee); await _context.SaveChangesAsync(); return true; } } }
Update the Endpoints to Use the New Service
Update the Program.cs to use EF Core and the new Employee Service. So, modify the Program class as follows. We are also registering the Employee Service as Scoped instead of Singleton.
using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using MinimalAPIDemo.Models; // Create a builder for the web application var builder = WebApplication.CreateBuilder(args); // Configure logging builder.Logging.ClearProviders(); // Clear default providers builder.Logging.AddConsole(); // Add Console logging provider builder.Logging.AddDebug(); // Add Debug logging provider // Add services to the DI container builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // Register EmployeeService in the DI container builder.Services.AddScoped<IEmployeeService, EmployeeService>(); // Add services to the container. builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); // Build the application var app = builder.Build(); // Use the custom error handling middleware app.UseMiddleware<ErrorHandlerMiddleware>(); // Configure the HTTP request pipeline for the development environment if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } // CRUD operations for Employee model // The EmployeeService and ILogger Services are injected into the endpoints // Endpoint to retrieve all employees app.MapGet("/employees", async (IEmployeeService employeeService, ILogger<Program> logger) => { try { logger.LogInformation("Retrieving all employees"); var employees = await employeeService.GetAllEmployeesAsync(); return Results.Ok(employees); } catch (Exception ex) { logger.LogError(ex, "An error occurred while retrieving all employees"); return Results.Problem(ex.Message); } }); // Endpoint to retrieve a single employee by their ID app.MapGet("/employees/{id}", async (int id, IEmployeeService employeeService, ILogger<Program> logger) => { try { logger.LogInformation("Retrieving employee with ID {Id}", id); var employee = await employeeService.GetEmployeeByIdAsync(id); if (employee == null) { logger.LogWarning("Employee with ID {Id} not found", id); return Results.NotFound(new { Message = $"Employee with ID {id} not found" }); } return Results.Ok(employee); } catch (Exception ex) { logger.LogError(ex, "An error occurred while retrieving employee with ID {Id}", id); var problemDetails = new ProblemDetails { Status = 500, Title = "An unexpected error occurred.", Detail = ex.Message, Instance = $"/employees/{id}" }; return Results.Problem(ex.Message); } }); // Endpoint to create a new employee with validation app.MapPost("/employees", async (Employee newEmployee, IEmployeeService employeeService, ILogger<Program> logger) => { try { if (!ValidationHelper.TryValidate(newEmployee, out var validationResults)) { // Return 400 Bad Request if validation fails return Results.BadRequest(validationResults); } logger.LogInformation("Creating a new employee"); var createdEmployee =await employeeService.AddEmployeeAsync(newEmployee); return Results.Created($"/employees/{createdEmployee.Id}", createdEmployee); } catch (Exception ex) { logger.LogError(ex, "An error occurred while creating a new employee"); return Results.Problem(ex.Message); } }); // Endpoint to update an existing employee app.MapPut("/employees/{id}", async (int id, Employee updatedEmployee, IEmployeeService employeeService, ILogger<Program> logger) => { try { if (!ValidationHelper.TryValidate(updatedEmployee, out var validationResults)) { // Return 400 Bad Request if validation fails return Results.BadRequest(validationResults); } logger.LogInformation("Updating employee with ID {Id}", id); var employee =await employeeService.UpdateEmployeeAsync(id, updatedEmployee); if (employee == null) { logger.LogWarning("Employee with ID {Id} not found", id); return Results.NotFound(new { Message = $"Employee with ID {id} not found" }); } return Results.Ok(employee); } catch (Exception ex) { logger.LogError(ex, "An error occurred while updating employee with ID {Id}", id); return Results.Problem(ex.Message); } }); // Endpoint to delete an employee app.MapDelete("/employees/{id}", async (int id, IEmployeeService employeeService, ILogger<Program> logger) => { try { logger.LogInformation("Deleting employee with ID {Id}", id); var result = await employeeService.DeleteEmployeeAsync(id); if (!result) { logger.LogWarning("Employee with ID {Id} not found", id); return Results.NotFound(new { Message = $"Employee with ID {id} not found" }); } return Results.NoContent(); } catch (Exception ex) { logger.LogError(ex, "An error occurred while deleting employee with ID {Id}", id); return Results.Problem(ex.Message); } }); // Run the application app.Run();
Add Migrations and Update Database:
Next, we need to generate the Migration and update the database schema. So, open the Package Manager Console and Execute the add-migration and update-database commands as follows. You can give your migration any name. Here, I am giving it Mig1. The name that you are giving it should not be given earlier.
With this, our Database with Employees database table should created as shown in the below image:
Now, run the application and test each endpoint, and it should work as expected.
In the next article, I will discuss How to implement Endpoint Filters in ASP.NET Core Minimal API with Examples. In this article, I explain ASP.NET Core Minimal API using Entity Framework Core (EF Core) with Examples. I hope you enjoy this article, ASP.NET Core Minimal API using Entity Framework Core (EF Core).