When a request is received by .NET Core web API, it goes through a chain of middlewares. Every middleware add some feature in the request pipeline on top of previous middleware. In addition to middleware there are also filters which are executed during request processing.
This article focuses on describing recommended order for middlewares and then how filters are executed during request pipeline.
Request Pipeline Overview
Every .NET core web app uses a
Startup class to bootstrap the application. Startup class has two methods:
- Configure Services, to configure the dependencies
- Configure, to configure the request processing pipeline. This is the part which decides which middlewares would be invoked.
The middlewares are invoked in the order in which they are configured in Configure method.
Below diagram shows overview of recommended order of middlewares for .NET Core web application. It includes some middlewares which we may not want to use with .NET core web API app.
Middlewares Order Overview
When a request is received, generally first middleware configured is exception middleware. This is because it can handle any exception from any other parts of request processing. It becomes global exception handler for the whole app. In development mode though, DeveloperExceptionPage middleware can be used instead of exception handler middleware.
Then HSTS middleware can be used to add the
Strict-Transport-Security header. Optionally, UseHttpsRedirection might be used to redirect users to HTTPS endpoint.
Note that UseHttpsRedirection middleware is not really recommended with Web APIs because this middleware sends redirect status code to client and if the web API client is not a browser, then the client might respect the redirect status codes.
Default files middleware is to rewrite the URL if the endpoint is not specified. Again this is not a web API related middleware, it makes more sense to have this in MVC apps. Hence it can be skipped for Web APIs.
On the same lines, Static Files middleware is to serve static files (js, CSS, images, etc) for a web app. It is a terminal middleware. So, any static files request would not go via subsequent middleware pipeline. This middleware also does not make sense for Web APIs.
Routing middleware (UseRouting) is to add the endpoint information to the request object. This information is later used by other middlewares. Some of those middlewares may include:
- CORS middleware for applying CORS policies
- Authentication middleware to check if the user is authenticated
- Authorization middleware to check if user is authorized to perform current operation
Session middleware is to enables and helps in maintaining server side session state. Generally this middleware might not be required as web APIs are generally stateless.
Routing middleware (UseEndpoints) is generally the last middleware in the pipeline which hands over the incoming request to appropriate endpoint (i.e. controller action) for processing. This middleware can use the patterns specified while configuring middleware to identify the endpoint.
After result is generated, response caching middleware can be used to store the processed response in cache. Optionally, response compression can also be used. Response compression middleware is generally not recommended if the “real host” (e.g. IIS or NGINX or apache) of .NET core app can support it. Response compression applied by actual web servers are generally more efficient than the middleware.
Many application might have a need for custom middleware components. And above description does not really talk about custom middleware. So where exactly custom middleware should be added ?
A custom middleware can be added anywhere in the pipeline – as long as you fully understand its purpose and other middleware’s purpose.
For example, suppose, an application wants to log requests only from authenticated users via a middleware. If this middleware is configured before static files middleware, it would not have sufficient information by then. Hence it would not be able to perform its duties.
Another example can be, let’s say an application wants to keep track of different APIs called by a user. And let’s say this custom middleware just writes incoming URL to some database table. Technically, this middleware can be configured before static files middleware. But should it be added there ? No, because if it is added there, it would end up logging all the static files requests which is not intended.
This was just first part of overview of request processing. There is also concept of filters. In next article, let’s try to discuss about it.
I hope you find this information useful. Let me know your thoughts.