One of the many changes that came with ASP.NET Core is a completely new model for the request pipeline. It is great, though, because it allows complete customization of how requests are handled in your application and there is an out-of-the-box solution for basic applications. Simple needs are serviced if the requirements are simple and the pipeline can be as complex as the requirements warrant.
General Overview
The ASP.NET Core request middleware is more commonly known as middleware. Middleware is configured to handle requests in a sequenced matter, going from one component of middleware to another. At any time a component can return the request and not pass it along to the next component. When a request is returned, however, it passes back through each previous middleware component in the opposite order. So, the last component it passed through on the way in, is the first it must then pass back through on its way out.
Figure 1 – Middleware
There are several middleware components available for use in your applications that are available as part of the ASP.NET Core installation. This is a non-comprehensive list but includes some of the most common to handle standard application scenarios.
Table 1 – Common Middleware Components Included with ASP.NET Core
Type |
Method |
Description |
DeveloperExceptionPage | UseDeveloperExceptionPage() | Provides a detailed exception page if the application is running in development mode. |
DatabaseErrorPage | UseDatabaseErrorPage() | Provides a detailed instruction page if the application requires Entity Framework migrations to be ran with instructions on possible actions. |
ExceptionHandler | UseExceptionHandler() | Allows you to redirect to a specific error page when unhandled exceptions are encountered. Will also log the exception and re-execute the request if the response has not been started. |
HSTS | UseHsts() | Adds a header for the Strict-Transport Security header. |
HTTPSRedirection | UseHttpsRedirection() | Redirects HTTP traffic to HTTPS. |
StaticFiles | UseStaticFiles() | Returns static content such as HTML, JavaScript, images, CSS, etc that do not need to be executed on the server. |
CookiePolicy | UseCookiePolicy() | Adds cookie policy validation to the application. |
Authentication | UseAuthentication() | Adds identity functionality such as authentication and authorization. |
MVC | UseMvc() | Adds MVC routing and serving functionality to the application. |
Custom Middleware
The requirements for developing your own custom middleware components are surprisingly simple. First, the constructor of the middleware should accept a RequestDelegate argument. The middleware you are developing may require more such as the IHostingEnvironment or ILoggingFactory interfaces but at the bare minimum, the RequestDelegate is required. Second, a public asynchronous method that returns a Task object named Invoke. The invoke method should accept an HttpContext argument. The Invoke method should be sure to call the next component in the chain via the Next argument of the constructor but as for requirements, that is it. Let’s take a look at a quick example.
A Simple Implementation
Listing 1 – SampleMiddleware.cs
public class SampleMiddleware { public SampleMiddleware(RequestDelegate next) { _next = next; } private RequestDelegate _next = null; public async Task Invoke(HttpContext context) { int dayOfYear = DateTime.Now.DayOfYear; context.Response.Headers.Add("X-DayOfYear", new[] { dayOfYear.ToString() }); await _next(context); } }
This is everything that is required for a new middleware component. In the constructor, I am saving a reference to the next RequestDelegate so it is available later in the Invoke method. In the Invoke method, I am simply adding a new header to the response that will have the day of the year as the header value and then calling the _next request delegate.
Listing 2 – Startup.cs
app.UseMiddleware<SampleMiddleware>();
Add this line to the Configure method of the Startup.cs file.
Figure 2 – Results
Conclusion
The ASP.NET Core Middleware, or request pipeline, is wildly different than what we may be accustomed to in ASP.NET 4 but it does offer much greater control and is something we should happily embrace. It is not difficult to create our own pipeline components and in this post, we did just that however simple the example.