ASP.NET Core Minimal APIs

• By OmerZ Solutions

ASP.NET Core Minimal APIs provide a lightweight and efficient approach for building RESTful APIs with minimal boilerplate code.

Despite their simplicity, Minimal APIs support powerful features such as Middleware, Endpoint Filters, Dependency Injection, and Entity Framework Core integration.

ASP.NET Core Minimal APIs
ASP.NET Core Minimal APIs allow developers to build clean, fast, and scalable APIs with significantly less code compared to traditional controllers.

What We Will Build

In this article, we will build a complete ASP.NET Core Minimal API example that includes:

  • Custom Middleware
  • Endpoint Filters
  • Entity Framework Core
  • SQL Server Integration
  • Student CRUD APIs

1. RequestLoggingMiddleware Middleware

Middleware in ASP.NET Core works as part of the HTTP request pipeline. Every request passes through middleware components before reaching the endpoint.

In this middleware, we log:

  • Request method
  • Request path
  • Response status code

RequestLoggingMiddleware.cs

namespace MiddlewareAndFiltersDemoWithDotNet.Middlewares
{
    public class RequestLoggingMiddleware
    {
        private readonly RequestDelegate _next;

        public RequestLoggingMiddleware(RequestDelegate next)
        {
            this._next = next;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            Console.WriteLine($"Incoming Request: {context.Request.Method} {context.Request.Path}");

            await _next(context);

            Console.WriteLine($"Response Status: {context.Response.StatusCode}");
        }
    }
}

2. StudentValidationEndpointFilter Endpoint Filter

Endpoint Filters in Minimal APIs are useful for implementing:

  • Validation
  • Authorization
  • Logging
  • Request preprocessing

In this example, the endpoint filter validates that:

  • Student name should not be empty
  • Student email should not be empty

StudentValidationEndpointFilter.cs

using MiddlewareAndFiltersDemoWithDotNet.Models;

namespace MiddlewareAndFiltersDemoWithDotNet.EndpointFilters
{
    public class StudentValidationEndpointFilter : IEndpointFilter
    {
        public async ValueTask<object?> InvokeAsync(
            EndpointFilterInvocationContext context,
            EndpointFilterDelegate next)
        {
            var student = context.GetArgument<Student>(0);

            Dictionary<string, string[]> errors =
                new Dictionary<string, string[]>();

            if (string.IsNullOrWhiteSpace(student.Name))
            {
                errors.Add(nameof(student.Name),
                    new string[] { "Student name is required" });
            }

            if (string.IsNullOrWhiteSpace(student.Email))
            {
                errors.Add(nameof(student.Email),
                    new string[] { "Student email is required" });
            }

            if (errors.Count > 0)
            {
                return Results.ValidationProblem(errors);
            }

            return await next(context);
        }
    }
}

3. Student Model

namespace MiddlewareAndFiltersDemoWithDotNet.Models
{
    public class Student
    {
        public int ID { get; set; }

        public string Name { get; set; } = string.Empty;

        public string Email { get; set; } = string.Empty;
    }
}

4. SchoolDbContext

using Microsoft.EntityFrameworkCore;
using MiddlewareAndFiltersDemoWithDotNet.Models;

namespace MiddlewareAndFiltersDemoWithDotNet.Data
{
    public class SchoolDbContext : DbContext
    {
        public DbSet<Student> Student { get; set; }

        public SchoolDbContext(
            DbContextOptions<SchoolDbContext> options)
            : base(options)
        {

        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }
}

5. Program.cs File

The Program.cs file configures:

  • Dependency Injection
  • Entity Framework Core
  • Middleware Pipeline
  • Minimal APIs
  • Endpoint Filters

Program.cs

using Microsoft.EntityFrameworkCore;

using MiddlewareAndFiltersDemoWithDotNet.Data;
using MiddlewareAndFiltersDemoWithDotNet.EndpointFilters;
using MiddlewareAndFiltersDemoWithDotNet.Middlewares;
using MiddlewareAndFiltersDemoWithDotNet.Models;

namespace MiddlewareAndFiltersDemoWithDotNet
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.
            builder.Services.AddDbContext<SchoolDbContext>(
                options => options.UseSqlServer(
                builder.Configuration.GetConnectionString("SchoolConn")));

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            app.UseMiddleware<RequestLoggingMiddleware>();

            app.MapPost("/students",
                (Student student, SchoolDbContext schoolDbContext) =>
            {
                schoolDbContext.Student.Add(student);

                schoolDbContext.SaveChanges();

                return Results.Created(
                    string.Format("/students/{0}", student.ID),
                    student);

            }).AddEndpointFilter<StudentValidationEndpointFilter>();

            app.MapGet("/students",
                (SchoolDbContext schoolDbContext) =>
            {
                return Results.Ok(
                    schoolDbContext.Student.ToList());
            });

            app.MapGet("/students/{id:int}",
                (int id, SchoolDbContext schoolDbContext) =>
            {
                var student = schoolDbContext.Student
                    .Where(x => x.ID == id)
                    .FirstOrDefault();

                if (student != null)
                {
                    return Results.Ok(student);
                }
                else
                {
                    return Results.NotFound();
                }
            });

            app.Run();
        }
    }
}

6. appsettings.json File

Add the SQL Server connection string inside the appsettings.json file.

"ConnectionStrings": {
  "SchoolConn": "Server=localhost;Initial Catalog=MyMWEF;Integrated Security=True;TrustServerCertificate=True;"
}

Entity Framework Core Migration

Add Migration

Add-Migration InitialCreate

Update Database

Update-Database

Add Student API Example

POST /students

Request Body

{
  "name": "John Smith",
  "email": "john@example.com"
}

Successful Response

{
  "id": 1,
  "name": "John Smith",
  "email": "john@example.com"
}

Validation Error Example

{
  "errors": {
    "Name": [
      "Student name is required"
    ],
    "Email": [
      "Student email is required"
    ]
  }
}

Get All Students API Example

GET /students

Response

[
  {
    "id": 1,
    "name": "John Smith",
    "email": "john@example.com"
  }
]

Get Student By ID API Example

GET /students/1

Response

{
  "id": 1,
  "name": "John Smith",
  "email": "john@example.com"
}

Middleware vs Endpoint Filter

Feature Middleware Endpoint Filter
Scope Global Endpoint Specific
Access to Endpoint Arguments No Yes
Best Use Case Logging, Authentication Validation, Endpoint Logic
Applied Using UseMiddleware() AddEndpointFilter()

Conclusion

ASP.NET Core Minimal APIs provide a clean and modern approach for building REST APIs with minimal code.

By combining:

  • Custom Middleware
  • Endpoint Filters
  • Entity Framework Core
  • Dependency Injection

developers can build scalable, maintainable, and production-ready APIs efficiently.

In this article, we created:

  • RequestLoggingMiddleware for request logging
  • StudentValidationEndpointFilter for validation
  • Student CRUD Minimal APIs
  • SQL Server integration using Entity Framework Core

Need Help Building ASP.NET Core Applications?

OmerZ Solutions helps businesses build scalable, secure, and enterprise-grade ASP.NET Core applications.

Contact Us