Middleware in Minimal API with .NET 8

Before reading this article, I recommend looking at my article Minimal API in .NET 8: A Simplfied Approach to Build Web APIs.

What is Minimal API Middleware?

Middleware, in the context of Minimal API, refers to the components that participate in the processing of HTTP requests and responses. These components are organized into a pipeline that allows developers to execute code at different stages of the request lifecycle. Unlike traditional ASP.NET Core applications, where configuring middleware involves several steps, Minimal API streamlines this process by providing a more concise and focused approach.

Common Minimal API Middleware

  • Routing Middleware: Responsible for mapping incoming requests to the appropriate endpoint based on defined routes.
  • Authentication Middleware: Handles user authentication, ensuring secure access to your Minimal API endpoints.
  • Exception Handling Middleware: Catches and handles exceptions, providing a centralized mechanism for managing errors in your API.
  • Logging Middleware: Offers a way to log information about requests, responses, and other relevant details for troubleshooting and analysis.
  • CORS Middleware: Enables Cross-Origin Resource Sharing, allowing controlled access to your API from different domains.

In this article, we will delve into the development and incorporation of three distinct custom middleware components: request logging, request modification and response modification.

1. Request Logging Middleware

Request Logging Middleware is used to log information about incoming HTTP requests. It can capture details like the request method, URI, headers, and other relevant information for debugging or analysis purposes.

app.Use(async (context, next) =>
{
    Console.WriteLine($"Incoming Request: {context.Request.Protocol} {context.Request.Method} {context.Request.Path}{context.Request.QueryString}");
    await next();
});

Output

2. Request Modification Middleware

Request Modification Middleware allows you to modify incoming HTTP requests before they reach your endpoints. This can include adding headers, modifying parameters, or performing any necessary transformations.

app.Use(async (context, next) =>
{
    context.Request.Headers.Append("Custom-Header", "Request Modified");

    // Log all headers for demonstration purposes
    foreach (var header in context.Request.Headers)
    {
        Console.WriteLine($"Custom-Header: {context.Request.Headers["Custom-Header"]}");
    }

    await next();
});

Output

Incoming request

3. Response Modification Middleware

Response Modification Middleware is used to modify the HTTP responses generated by your endpoints. This can involve adding headers, transforming content, or making any necessary adjustments.

app.Use(async (context, next) =>
{
    context.Response.OnStarting(() =>
    {
        if (!context.Response.Headers.ContainsKey("Custom-Header"))
        {
            context.Response.Headers.Append("Custom-Header", "Response Modified");
        }
        return Task.CompletedTask;
    });

    await next();
});

Output

Response headers

Below program.cs file full code

using Microsoft.AspNetCore.Http.HttpResults;
using MinimalApi;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<IBookService, BookService>();

var app = builder.Build();

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

app.UseHttpsRedirection();

//---------------------------- Middlewares -----------------------------//

// Request Logging Middleware
app.Use(async (context, next) =>
{
    Console.WriteLine($"Incoming Request: {context.Request.Protocol} {context.Request.Method} {context.Request.Path}{context.Request.QueryString}");
    await next();
});

// Request Modification Middleware
app.Use(async (context, next) =>
{
    context.Request.Headers.Append("Custom-Header", "Request Modified");

    // Log all headers for demonstration purposes
    foreach (var header in context.Request.Headers)
    {
        Console.WriteLine($"Custom-Header: {context.Request.Headers["Custom-Header"]}");
    }

    await next();
});

// Response Modification Middleware
app.Use(async (context, next) =>
{
    context.Response.OnStarting(() =>
    {
        if (!context.Response.Headers.ContainsKey("Custom-Header"))
        {
            context.Response.Headers.Append("Custom-Header", "Response Modified");
        }
        return Task.CompletedTask;
    });

    await next();
});


//---------------------------- Endpoints -----------------------------//

// Hello Word
app.MapGet("/", () => "Hello, World!");

// Example 1: Get all books
app.MapGet("/books", (IBookService bookService) =>
    TypedResults.Ok(bookService.GetBooks()))
    .WithName("GetBooks");

// Example 2: Get a specific book by ID
app.MapGet("/books/{id}", Results<Ok<Book>, NotFound> (IBookService bookService, int id) =>
{
    var book = bookService.GetBook(id);
    return book is { } ? TypedResults.Ok(book) : TypedResults.NotFound();
}).WithName("GetBookById");

// Example 3: Add a new book
app.MapPost("/books", (IBookService bookService, Book newBook) =>
{
    bookService.AddBook(newBook);
    return TypedResults.Created($"/books/{newBook.Id}", newBook);
}).WithName("AddBook");

// Example 4: Update an existing book
app.MapPut("/books/{id}", (IBookService bookService, int id, Book updatedBook) =>
{
    bookService.UpdateBook(id, updatedBook);
    return TypedResults.Ok();
}).WithName("UpdateBook");

// Example 5: Delete a book by ID
app.MapDelete("/books/{id}", (IBookService bookService, int id) =>
{
    bookService.DeleteBook(id);
    return TypedResults.NoContent();
}).WithName("DeleteBook");

app.Run();

To sum it up, middleware is like a set of tools that help control and customize how your minimal API handles requests and responses. It allows you to add special features, like logging or modifying requests, in a specific order. This flexibility makes it easier for developers to fine-tune their APIs and make them work just the way they want. In a nutshell, middleware gives you the power to shape how your API behaves, making it a handy tool in .NET 8 minimal APIs.

References: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/middleware?view=aspnetcore-8.0

The source code is available on the following repository: https://github.com/alibenchaabene/MinimalApi/tree/features/Middlewares

Thank you for reading, please let me know your questions, thoughts, or feedback in the comments section. I appreciate your feedback and encouragement.

Happy Documenting!


Similar Articles