Middleware Components And Request Pipeline in ASP.NET Core

Introduction

In this article, we will discuss the Middleware And Request Pipeline. In the previous article, we have seen the overview of application flow let’s understand Middleware and pipeline in detail. Please, read our previous article before proceeding to this article where we learn ASP.NET Core appsettings.json file.

What is Middleware?

The middleware is a piece of software that can handle an HTTP request or response given middleware. a component has a very specific purpose, for example, we may have a middle of a component that authenticates a user another piece of middlewares to handle errors yet another middleware to pass static files such as JavaScript and CSS files, images, etc.

So, middleware components use to set up a request processing pipeline. it is this pipeline that determines how a request is processed they request the pipeline configures as part of the application startup by this configure method that is present in the startup class.


public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
	app.Run(async (context) =>
	{
		await context.Response.WriteAsync("<p> Hello World middleware 1 </p>");
	});
}

we already know the execution of an ASP.NET Core project starts with this main method.

ASP.NET Core main method

The main method calls create a default build method which sets up a default web host as part of setting up the web host.

we are also configuring the startup class using this UseStartup of extension method and this startup class is present in this file and within its class, we’ve got two methods configured services and configure.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace FirstCoreWebApplication
{
    public class Startup
    {
        private IConfiguration _config;
        // Below we are using Dependency Injection to inject the Configuration object
        public Startup(IConfiguration config)
        {
            _config = config;
        }
        
        public void ConfigureServices(IServiceCollection services)
        {
        }
        
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync(_config["MyCustomKey"]);
            });
        }
    }
}

How Does Pipeline work?

When the HTTP request comes in something must handle that request. So it results in an HTTP response those pieces of code that handles the request and results in response make up the request pipeline.

middleware pipeline in asp.net core

What we can do is configure this request pipeline by adding middleware layers. The software components assemble into an application pipeline to handle requests and responses.

So, a browser is going to send a request to a server and that request is going to interpretes by the server and handled by some piece of software.

Now, first, that request attaches to something called the context object as a part of the software that manages this context.

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
            // start work that doesn't write to the Response.
            await next.Invoke();
            //  start to logging or other work that doesn't write to the Response.
        });

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from 2nd delegate.");
        }); 
    }
}

In our case, it would be Asp.Net Core middlewares. you can essentially think of it as a pipeline which is a series of pipes that are going to determine what is going to happen to the context.

So, first, the request is passed along the first by and the first byte interprets the context and checks out the request and determines if there is some type of response needed and attach that to the context.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    // app.UseCookiePolicy();

    app.UseRouting();
    // app.UseRequestLocalization();
    // app.UseCors();

    app.UseAuthentication();
    app.UseAuthorization();
    // app.UseSession();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

Request Processing Pipeline

If there is no immediate response that should be handed back to the server. Then the context is simply passed along to the next pipe in the pipeline this continues again to the next piece of the middle where whatever it might be.

And it goes on till it reaches the very large pipe.

Now, it is also possible that at the end of the pipeline no response has been formed and that will cause a 404 for not found and written back to whoever originated the request.

However, it is possible that in any one or more of these middlewares there may be a response that needs to be passed back and it could happen in any of the pipes.

Request Processing Pipeline

So, sometimes it could happen that the middlewares would not pass the context along. The next piece but rather says Okay we have a response that we need to send back but typically your context.

will go all the way through the pipeline to the end. But, the last piece of middleware sends a response that gets back through the pipeline to the server and then the server sends back the response to the browser.

This is a very simplified version of how request works. the request comes into the server then accesses the .NET Core framework and puts the request into a context object.

The context gets passed along through the middle class and if a middleware has a response anywhere along the way then it will attach that response to the context object and then pass that context object back through the pipeline to the server and then the server sends back the response to the browser.

Now, keep in mind the order of pipelines is important. It always gets passed from the first to the last. A good following example.

1.Exception/error handling
Developer Exception Page Middlewares (UseDeveloperExceptionPage) report app runtime errors.

ex. 

if (env.IsDevelopment())
{
	app.UseDeveloperExceptionPage();
	app.UseDatabaseErrorPage();
}
else
{
	app.UseExceptionHandler("/Error");
	app.UseHsts();
}

2.HTTPS Redirection Middleware redirects HTTP requests to HTTPS.

ex.
    app.UseHttpsRedirection();

3. Static File Middleware returns static files and short-circuits further request processing.

ex.     
	app.UseStaticFiles();

4. Cookie Policy Middleware conforms the app to the EU General Data Protection Regulation (GDPR) regulations.

ex. 
    app.UseCookiePolicy();

5. Routing Middleware to route requests.

ex.     
	app.UseRouting();

6. Authentication Middleware attempts to authenticate the user before they’re allowed access to secure resources.

ex.
    app.UseAuthentication();

7. Authorization Middleware (UseAuthorization) authorizes a user to access secure resources.

ex.
    app.UseAuthorization();

8. Session Middleware (UseSession) establishes and maintains session state. If the app uses session state, then call the Session Middleware after Cookie Policy Middleware and before MVC Middleware.

ex.
    app.UseSession();

9. Endpoint Routing Middleware to add Razor Page’s endpoints to the request pipeline.

ex.
app.UseEndpoints(endpoints =>
{
	endpoints.MapRazorPages();
});

A good example will be authentication middleware If the middleware component finds that a request isn’t authorized it will not pass it to the next piece of the middleware but it will immediately return an unauthorized response.

It is hence important that authentication Middleware is added before other components that shouldn’t be triggered in case of an unauthorized request.

We will be adding more middleware in our project but we’ll do them as we face that requirement for that.

Thank you for reading this article, I hope you will understand the Middleware Components And Request Pipeline in ASP.NET Core. We’ll get into more details about this when we’ll learn Static Files Middleware in ASP.NET Core in the next article.

Leave a Reply

Your email address will not be published. Required fields are marked *