ASP.NET Core Middleware: A Layered system

The ASP.NET Core framework is built from the ground up with extensibility in mind, having Middleware as the fundamental core to its architecture. From a REST perspective, Middleware is an implementation of the Layered System, which is one of the constraints for REST-fulness.

This post is part of a series on Implementing REST in ASP.NET Core

Middleware in ASP.NET Core are software components that are specifically orchestrated in the application pipeline to handle requests and responses. Each component can choose to potentially modify and let the request thru to the next component or immediately return a response based on specific implementation logic.

ASP.NET Core Middleware visually explained

Compared to HTTP Modules, Middleware drastically simplifies the process by just using RequestDelegates, which is a function with a specific signature.

Writing Middleware

There are two ways of creating Middleware: Inline using IApplicationBuilder or as a self contained class.

By using the .Use() and .Run() extension methods available on IApplicationBuilder one can easily chain inline Middleware together.

Here's an example of inline Middleware in it's most basic form. This piece handles all requests and simply returns "Hello World":

public void Configure(IApplicationBuilder app)  
{
    app.Run(async ctx => await ctx.Response.WriteAsync("Hello, World!"));
}

Here's another example of inline Middleware with .Use():

public void Configure(IApplicationBuilder app)  
{
    app.Use(async (ctx, next) =>
    {
        // Code for Middleware 1
        await next.Invoke();
        // More code here like logging.
    });

    app.Use(async (ctx, next) =>
    {
        // Code for Middleware 2
        await next.Invoke();
        // More code here like logging.
    });

    app.Run(async ctx => await ctx.Response.WriteAsync("Hello World"));
}

Note that the .Run() method is called last. This terminates the pipeline.

The other way of authoring Middleware is by using classes. Middleware classes need to have a specific signature: Receive a RequestDelegate as first parameter in the constructor and have an Invoke() function receiving the HttpContext.

Here's an example:

public class AwesomeMiddleware  
{
    private readonly RequestDelegate _next;

    public MyMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
    {
        //be awesome here
        await _next(httpContext);
    }
}

The Middleware needs to be registered using the IApplicationBuilder:

public void Configure(IApplicationBuilder app)  
{
    app.UseMiddleware<AwesomeMiddleware>();

    app.Run(async ctx => await ctx.Response.WriteAsync("Hello World"));

Middleware is awesome.

Basically everything in ASP.NET Core is Middleware. If you understand this concept it's an half of a battle already won.

We've now seen how Middleware in ASP.NET Core is directly relevant to the Layered System from REST.