Middleware is a very important topic in ASP.Net Core since it enables you to add very important functionality, like adding necessary configuration to deploy ASP.Net Core and Angular together. But at the same time there are a lot of misunderstandings regarding middleware in ASP.Net Core among developers that are new to the platform. That’s why I think it’s a good start to highlight the most important concepts regarding middleware so that new developers can get started much quicker with ASP.Net Core.
The concept of middleware
I won’t try to give a real and exhaustive definition of middleware (you can find this on the Microsoft documentation). Instead, I will try to depict a picture of how middleware in ASP.Net cor relate to the application you’re developing. So let’s imagine that you already have an ASP.Net Core application that is hosted somewhere and I want to make a request to that application. So when I send my GET request, it will first hit Kestrel, the web server built into ASP.Net Core. For the request, that’s the entry point to the application.
As a next step, Kestrel would need to direct the request to the controller responsible for handling my request (let’s assume that the controller exists 🙂 ). So we have a point A (Kestrel, the entry point) and point B (the controller). Now, wouldn’t it be cool if we could place some piece of software between A and B that could help us with a lot of things? Like handling authentication and authorization, logging exceptions, routing configuration, static file behavior and so on. Well, we can do exactly that and each piece of such software/code is called middleware.
Hence, middleware is like a pipeline from Kestrel (the entry point) and other parts of your application, like controllers. Each request that comes in needs to pass through this pipeline and, even more, each response will need to pass through the same pipeline in reverse, from point B to point A (Kestrel will be in this case the exit point).
In ASP.Net Core you typically configure your middleware in the StartUp.cs class, in the Configure() method and it could look like this:
[code language=”csharp” highlight=”8, 9, 10, 11, 12, 13, 14, 15, 16″]
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
CreateRootPath();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.Use(async (context, next)
{
await next();
if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value))
{
context.Request.Path = “/index.html”;
await next();
}
})
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(absolutePath),
RequestPath = new PathString(virtualPath),
});
app.UseAuthentication();
app.UseMvc();
}
[/code]
In this example everything that starts with “app.” is a middleware. So if we imagine that a request would arrive from up, it will pass through each “app.” middleware from top to bottom, while each response would pass through each middleware from bottom to top. And with this, we already started a new important topic: middleware order.
Middleware order
We already said previously, that each request will pass through each middleware from top to bottom in the code above, and each response will pass through each middleware from bottom to top. That’s why precisely the middleware order is very important in ASP.Net Core. If we have authentication, for instance, it makes sense that we authenticate the request before sending it to the controller, so the app.UseAuthentication() middleware should basically always come before the app.UseMvc() middleware. In the same perspective, if we are in a development environment and want to use friendly developer exception pages, it is always advised to have the app.UseDeveloperExceptionPage() on the first position, since in this case you can catch all exceptions (including from other middleware) on the last midleware that a response will hit.
Please note: the last middleware an incoming request will hit is the one on the last position, while the last middleware each outgoing response will hit is the one on the first position!
The next() delegate
I have highlighted a “special” middleware in the code above, so you might check it again. In a certain way, that’s a custom middleware and the most “special” thing about it is that it uses the awaited next() delegate/method. And that’s precisely the mechanism middleware use to pass the request/response to the next middleware in line. If you use a simple custom middleware and don’t use the next() delegate, you will short-circuit the entire middleware pipeline and the request/response won’t be passed to the next middleware.
In my case, the middleware is designed for a scenario where we have an Angular front end, which might have its own routes that Kestrel is not aware of. So once the request comes in, we use next() to pass it to the next middleware. We await this next(), because we want to execute the statement only when the response comes back, because only then we can check for a 404 error thrown by Kestrel that was not able to find an appropriate controller (this check might happen in app.UseMvc() ). And then we use again next() to pass the response to the next middleware. Since this is a response, which passes middleware from bottom to top, the next one would be app.UseDevelopmentExceptionPage() if we are in a development environment.
Note: next() passes the request/response to the next middleware in the pipeline. You can short-circuit the entire pipeline if you forget to use it. You can implement custom code both before it and after it.
Things to come
This only scratched the surface of middleware in ASP.Net Core. The coming days I plan to write a part two to this tutorial, in which I will concentrate on specific middleware delegates like Use(), Map() and Run().
I also plan to write an article some time about how to write your own middleware, since it might be useful also for those who are more experienced with ASP.Net Core development. So you might want to check back from time to time!
Please feel free to drop a comment if you have anything to say and if you found this piece of content useful also share it with your friends and network on social media. That’s the only way I can fin out if I should keep writing or not 🙂 Cheers!
How useful was this post?
Click on a star to rate it!
Average rating / 5. Vote count:
Dan Patrascu-Baba
Latest posts by Dan Patrascu-Baba (see all)
- Configuration and environments in ASP.NET Core - 25/11/2019
- GraphQL in the .NET ecosystem - 19/11/2019
- A common use case of delegating handlers in ASP.NET API - 12/11/2019