ASP.NET Core Middleware Components

ASP.NET Core Middleware with Examples

In this article, I will discuss the ASP.NET Core Middleware Components with Examples. Please read our previous article discussing the ASP.NET Core AppSettings.json File with Examples.

What are ASP.NET Core Middleware Components?

ASP.NET Core Middleware Components are the basic building blocks of the Request Processing Pipeline in ASP.NET Core Applications. The Request Processing Pipeline determines how HTTP Requests and Responses will be processed in the ASP.NET Core Application. So, middleware components are used to implement various functionalities like authentication, authorization, error handling, routing, and logging.

Middleware components are executed in the order they are added to the pipeline, and each middleware component in the ASP.NET Core Application performs the following tasks.

  • Chooses whether to pass the HTTP Request to the next Middleware component registered in the request processing pipeline.
  • Can perform certain tasks before and after the next component is invoked in the pipeline.

Note: In ASP.NET Core, many built-in Middleware components are already made available for us to use directly. We can also create our custom Middleware components as per our business requirements. The most important point you need to remember is that a given Middleware component should only have a specific purpose, i.e., a single responsibility.

How Do We Configure Middleware Components in ASP.NET Core Applications?

We need to configure the Middleware Components within the Main() method of the Program class, which is present inside the Program.cs class file using the WebApplication instance. When we create a new ASP.NET Core Empty Web Application, the Program class is created with the Main method by default, as shown in the image below. The following Main method configures two middleware components, MapGet and Run, by default.

How Do We Configure Middleware Components in ASP.NET Core Applications?

How Does the Middleware Component Works in the ASP.NET Core Application?

In the ASP.NET Core Web Application, the Middleware Component can access both the incoming HTTP Request and outgoing HTTP Response. So, a Middleware Component in ASP.NET Core Web Application can

  • Handle the incoming HTTP request by generating an HTTP response.
  • Process the incoming HTTP request, modify it, and then pass it to the Next Middleware Component configured in the Request Processing Pipeline.
  • Process the outgoing HTTP response, modify it, and then pass it on to either the previous middleware component or the ASP.NET Core Web Server.

For a better understanding, please look at the following diagram, which shows how the middleware components are used in the Request Processing Pipeline of an ASP.NET Core Web Application. As shown in the image below, we have configured 3 Middleware Components to handle HTTP Requests and Responses.

How Does the Middleware Component Works in the ASP.NET Core Application?

We have a Logging Middleware Component. This component logs the request time and then passes the HTTP Request to the next middleware component, i.e., the Static Files Middleware component in the Request Pipeline, for further processing.

As previously discussed, a Middleware Component in an ASP.NET Core Web Application may also handle the HTTP Request by generating an HTTP Response. The Middleware Component may also decide not to call the Next Middleware Component in the Request Processing Pipeline, a concept called Short-Circuiting the Request Processing Pipeline.

For example, we have a Static Files Middleware Component. Suppose the incoming HTTP request comes for some static files such as images, CSS files, JavaScript, etc. In that case, this Static Files Middleware component can handle the request and then Short-Circuiting the Request Processing Pipeline by not calling the Next Middleware Component in the pipeline, i.e., the MVC Middleware Component.

The ASP.NET Core Middleware Components can access both the HTTP Request and Response in the pipeline. So, a middleware component can also process the outgoing response. For example, the logging middleware component, in our case, may log the time when the response is sent back to the client.

What is the Execution Order of Middleware Components?

It is very important to understand the execution order of Middleware Components in ASP.NET Core Web Applications. These components are executed in the same order as they are added to the Request Processing Pipeline for incoming requests and in reverse order for outgoing responses. So, we must take proper care when adding the Middleware Components to the Request Processing Pipeline. If we add them in the wrong order, then we might get unexpected behavior.

How Do We Configure Middleware Components in ASP.NET Core?

To configure Middleware Components, we can use the Map/MapGet, Run, and Use extension methods in ASP.NET Core applications.

Configuring Middleware Components using Map/MapGet Extension Method:

First, let us see how to configure Middleware Components using the MapGet Extension method. So, please modify the Main method of the Program class as follows to add a few Middleware Components using the Map Extension Method.

namespace FirstCoreWebApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Initializes the configuration for the web application
            var builder = WebApplication.CreateBuilder(args);

            // Builds the web application based on the configured settings
            var app = builder.Build();

            // Maps HTTP GET requests to the root URL "/" to a method returning "Hello World!"
            app.MapGet("/", () => "Hello World!");

            // Maps HTTP GET requests to "/greet" URL to a method returning a greeting message
            app.MapGet("/greet", () => "Hello from the /greet endpoint!");

            // Maps HTTP GET requests to "/greet/{name}" URL to a method that uses a route parameter
            app.MapGet("/greet/{name}", (string name) => $"Hello, {name}!");

            // Starts the web application which begins listening for incoming requests
            app.Run();
        }
    }
}

Now, run the application and access the endpoints using the appropriate URL. Based on the URL, the respective endpoint will be executed. Instead of using MapGet, we can also use the Map extension method, and it should work as expected.

What is the Difference Between MapGet and Map Extension Methods in ASP.NET Core?

In ASP.NET Core, both MapGet and Map are extension methods used for defining endpoint middleware and mapping the incoming HTTP requests to specific middleware components, but they have distinct purposes and use cases:

MapGet Method:
  • MapGet is specifically designed to handle HTTP GET requests. It’s used to define endpoints that respond only to GET requests.
  • We typically use MapGet to retrieve data from the server without modifying its state, such as fetching a list of items or getting details about a specific item.
  • The MapGet method usually takes a route pattern and a request delegate (a handler function). The handler function is executed when a GET request matches the specified route pattern.
Map Method:
  • Map is a general method for handling all types of HTTP requests (such as GET, POST, PUT, DELETE, etc.). It’s more flexible than MapGet.
  • We need to use Map when we need to set up endpoints that might handle multiple types of HTTP requests or when we have custom logic to determine the type of request to be handled.
  • Like MapGet, Map also takes a route pattern and a request delegate. However, since Map can handle various HTTP methods, the request delegate often contains logic to differentiate between these methods.

Note: Once we progress in this course, we will discuss handling GET, POST, PUT, and DELETE requests using the Map method using Minimal APIs.

Configuring Middleware Components using the Run Extension Method:

Now, let us see how to configure Middleware Components using the Run Extension method. So, modify the Main method of the Program class as follows to add a new custom Inline Middleware Component using the Run Extension Method.

namespace FirstCoreWebApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Initializes the configuration for the web application
            var builder = WebApplication.CreateBuilder(args);
            
            // Builds the web application based on the configured settings
            var app = builder.Build();

            //Configuring New Inline Middleware Component using Run Extension Method
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Getting Response from First Middleware");
            });

            // Starts the web application which begins listening for incoming requests
            app.Run();
        }
    }
}

Now, run the application, and you should get the expected output, as shown in the image below.

Configuring Middleware Components using the Run Extension Method

If you go to the definition of the Run Extension Method, you will see the following signature. It basically adds a terminal middleware delegate to the application’s request pipeline.

What is the Execution Order of Middleware Components?

Here, you can see that it clearly says that this is an extension method used for adding terminal middleware components. Terminal Middleware is the last middleware component. You can also see from the above definition of the Run() Extension method that it takes an input parameter of RequestDelegate type. Now, if you go to the definition of RequestDelegate, then you will see the following.

How Do We Configure Middleware Components in ASP.NET Core?

As you can see in the above image, the RequestDelegate is a delegate that takes an input parameter of type HttpContext object.

As we already discussed, the middleware components in an ASP.NET Core Web Application can access both HTTP Request and Response, and this is because of the above HttpContext object. In our example, we are passing an anonymous method or delegate to the Run Extension method, and moreover, we are passing the HTTP Context object as an input parameter. The following diagram shows the above.

Configuring Middleware Components using Map/MapGet Extension Method

Instead of passing the request delegate as an inline anonymous method, we can define it in a separate method and pass it here. To better understand, please modify the Program class code as follows.

namespace FirstCoreWebApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Initializes the configuration for the web application
            var builder = WebApplication.CreateBuilder(args);
            
            // Builds the web application based on the configured settings
            var app = builder.Build();

            //Configuring New Inline Middleware Component using Run Extension Method
            app.Run(FirstMiddleware);

            // Starts the web application which begins listening for incoming requests
            app.Run();
        }

        //This method signature must be the same as the RequestDelegate signature
        private static async Task FirstMiddleware(HttpContext context)
        {
            //Using context object, we can access both Request and Response
            await context.Response.WriteAsync("Getting Response from First Middleware");
        }
    }
}

In this example, the FirstMiddleware method is defined separately and then passed to the Run extension method. Now, run the application, and you should see the same output. The most important point to remember is that the FirstMiddleware method signature should and must be the same as the RequestDelegate delegate signature; otherwise, you will get a compile-time error.

How Do We Add Multiple Middleware Components to the Request Processing Pipeline?

Let us modify the Program class as follows to add two custom inline middleware components to the Request processing pipeline.

namespace FirstCoreWebApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Initializes the configuration for the web application
            var builder = WebApplication.CreateBuilder(args);
            
            // Builds the web application based on the configured settings
            var app = builder.Build();

            //Configuring First Middleware Component using Run Extension Method
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Getting Response from First Middleware");
            });

            //Configuring Second Middleware Component using Run Extension Method
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Getting Response from Second Middleware");
            });

            // Starts the web application which begins listening for incoming requests
            app.Run();
        }
    }
}

Now, we have two middleware components registered using the Run() extension method. Run the application, and you will get the following output.

How Do We Add Multiple Middleware Components to the Request Processing Pipeline?

The output is coming from the first middleware component. When we register a middleware component using the Run() extension method, that component becomes a terminal component, meaning it will not call the next middleware component registered in the request processing pipeline. The first middleware component is not called the second middleware component.

Then, the question that should come to your mind is how to call the next middleware component registered in the request processing pipeline. The answer is to register the middleware component using the Use extension method.

Configuring Middleware Components Using the Use Extension Method

Let us modify the Program class code as follows to register the Middleware component using the Use extension method. As you can see in the code below, the First middleware component is registered using the Use extension method, and the second middleware component is registered using the Run extension method.

Further, in the first Use Extension method, we pass two input parameters to the anonymous method, i.e., context and next. Then, we call the next delegate, which will call the next middleware component registered in the Request Processing Pipeline.

namespace FirstCoreWebApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Initializes the configuration for the web application
            var builder = WebApplication.CreateBuilder(args);
            
            // Builds the web application based on the configured settings
            var app = builder.Build();

            //Configuring First Middleware Component using Use Extension Method
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync("Getting Response from First Middleware");
                await next();
            });

            //Configuring Second Middleware Component using Run Extension Method
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("\nGetting Response from Second Middleware");
            });

            // Starts the web application which begins listening for incoming requests
            app.Run();
        }
    }
}

Now run the application, and you will see the output as expected, which is coming from both middleware components, as shown in the image below.

Configuring Middleware Components Using the Use Extension Method

Understanding the Use Extension Method in ASP.NET Core:

If you go to the definition of the Use extension method, you will see the following signature.

What is the Difference Between MapGet and Map Extension Methods in ASP.NET Core?

This method has also been implemented as an extension of the IApplicationBuilder interface. As you can see from the above definition, this method takes two input parameters. The first parameter is the HttpContext context object, through which it can access both the HTTP request and response. The second parameter is the Func type, i.e., a generic delegate, which we can use to call the next middleware component registered in the request processing pipeline. 

Can we create a Terminal Middleware Component using the Extension method?

It is also possible to create a terminal middleware component using the Use extension method in ASP.NET Core. A terminal middleware component handles the request completely and does not call the next() delegate. In this case, we need to specify the context object and explicitly request a delegate. For a better understanding, please modify the Program class as follows.

namespace FirstCoreWebApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Initializes the configuration for the web application
            var builder = WebApplication.CreateBuilder(args);
            
            // Builds the web application based on the configured settings
            var app = builder.Build();

            //Configuring First Middleware Component using Use Extension Method
            //This will also act as a terminal Middleware Component
            app.Use(async (HttpContext context, RequestDelegate next) =>
            {
                await context.Response.WriteAsync("Getting Response from First Middleware");
                // Not calling 'next' since we want to terminate the pipeline here.
            });

            //Configuring Second Middleware Component using Run Extension Method
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("\nGetting Response from Second Middleware");
            });

            // Starts the web application which begins listening for incoming requests
            app.Run();
        }
    }
}
Differences Between Run, Map, and Use Extension Method in ASP.NET Core

In ASP.NET Core, Run, Map, and Use are extension methods used to configure the middleware pipeline. Each method serves a distinct purpose in controlling the flow of HTTP requests in the request processing pipeline. Understanding the differences between these extension methods is very important for effective pipeline management and middleware configuration.

Run Extension Method:
  • The Run extension method terminates the middleware pipeline. It does not accept a next parameter because it is intended to be the final point in the middleware chain.
  • When Run is called, no subsequent middleware is executed after it. This means that the response is generated, and the request lifecycle ends at this point.
  • Run is typically used at the end of the middleware pipeline to handle requests and generate responses directly without passing them to other middleware.
Map Extension Method:
  • The Map extension method branches the middleware pipeline based on a specific request path. It allows the middleware to run only when the incoming request matches a certain path.
  • It is useful for creating separate pipeline branches that can handle different URLs independently. This allows for handling specific routes or groups of routes within the same application. For example, you could use Map to handle requests for /admin separately from the rest of the application.
  • It is mostly used in Minimal APIs.
Use Extension Method:
  • The Use extension method is the most flexible, allowing us to pass requests to the next middleware in the pipeline.
  • It is commonly used to add middleware that performs actions before calling the next middleware component to process the request or to do additional processing after the next middleware has been completed.

Note: If you use the Map and Run middleware, you will see that the Map endpoint might not write the output to the Response stream.

Where Do We Use Middleware Components in the ASP.NET Core Application?

Middleware components are used in an ASP.NET Core application to handle cross-cutting concerns such as authentication, authorization, logging, error handling, routing, and other application-level services. Middleware components are configured in the HTTP request processing pipeline, and they determine how requests are handled and responses are returned. The following are some of the common built-in middleware components used in ASP.NET Core applications:

UseRouting: Configures the routing middleware, which is responsible for mapping incoming requests to the appropriate endpoint handlers based on route patterns defined in the application. It allows the application to determine which endpoint should handle the request and what the route parameters are.

UseAuthentication: This middleware adds to the ASP.NET Core pipeline and is responsible for validating the credentials provided in the request. It authenticates users and sets the user identity on the request context. This middleware is typically added after UseRouting but before UseAuthorization.

UseAuthorization: This adds the authorization middleware to the pipeline. It checks whether an authenticated user has the necessary permissions to access a given resource or endpoint. This middleware ensures that security policies are enforced by verifying whether a user is allowed to perform specific actions.

UseHttpsRedirection: Automatically redirects HTTP requests to HTTPS to ensure that all communication between the client and server is encrypted and secure. This is crucial for maintaining data integrity and confidentiality.

UseDeveloperExceptionPage: Provides a detailed error page in the browser during development, including stack traces, query parameters, cookies, and headers when an exception occurs. This middleware helps developers diagnose issues during the development phase.

UseExceptionHandler: Handles exceptions that occur during request processing by catching them and executing custom error-handling logic. It is used in production environments to manage exceptions, such as by redirecting users to a custom error page or returning a standard error response.

UseStaticFiles: This middleware enables serving static files like images, JavaScript, and CSS files directly from the web server to the client. It is essential for delivering static resources that do not change frequently, enhancing performance by allowing the server to serve these assets without processing them through the MVC or Web API pipeline.

The middleware component must be added in the correct sequence to ensure proper functionality in the application’s request pipeline. The middleware configuration enables ASP.NET Core applications to perform essential processing tasks, handle security, and provide a smooth user experience.

In the next article, I will discuss the ASP.NET Core Request Processing Pipeline with Examples. In this article, I explain How to use Middleware Components in the ASP.NET Core Application to handle the request processing pipeline with an example. I hope you enjoy this article on ASP.NET Core Middleware Components with Examples.

11 thoughts on “ASP.NET Core Middleware Components”

Leave a Reply

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