ASP.NET Core 9: Using FastEndpoints in ASP.NET Core Applicaitons

In this article, we will understand the use of the FastEndpoints in ASP.NET Core Applicaitons. FastEndpoints is a lightweight REST API development framework built for ASP.NET 8 onwards. It is designed to be a developer-friendly alternative for Minimal APIs as well as MVC Controllers. This helps offering a clean and maintainable structure with minimal boilerplate code. 

Importance of FastEndpoints

FastEndpoints follows the REPR design pattern, Request, Endpoint, Response that helps to organize code in a clear and modular way. It is especially suitable for vertical slice architecture, where each feature is self-contained that cuts through all layers of the application stack. In the vertical slice, instead of organizing code by technical layers like controllers, services, repositories, the code is organized by features or use cases.

Following are important advantages of using FastEndpoints:

  • Minimal Boilerplate: We can define endpoints without controller and its action method with attributes on them.
  • Improved Performance: It matches Minimal APIs in speed and supressed the MVC Controllers in benchmarks.
  • Cleaner Codebase: It encourages separation of concerns based on the user stories that helps to reduce the code complexity.
  • Use the built-In Features:
    • Support the FluentValidation for model validation.
    • Provides the JWT authentication and role-based security.
    • Has Auto-discovery and registration of endpoints.
    • Provides Easy integration with Swagger, Serilog, etc.
  • Flexible Dependency Injection: It supports constructor and property injection.
To define Endpoints using FastEndpoints, we need to use the following class:
  • Endpoint
    • The Endpoint class in FastEndpoints is the core building block for defining API routes and their behavior in a clean, feature-focused manner. It is the part of the FastEndpoints library.
    • The Endpoint class encapsulates the following:
      • The route
      • The request model, that represents the input data
      • The response model that is for response data
      • The handler logic, that represents the logic for the endpoint
    • Advantages of using the Endpoint class
      • This provides strong typing because we need to explicitly define the request and response model classes
      • There are not controllers
      • There is built-in support for data validations
      • We define separate endpoints for Read and Write and hence this is CQRS friendly.
      • This approach provides code-testability.
      • This improves readability and maintainability.
      • This is suitable for Microservices architecture.      
The Implementation

To implement the application code, we need SQL Server database with table in it. I have created EComm database with the ProductInfo table in it. The Listing 1, shows the script for creating table.  

USE [EComm]
GO
 
/****** Object:  Table [dbo].[ProductInfo]    Script Date: 9/9/2025 4:07:58 AM ******/
SET ANSI_NULLS ON
GO
 
SET QUOTED_IDENTIFIER ON
GO
 
CREATE TABLE [dbo].[ProductInfo](
	[ProductId] [varchar](20) NOT NULL,
	[ProductName] [varchar](100) NOT NULL,
	[CategoryName] [varchar](100) NOT NULL,
	[Description] [varchar](200) NOT NULL,
	[UnitPrice] [int] NOT NULL,
	[ProductRecordId] [int] IDENTITY(1,1) NOT NULL,
PRIMARY KEY CLUSTERED 
(
	[ProductId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON,
OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
 
Listing 1: The ProductInfo table script

Step 1: Open Visual Studio and create a new ASP.NET Core API project targeted to .NET 9. Name this project as  API_FastEndpoints. Since we will be using Entity Framework Core with database-first approach, we need to install following packages in the project:
  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Relational
  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.Tools
We also need to install package for FastEndpoints as follows:
  • FastEndpoints
Figure 1 shows the dependencies of the FastEndpoints:


Figure 1: FastEndpoints Dependencies

As shown in Figure 1, the FluentValidation is supported as built-in features.

Step 2: Use the command shown below to generate Entities and DbContext class to acess the database.

dotnet ef dbcontext scaffold "Data Source=.;Initial Catalog=EComm;User Id=[USER-NAME];Password=[PASSWORD];

TrustServerCertificate=True" Microsoft.EntityFrameworkCore.SqlServer -o Models -t ProductInfo  

The project will be added with the Models folder with ProductInfo and EcommContext classes in it.

Cut the connection string from the EcommDbContext.cs file and add it in appsettings.josn as shown in Listing 2 so that we can use the connection string during the dependency registration of EcommContext class.   

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
    "AllowedHosts": "*",
    "ConnectionStrings": {
        "AppConn": "Data Source=.;Initial Catalog=EComm;Integrated Security=SSPI;TrustServerCertificate=True"
    }
}
Listing 2: The modified appsettings.json
 
Step 3: In the project, add a new folder named Results. In this folder, add class files for request and Response classes as shown in Listing 3. We will use these classes for defining Endpoints using FastEndpoints.

public class Request
{
   public ProductInfo? Product { get; set; }
   public string? ProductId { get; set; }
}
public class Response
{
    public List<ProductInfo>? Products { get; set; }
    public ProductInfo? Product { get; set; }
    public string? Message { get; set; }
}
Listing 3: The Request and Response classes
 
Step 4: In the project, add a new folder named Endpoints. In this folder, we will create endpoints for performing GET and POST operations.  Let's add a new file named GetProductsEndpoint.cs. In this file, we will add code for the Get request. The code is shown in Listing 4.

using API_FastEndpoints.Results;
using Com.Dal.Models;
using FastEndpoints;

namespace API_FastEndpoints.EndPoints
{
    public class GetProductsEndpoint :Endpoint<Request, Response>
    {
        EcommContext _ctx;
        public GetProductsEndpoint(EcommContext ctx)
        {
            _ctx = ctx;
        }
         
        public override void Configure()
        {
            Get("/api/products/{ProductId?}");
            AllowAnonymous();
            Description(b => b
                .Produces<Response>()
                .Produces(404)
                .WithTags("Products"));
        }
        public override async Task HandleAsync(Request req, CancellationToken ct)
        {
            if (string.IsNullOrEmpty(req.ProductId))
            {
                var products = _ctx.ProductInfos.ToList();
               await HttpContext.Response.SendOkAsync(products, cancellation: ct);
                return;
            }
            var product = _ctx.ProductInfos.Find(req.ProductId);
            if (product == null)
            {
                await HttpContext.Response.SendNotFoundAsync(cancellation: ct);
                return;
            }
            await HttpContext.Response.SendOkAsync(new Response { Product = product }, cancellation: ct);
        }

    }
}
Listing 4: The Get Endpoint

As shown in Listing 5, the GetProductsEndpoint class is derived from Endpoint base class. The base class is types with Request and Response class those we have created in Listing 3, this represents the request and response to and from the endpoint. The GetProductsEndpoint class is injected using the EcommContext class to perform database operations. The Configure() method is used to define the endpoint route using the Get() method. This is an encapsulation provided by the Endpoint base class. The AllowAnonymous() method represents the Endpoint does not need the user authentication. The HandleAsync() method contains the logic for the endpoint. The method responds based on the state of the logic execution either Ok or NotFound using the Response property of the HttpContext class. This property is of HttpResponse class type.

To perform the POST Operations, in the Endpoints folder, let's add a new class file named CreateProductEndpoint.cs. As explained for Get point, we will add logic for the POST request in this class file as shown in Listing 5.
using API_FastEndpoints.Results;
using Com.Dal.Models;
using FastEndpoints;

namespace API_FastEndpoints.EndPoints
{
    public class CreateProductEndpoint: Endpoint<Request,Response>
    {
        EcommContext _ctx;
        public CreateProductEndpoint(EcommContext ctx)
        {
            _ctx = ctx;
        }

        public override void Configure()
        {
            Post("/api/products");
            AllowAnonymous();
        }

        public override async Task HandleAsync(Request req, CancellationToken ct)
        {
            try
            {
                await _ctx.ProductInfos.AddAsync(req.Product!, ct);
                await _ctx.SaveChangesAsync(ct);
                await HttpContext.Response.SendOkAsync(new Response { Product = req.Product, Message = "Product created successfully" });
            }
            catch (Exception ex)
            {
                await HttpContext.Response.SendErrorsAsync(
                    new List<FluentValidation.Results.ValidationFailure>
                    {
                        new("Exception", ex.Message)
                    },
                    500
                );
            }
        }
    }
}

Listing 5: The Post Endpoint
The CreateProductEndpoint class is exposing the Post endpoint to perform post operations.

This is how we can create separate endpoints for Read and Write operations and hence we can implement the CQRS pattern.

Step 5: Once we have created endpoints, we need to register them in ASP.NET Core pipeline. To so this we need to perform the following steps:
  • We need to use the AddFastEndpoints() method in the Service registration of the ASP.NET Core. This is used to perform the following:
    • Registers FastEndpoints services into the dependency injection container.
    • Scans application assemblies to automatically discover and register endpoint classes.
    • Sets up internal middleware, validation, and other FastEndpoints features.       
  • We need to use the UseFastEndpoints() middleware to perform following:
    • This activates FastEndpoints routing, so the endpoint classes can respond to HTTP requests. 
    • Used to maps endpoints to their respective routes like /api/products.
    • Manage request processing, validation, and response formatting.
Modify the code in Program.cs as shown in Listing 6.


using System.Text.Json;
using System.Text.Json.Serialization;
using Com.Dal.Models;
using FastEndpoints;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddDbContext<EcommContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("AppConn")));
builder.Services.AddFastEndpoints();
builder.Services.Configure<Microsoft.AspNetCore.Http.Json.JsonOptions>(options =>
{
    options.SerializerOptions.PropertyNamingPolicy = null;
    options.SerializerOptions.WriteIndented = true;
    options.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
    options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
});

// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();

 app.UseFastEndpoints();
app.Run();
Listing 6: The Program.cs

Run the application and Test endpoints using API_FastEndpoints.http file, the Get and Post request will show results as shown in Figure 2 and Figure 3.



Figure 2: The Get request
 
As shown in Listing 3, we have the Request class that contains the Product property, we need to send the Post request with 'Product' as a key in the Request as shown in Figure 3.


Figure 3: The POST request

The code for the article can be downloaded from this link

Conclusion: While building APIs if you want the speed of Minimal APIs with the structure of MVC then FastEndpoints offers a hybrid approach that is both powerful and elegant.  

Popular posts from this blog

Uploading Excel File to ASP.NET Core 6 application to save data from Excel to SQL Server Database

ASP.NET Core 6: Downloading Files from the Server

ASP.NET Core 8: Creating Custom Authentication Handler for Authenticating Users for the Minimal APIs