Skip to main content Skip to footer

Utilizing the IMiddleware interface in Umbraco

What Is Middleware

Middleware is software executed as part of an application's request and response processing pipeline.

Middleware components are arranged in a pipeline and executed sequentially in the order they are registered. A middleware component can prevent further components in the pipeline from being called. Middleware allows developers to customise the behaviour of the request processing pipeline by adding or modifying components.

Middleware supported out of the box by Microsoft includes support for HSTS, HttpsRedirection, Static Files and more. Examples of ways to extend this include support for caching, logging, image processing, header injection and permissions policies.

The IMiddleware Interface

The interface IMiddleware allows developers to customise the middleware for the app's request pipeline. It handles requests and responses through the request pipeline. From Microsoft:

IMiddlewareFactory/IMiddleware is an extensibility point for Middleware activation that offers the following benefits:

  • Activation per client request (injection of scoped services)
  • Strong typing of middleware

An example is shown below:

public class MyMiddleware : IMiddleware
{
    private readonly IMyService _myService;
    private readonly IUmbracoContextAccessor _umbracoContextAccessor;

    public MyMiddleware(IMyService myService, IUmbracoContextAccessor umbracoContextAccessor)
    {
        _myService = myService;
        _umbracoContextAccessor = umbracoContextAccessor;
    }

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        // Your custom middleware logic here using _myService
        // ...

        await next(context);
    }
}

Middleware Component Execution Order

The middleware pipeline is configured in Program.cs. Components are executed in the order they are added to the pipeline; Microsoft details the middleware order in full. The terminal middleware is Endpoint middleware; this is the last piece of middleware that will be executed before a response is sent to the client.

This means:

  • Ordering of custom middleware must consider the pipeline and the pipeline components that come before and after it.
  • Middleware must be add calls prior to UseEndpoints() method or, if developing with Umbraco, before .WithEndpoints() method. 

Umbraco

In Umbraco in  Program.cs the Middleware components can be registered before app.UseUmbraco() as follows:

app.UseMiddleware<MyMiddleware>();

app.UseUmbraco()
    .WithMiddleware(u =>
    {
        u.UseBackOffice();
        u.UseWebsite();
    })
    .WithEndpoints(u =>
    {
        u.UseInstallerEndpoints();
        u.UseBackOfficeEndpoints();
        u.UseWebsiteEndpoints();
    });

For any MiddleWare routine that relies on the UmbracoPipeline consider using the Middleware extension points that Umbraco provides.

Non-Umbraco Sites

For non-Umbraco Sites the middleware can be injected as follows into Program.cs:

app.UseMiddleware<MyMiddleware>();
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
       ....
    });

Container Registration

Microsoft refers to the use of IMiddleware or IMiddlewareFactory as "factory-activated" middleware. For it to work correctly, it must be registered in the built-in container.

Umbraco

In Umbraco sites the IComposer pattern can be followed:

using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;

public class MyMiddlewareComposer: IComposer
{
public void Compose(IUmbracoBuilder builder)
{
builder.Services.AddTransient<MyMiddleware>();
}
}

Non-Umbraco Sites

Inject the middleware into the container, in Program.cs as follows:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddTransient<FactoryActivatedMiddleware>();

Top Tips

  • Too much middleware will slow the application down.
  • Be mindful of execution order when adding middleware components.

Summary

The IMiddleware interface allows modification of incoming requests and outgoing responses. It creates an extension point for dependency injection/ inversion of control into Middleware. This enables the development of testable, robust applications.

References