Why custom middlewares are not required to implement an interface or derive from a base class in asp.net core 3?

Viewed 531

I'm new to asp.net core, sorry if my question sounds dumb. In asp.net core 3, we can implement a custom middleware as simple as:

public class CustomMiddleware 
{
   private RequestDelegate next;
   public CustomMiddleware (RequestDelegate nextDelegate) {
      next = nextDelegate;
   }
   public async Task Invoke(HttpContext context) {
      ...
   }
}

so our custom middlewares don't need to implement an interface such as IMiddleware or inherit from an abstract base Middleware class, which is a little bit strange to me. Because for some other thing like controller, we have public class HomeController : ControllerBase. So why Microsoft not setup a strong type interface/abstract class for custom middleware, for example,

public abstract class BaseMiddleware {
    public BaseMiddleware(RequestDelegate nextDelegate) {
      next = nextDelegate;
    }
    public abstract async Task Invoke(HttpContext context);
}

so that our custom middleware can be:

public class CustomMiddleware : BaseMiddleware 
{
   public CustomMiddleware(RequestDelegate nextDelegate) : base(nextDelegate) {}
   public override async Task Invoke(HttpContext context) {
      ...
   }
}
1 Answers

You do have the possibility to implement IMiddleware (MSDN). Its signature is slightly different than a normal one because this interface has declared the Invoke method in the following way:

System.Threading.Tasks.Task InvokeAsync 
  (Microsoft.AspNetCore.Http.HttpContext context,
   Microsoft.AspNetCore.Http.RequestDelegate next)

As you can see the RequestDelegate is now part of the Invoke method parameters. In conventional cases you receive that reference in your custom middleware's ctor.

Similarly if your middleware relies on any dependency then you will receive that in a different way:

public class MiddlewareA
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext context, IDependency dep)
    {
        ...
        await next(context);
    }
}
public class MiddlewareB : IMiddleware
{
    private readonly IDependency _dep;

    public FactoryActivatedMiddleware(IDependency dep)
    {
        _dep = dep;
    }

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        ...
        await next(context);
    }
}

This type of middleware is called factory-based middleware.

Related