Creating conventional and factory-based Middleware for .NET Core

Felipe Ramos
2 min readNov 18, 2020
Processing pipeline for ASP.NET Core MVC and Razor Pages. Image from the AspNetCore.Docs
Processing pipeline for ASP.NET Core MVC and Razor Pages. Image from the AspNetCore.Docs

A quick summary — Middleware make up the application pipeline. Each piece of functionality provided for MVC, Pages, and Blazor is achieved by chaining several components together (many in specific order). Take the following line in Startup app.UseStaticFiles(), by default this is called before app.UseAuthorization(). This is done because the static files components serve files from wwwroot, and assume those are all public. By changing the registration order all of a sudden serving static files would require an authenticated user. StaticFiles component also showcase another concept from the middleware design: terminal middleware (middleware short-circuits execution). Once we find the request is looking for a static file we no longer need to worry about endpoints or routing for example so our chain stops and unrolls.

For anyone coming from ASP.NET, Middleware is similar to IHttpModules in the sense that both run for each request, can short-circuit (refer to as terminal middleware), and they can both modify, or create responses.

I digress — back to the differences between conventional and factory-based middleware. Most of the examples on writing custom middleware you’ll find follow the convention approach and aside from some minor tradeoffs they both get the job done.

1st difference is typing. Factory-based middleware implements Microsoft.AspNetCore.Http.IMiddleware where as conventional only requires the RequestDelegate injected via constructor and a Invoke function.

2nd subtle difference has to do with scope. Factory-based middleware are transient and can receive scoped services via the constructor. This is not a big deal if the scoped/transient service needed doesn’t need to be access before Invoke is call, but there might be a use case for it in your requirements.

In line # 6 you’ll notice factory-based components require an extra service call (if scoped/transient services are injected via constructor).

Sample Project
Sample Project

Sample project contain two custom middleware, RequestResponseMonitorMiddleware and UserActionMiddleware factory-based component. RequestMonitor is registered at the very top to log execution time of the entire chain. To play around with the full codebase check out the repository at the end of the document.

For the complete codebase take a look at Project Repository.

--

--