Strongly typed middleware with IMiddleware

Using IMiddleware to ensure correctly configured middleware

Home DailyDrop

Daily Knowledge Drop

To create custom ASP.NET Core middleware, all that is required is a class with an Invoke or InvokeAsync method. However, if configured incorrectly, the error will not be apparent until runtime.

The IMiddleware interface can be used to ensure custom middleware contains the correct method, through the implementation of the interface, ensuring any configuration errors are apparent at compile time.


Weakly typed

To define a working middleware component, a class with an Invoke or InvokeAsync method needs to be defined:

public class WeakTypeMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task Invoke(HttpContext httpContext)
    {
        Console.WriteLine($"Hello from {nameof(WeakTypeMiddleware)}");

        await _next.Invoke(httpContext);
    }
}

And the components must be added to the middleware pipeline:

app.UseMiddleware<WeakTypeMiddleware>();

However, nothing is preventing the middleware component from accidentally being configured incorrectly - in the below example the class doesn't contain a method with the correct name:

public class WeakTypeMiddleware
{
    private readonly RequestDelegate _next;

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

    // incorrect method name used
    public async Task InvokePipeline(HttpContext httpContext)
    {
        Console.WriteLine($"Hello from {nameof(WeakTypeMiddleware)}");

        await _next.Invoke(httpContext);
    }
}

The above class is a valid class, but not a valid middleware component. The above code will compile, but an exception will occur when trying to call an endpoint which makes use of the component:

System.InvalidOperationException: 'No public 'Invoke' or 'InvokeAsync' 
    method found for middleware of type 'WeakTypeMiddleware'.'

The exception tells us exactly what the problem is, and how to resolve it - it is easily fixed. However a better and cleaner approach is to never encounter the exception in the first place.


Strongly typed

A middleware component can be strongly typed by using the IMiddleware interface:

public class StrongTypeMiddleware : IMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        Console.WriteLine($"Hello from {nameof(StrongTypeMiddleware)}");

        await next.Invoke(context);
    }
}

The interface enforces the InvokeAsync method on the implementation, ensuring it will be configured correctly.

A slight difference between the two,is that with the weakly typed implementation, the next delegate is passed into the constructor, however with the strongly typed implementation, the next delegate is passed into the InvokeAsync method.


Notes

Implementing strongly typed middleware using IMiddleware instead of having the components weakly typed is a minor code change, and may not offer any immediately obvious benefits - however, using the interface will ensure code uniformity across all middleware components, as well as make it easier to find and identify middleware components in a large code base.


References

Strongly Typed Middleware in ASP.NET Core

Daily Drop 170: 28-09-2022

At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.

The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.
c# .net middleware typed stronglytyped