This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Write custom ASP.NET Core middleware

  • 5 contributors

By Fiyaz Hasan , Rick Anderson , and Steve Smith

Middleware is software that's assembled into an app pipeline to handle requests and responses. ASP.NET Core provides a rich set of built-in middleware components, but in some scenarios you might want to write a custom middleware.

This topic describes how to write convention-based middleware. For an approach that uses strong typing and per-request activation, see Factory-based middleware activation in ASP.NET Core .

Middleware class

Middleware is generally encapsulated in a class and exposed with an extension method. Consider the following inline middleware, which sets the culture for the current request from a query string:

The preceding highlighted inline middleware is used to demonstrate creating a middleware component by calling Microsoft.AspNetCore.Builder.UseExtensions.Use . The preceding Use extension method adds a middleware delegate defined in-line to the application's request pipeline.

There are two overloads available for the Use extension:

  • One takes a HttpContext and a Func<Task> . Invoke the Func<Task> without any parameters.
  • The other takes a HttpContext and a RequestDelegate . Invoke the RequestDelegate by passing the HttpContext .

Prefer using the later overload as it saves two internal per-request allocations that are required when using the other overload.

Test the middleware by passing in the culture. For example, request https://localhost:5001/?culture=es-es .

For ASP.NET Core's built-in localization support, see Globalization and localization in ASP.NET Core .

The following code moves the middleware delegate to a class:

The middleware class must include:

  • A public constructor with a parameter of type RequestDelegate .
  • Return a Task .
  • Accept a first parameter of type HttpContext .

Additional parameters for the constructor and Invoke / InvokeAsync are populated by dependency injection (DI) .

Typically, an extension method is created to expose the middleware through IApplicationBuilder :

The following code calls the middleware from Program.cs :

Middleware dependencies

Middleware should follow the Explicit Dependencies Principle by exposing its dependencies in its constructor. Middleware is constructed once per application lifetime .

Middleware components can resolve their dependencies from dependency injection (DI) through constructor parameters. UseMiddleware can also accept additional parameters directly.

Per-request middleware dependencies

Middleware is constructed at app startup and therefore has application life time. Scoped lifetime services used by middleware constructors aren't shared with other dependency-injected types during each request. To share a scoped service between middleware and other types, add these services to the InvokeAsync method's signature. The InvokeAsync method can accept additional parameters that are populated by DI:

Lifetime and registration options contains a complete sample of middleware with scoped lifetime services.

The following code is used to test the preceding middleware:

The IMessageWriter interface and implementation:

Additional resources

  • Sample code used in this article
  • UseExtensions source on GitHub
  • Lifetime and registration options contains a complete sample of middleware with scoped , transient , and singleton lifetime services.
  • DEEP DIVE: HOW IS THE ASP.NET CORE MIDDLEWARE PIPELINE BUILT
  • ASP.NET Core Middleware
  • Test ASP.NET Core middleware
  • Migrate HTTP handlers and modules to ASP.NET Core middleware
  • App startup in ASP.NET Core
  • Request Features in ASP.NET Core
  • Factory-based middleware activation in ASP.NET Core
  • Middleware activation with a third-party container in ASP.NET Core

By Rick Anderson and Steve Smith

Middleware is generally encapsulated in a class and exposed with an extension method. Consider the following middleware, which sets the culture for the current request from a query string:

The preceding sample code is used to demonstrate creating a middleware component. For ASP.NET Core's built-in localization support, see Globalization and localization in ASP.NET Core .

Test the middleware by passing in the culture. For example, request https://localhost:5001/?culture=no .

Middleware should follow the Explicit Dependencies Principle by exposing its dependencies in its constructor. Middleware is constructed once per application lifetime . See the Per-request middleware dependencies section if you need to share services with middleware within a request.

Because middleware is constructed at app startup, not per-request, scoped lifetime services used by middleware constructors aren't shared with other dependency-injected types during each request. If you must share a scoped service between your middleware and other types, add these services to the InvokeAsync method's signature. The InvokeAsync method can accept additional parameters that are populated by DI:

Middleware extension method

The following extension method exposes the middleware through IApplicationBuilder :

The following code calls the middleware from Startup.Configure :

ASP.NET Core

Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see: https://aka.ms/ContentUserFeedback .

Submit and view feedback for

Add Custom Middleware in ASP.NET Core Application

Here, you will learn how to create and add your own custom middleware into the request pipeline of ASP.NET Core application.

The custom middleware component is like any other .NET class with Invoke() method. However, in order to execute next middleware in a sequence, it should have RequestDelegate type parameter in the constructor.

Visual Studio includes template for creating standard middleware class. For this, right click on the project or folder where you want to create middleware class and select Add -> New Item. This will open Add New Item popup. Search for word "middleware" in the top right search box as shown below.

Logging Infrastructure .NET Core

Select Middleware Class item and give it a name and click on Add button. This will add a new class for the middleware with extension method as shown below.

As you can see above, the Invoke() method is not asynchronous. So, change it to asynchronous and write your custom logic before calling next();

Add Custom Middleware

Now, we need to add our custom middleware in the request pipeline by using Use extension method as shown below.

We can add middleware using app.UseMiddleware<MyMiddleware>() method of IApplicationBuilder also.

Thus, we can add custom middleware in the ASP.NET Core application.

.NET Tutorials

Database tutorials, javascript tutorials, programming tutorials.

Custom middleware in an ASP.NET Core application

In a previous article on Middleware in ASP.NET Core , we saw that Middleware is a software component that handles requests and responses in an application pipeline. It serves as a link between a server and a client application. The middleware is responsible for tasks like authentication, authorization, logging, error handling, routing, and so on.

A custom middleware is a software component designed to extend the functionality of a pipeline in an application. It is a piece of software that is inserted into the pipeline of the application to perform a specific task, such as authentication, logging, error handling, or routing, and it can be used to add custom functionality to the application.

Examples of a Custom Middleware implementation

Custom middleware in ASP.NET Core allows developers to execute code before or after the request-response cycle. It provides a flexible and extensible way for developers to add custom functionality to their applications. With custom middleware, developers can create a pipeline of processing for each request and response that can be tailored to meet the specific needs of their applications.

In Visual Studio, you can right click the project > Add New Item and choose a ‘Middleware class’ to add a middleware to your application.

Here is an example of a custom middleware implementation for authentication:

The code begins by declaring a class that is injected with the RequestDelegate delegate, which is used to handle incoming HTTP requests.  The RequestDelegate is a delegate that represents the next middleware component in the pipeline.  In other words, it is a reference to the next middleware component in the pipeline that executes after the current middleware component completes processing the request.

A middleware component is typically defined as a class that either implements the IMiddleware interface or utilizes a function that takes a HttpContext object and returns a Task. The HttpContext object carries important details about the current HTTP request being processed, such as request method, URL, headers, and body.

Middleware components utilize the HttpContext object to examine and adjust the incoming request or outgoing response as needed. Examples include adding a custom header to the response or performing authentication logic on the incoming request.

In the constructor of the middleware component, the _next field is initialized with the provided RequestDelegate. This permits the middleware component to invoke the next middleware component in the pipeline after completing request processing. The middleware component also has the option to bypass the pipeline by not calling the next middleware component, and instead respond to the request on its own.

The asynchronous InvokeAsync method is then declared. This is used to handle incoming requests. The first step in this method is to check the Authorization header of the request for a Bearer token. If the token is found, it is validated using the ValidateToken method. If the token is valid, the claims of the token are used to set the context.user to a ClaimsPrincipal. If the token is not valid, the status code of the response is set to Unauthorized. Finally, the _next RequestDelegate is invoked, which is responsible for processing the request.

The ValidateToken method is responsible for validating the token. This method must be implemented according to the authentication mechanism used.

The custom middleware can be added to the HTTP pipeline as follows:

Custom Middleware to add Logging

Another example of custom middleware could be to add logging to track request and response details, such as request time, URL, status code, etc. Here is an example:

The above code is a middleware class that logs requests. The middleware class takes in a RequestDelegate object as its argument and sets it as the next delegate to be invoked in the pipeline.

When the middleware is invoked, the start time of the request is logged and then the request is passed to the next delegate. Once the response is received from the next delegate, the end time is logged and the total time elapsed is calculated. Finally, a log message containing the request method, path, status code and total time elapsed is written to the console.

Combining Custom Middleware with other built-in Middleware

Additionally, custom middleware can be combined with other built-in middleware and third-party middleware to create a pipeline of processing for each request and response.

For example, you can use custom middleware for authentication, followed by built-in middleware for static file serving, followed by custom middleware for logging.

In this example, each middleware component will be executed in the order they are added to the pipeline. The CustomAuthMiddleware will be executed first, followed by the built-in UseStaticFiles middleware, and finally the RequestLoggingMiddleware. The result of each middleware’s execution will be passed on to the next middleware in the pipeline until the response is returned to the client.

Custom Middleware for Exception Handling and Caching

So far, we have seen how custom middleware in ASP.NET Core can be used to add custom functionality to the request-response pipeline. One of the most common uses of custom middleware is exception handling and Caching.

Here’s an example of how to add custom exception handling middleware:

Create a new class for your custom middleware, for example:

Use the UseMiddleware method to add the custom middleware to the request-response pipeline:

With this custom exception handling middleware in place, any exceptions that occur in your application will be caught and logged, and the response status code will be set to 500 Internal Server Error. This can be useful for handling unexpected errors and providing a consistent response to the client.

Another common use case for custom middleware is caching. Here’s an example of how to add custom caching middleware:

The above code is a middleware class that allows for caching of HTTP responses in an application. It uses a memory cache, that stores data in the RAM of the computer, rather than on a hard drive.

When invoked, the middleware first checks if a response has already been cached for the current request. If so, it sets the response body to the cached data and exits. If not, it continues by creating a MemoryStream object to store the response data. It then sets the response body to the MemoryStream object and calls the next piece of middleware in the pipeline.

After the response is generated, Responses will be cached in memory using the `IMemoryCache` service for 10 minutes. Finally, the response data is copied back to the original response body stream, allowing it to be sent back to the client. Subsequent requests for the same URL within the cache time window will receive the cached response, instead of making a new request to the server.

In conclusion, custom middleware in ASP.NET Core is a powerful tool for adding custom functionality to your application, such as exception handling, caching, and more. With custom middleware, you can create a flexible and extensible pipeline of processing for each request and response, tailored to meet the specific needs of your application.

This article was technically reviewed by Mahesh Sabnis

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET . This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too . Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

  • Please Share this article if you think it was worth reading. Thanks!

writing custom middleware in asp net core

Suprotim has received the prestigious Microsoft MVP award for Sixteen consecutive years. In a professional capacity, he is the CEO of A2Z Knowledge Visuals Pvt Ltd, a digital group that offers Digital Marketing and Branding services to businesses, both in a start-up and enterprise environment.

Get in touch with him on Twitter @ suprotimagarwal or at LinkedIn

  • Click here to post your Comments

.NET Framework, Visual Studio and C#

Patterns & practices, cloud and mobile, .net desktop, interview questions & product reviews, join our community, popular articles, jquery cookbook.

jQuery CookBook

  • United States
  • United Kingdom

Joydip Kanjilal

By Joydip Kanjilal , Contributor, InfoWorld |

How to build custom middleware in ASP.NET Core

Take advantage of asp.net core middleware to customize your application’s handling of http requests and responses..

How to build custom middleware in ASP.NET Core

ASP.NET Core is an open source, cross-platform, lean, and modular framework for building high-performance web applications. It is also extensible. When building an ASP.NET Core application, you can draw on various middleware components to customize the handling of requests and responses, and even inspect, route, or modify the request and response messages that flow through the pipeline. This article presents a discussion of ASP.NET Core middleware and how it can be used, with relevant code examples in C#.

Usually, you have a chain of middleware components in the application pipeline in ASP.NET Core. The ASP.NET Core request pipeline contains a series of request delegates that are invoked one after the other. Incoming requests flow through each of the middleware components in the pipeline, and each of these components can either process the request or pass the request to the next component in the pipeline.

Configuring the ASP.NET Core middleware pipeline

The middleware pipeline is configured using the Configure method in the Startup.cs file. This is exactly where you can chain together your ASP.NET Core pipeline. The Configure method is automatically called by the ASP.NET runtime. Here is a quick look at this method.

The above code snippet illustrates how you can add MVC to the ASP.NET Core request execution pipeline. In the next section, we will build a custom middleware component for ASP.NET Core.

Create an ASP.NET Core project in Visual Studio

Assuming that you have .NET Core installed in your system (preferably .NET Core 2), you can follow these steps to create a new ASP.NET Core project in Visual Studio 2017 or Visual Studio 2015.

  • Open Visual Studio
  • Click File -> New -> Project
  • In the New Project dialog window, select the ASP.NET Core Web Application project template
  • Specify the name and location for your project and click OK to save
  • In the next screen, select Web API from the list of templates, unselect authentication and Docker support (we don’t need either of these for now), and save the project

And that’s all you need to do to create an ASP.NET Core web application that leverages Web API. We will now build a custom middleware component that checks if the authentication key passed in the request is valid. If the authentication key is not valid, the request will be rejected with an appropriate message.

Create a custom ASP.NET Core middleware component

You have an extension method in IApplicationBuilder that you can take advantage of to build your own middleware in ASP.NET Core. Note that it is always a good practice to write your middleware component in a separate class or a separate project so that you can update the middleware if need be, without having to change your service layer.

There are various ways to build a custom middleware component—I will demonstrate the simplest way. Right-click on the project in the Solution Explorer window and create a new .cs file named MyCustomMiddleware. At first glance, this class will look like this.

Note that your custom middleware should have a constructor with a parameter of type RequestDelegate . A RequestDelegate is a just another delegate that accepts an HttpContext and returns a Task . Here is how the modified version of our custom middleware should look.

Invoke your custom ASP.NET Core middleware

Your middleware should also have a method that will be called when the middleware is executed. This is the Invoke method as shown in the code listing below. Note that this method has been named Invoke in this example only by convention. It is here that you can write your code to inspect or modify the requests and responses.

Refer to the code listing given above. If the request header does not contain a valid authentication key, then an appropriate message will be returned as a response when you run your Web API. (Note that ”Authentication-Key” is a string that would be compared against a list of valid keys.)

How to Create a Custom ASP.NET Core Middleware

How to Create a Custom ASP.NET Core Middleware image

Understanding Middleware

Middleware components handle requests in sequence. The order of middleware in the pipeline defines the order for the request and the reverse order for the response. Middleware can handle the request and produce a response, or pass the request to the next middleware in the sequence.

Creating Custom Middleware

Before we dive into creating a custom middleware, you need to set up an ASP.NET Core project. If you don't have one already, you can create it using the following shell command:

Step 1: Create a Middleware Class

Create a new class that will represent your middleware. You can name it anything you want, but for this tutorial, we'll name it "CustomMiddleware".

The constructor of the middleware class takes a parameter of type RequestDelegate . This delegate represents the next middleware in the pipeline.

The InvokeAsync method is where the middleware does its job. It adds custom logic to the HTTP request process.

Step 2: Registering the Middleware

After creating the middleware class, it needs to be registered in the application's request processing pipeline. This is done in the Configure method of the Startup class.

Now the custom middleware is part of the pipeline and will be invoked for every incoming HTTP request.

And that's it! You've learned how to create and use custom middleware in an ASP.NET Core application. This is a powerful feature that can greatly enhance your flexibility when handling HTTP requests. If you need to hire .NET remote developers , consider checking our website.

If you're interested in enhancing this article or becoming a contributing author, we'd love to hear from you.

Please contact Sasha at [email protected] to discuss the opportunity further or to inquire about adding a direct link to your resource. We welcome your collaboration and contributions!

Middleware is a layer of software that connects two or more applications or systems, allowing them to exchange data, manage requests, and enhance functionality. Middleware acts as a bridge between different software components, simplifying communication and enabling developers to focus on the specific features of their application. Middleware can be used for various purposes, such as authentication, logging, caching, and more.

Learn more about Middleware .

RequestDelegate

Custom middleware.

Hire Top Remote Software Developers with Expertise in Databases, .Net and MS EF

Unlock the Power of Remote .NET Developers with Expertise in Databases and Ext.js

Efficiently Scale Your Engineering Team with Expert Remote .Net and Database Developers Skilled in MS SQL Server

secure.food

Creating Custom Middleware In ASP.Net Core

Middleware is the new “pipeline” for requests in asp.net core. Each piece of middleware can process part or all of the request, and then either choose to return the result or pass on down to the next piece of middleware. In the full ASP.net Framework you were able to specify “HTTP Modules” that acted somewhat like a pipeline, but it was hard to really see how the pieces fit together at times.

Anywhere you would normally write an HTTP Module in the full ASP.net Framework is where you should probably now be using middleware. Infact for most places you would normally use MVC filters, you will likely find it easier or more convenient to use middleware.

This diagram from Microsoft does a better job than I could at seeing how pipelines work. Do notice however that you can do work both before and after the pass down to the next middleware. This is important if you wish to affect results as they are going out rather than results that are coming in.

writing custom middleware in asp net core

Table of Contents

Basic Configuration

The easiest way to get started with middleware is in the Configure method of your startup.cs file. In here is where you “chain” your pipeline together. It may end up looking something like the following :

Now an important thing to remember is that ordering is important. In this pipeline the static files middleware runs first, this middleware can choose to pass on the request (e.g. not process the response in its entirety) or it can choose to push a response to the client and not call the next middleware in the chain. That last part is important because it will often trip you up if your ordering is not correct (e.g. if you want to authenticate/authorize someone before hitting your MVC action).

App.Use is going to be the most common pipeline building block you will come across. It allows you to add on something to the response and then pass to the next middleware in the pipeline, or you can force a short circuit and force a return result without passing to the next handler.

To illustrate, consider the following

In this example, the pipeline adds a response header of X-Content-Type-Options and then passes it to the next handler. The next handler adds a response text of “Hello World!” then the pipeline ends. In this example because we are not calling Next() we actually don’t pass to the next handler at all and execution finishes. In this way we can short circuit the pipeline if something hasn’t met criteria. For example if some authorization key is not present.

You may see App.Run appear around the place, it’s like App.Use’s little brother. App.Run is an “end of the line” middleware. It can handle generating a response, but it doesn’t have the ability to pass it down the chain. For this reason you will see App.Run middleware at the end of the pipeline and no where else.

App.Map is used when you want to build a mini pipeline only for a certain URL. Note that the URL given is used as a “starts with”. So commonly you might see this in middleware for locking down an admin area. The usage is pretty simple :

So in this example when someone goes to /helloworld, they will be given the Hello World! message back.

App.MapWhen

This is similar to Map, but allows for much more complex conditionals. This is great if you are checking for a cookie or a particular query string, or need more powerful Regex matching on URLs. In the example below, we are checking for a query string of “helloworld”, and if it’s found we return the response of Hello World!

Building A Middleware Class

And after all that we going to toss it in the bin and create a middleware class! Middleware classes use quite a different syntax to all of the above, and really it just groups them all together in a simple pattern.

Let’s say I want to build a class that will add common security headers to my site . If I right click inside my .net core web project and select “Add Item”, there is actually an option to add a middleware class template.

writing custom middleware in asp net core

If you can’t find this, don’t fear because there is absolutely nothing about using the template. It just provides the basic structure of how your class should look, but you can copy and paste it from here into a plain old .cs file and it will work fine. Our security middleware looks something like the following :

Very simple. In our invoke method we do all the work we want to do and pass it onto the next handler. Again, we can short circuit this process by returning an empty Task instead of calling next.

Another thing to note is that this is instantiated using the service container. That means if you have a need to access a database or call in settings from an external source, you can simply add the dependency in the constructor.

Important : App middleware is constructed at startup. If you require scoped dependencies or anything other than singletons, do not inject your dependencies into the constructor. Instead you can add dependencies into the Invoke method and .net core will work it out. Again, if you need scoped dependencies add these to your Invoke method not your constructor.

The Extensions part is optional, but it does allow you to write code like this :

Related posts:

  • Custom Error Pages In ASP.net Core
  • Getting Started With NancyFX In ASP.net Core
  • CSRF Tokens In AngularJS/jQuery With ASP.NET Core
  • Implementing A Leaky Bucket Client In .NET Core

2 thoughts on “Creating Custom Middleware In ASP.Net Core”

Very helpful, thank you. I noticed some typos.

1. e.g. if you with to authenticate/authorize That should say “if you want to authenticate/authorize”

2. do not inject your dependencies into the instructure. Instead the you can add dependencies This should say “do not inject your dependencies into the constructor. Instead you can add dependencies”

🙂 Thanks. Fixed!

Leave a Comment Cancel reply

Save my name, email, and website in this browser for the next time I comment.

Study through a pre-planned curriculum designed to help you fast-track your DotNet career and learn from the world’s best collection of DotNet Resources.

Find us on social media:

As Featured On

writing custom middleware in asp net core

Contact: [email protected]  | Phone Number: (973) 916-2695 | Address: 288 Rosa Parks Blvd, Paterson, New Jersey 07501, USA

Disclaimer: Efforts are made to maintain reliable data on all information presented. However, this information is provided without warranty. Users should always check the offer provider’s official website for current terms and details. Our site receives compensation from many of the offers listed on the site. Along with key review factors, this compensation may impact how and where products appear across the site (including, for example, the order in which they appear). Our site does not include the entire universe of available offers. Editorial opinions expressed on the site are strictly our own and are not provided, endorsed, or approved by advertisers.

2022 © DotNetCoreTutorials All rights reserved.

3 Ways To Create Middleware In ASP.NET Core

3 Ways To Create Middleware In ASP.NET Core

READ TIME - 3 MINUTES

In this newsletter, we'll be covering three ways to create middleware in ASP.NET Core applications.

Middleware allows us to introduce additional logic before or after executing an HTTP request.

You are already using many of the built-in middleware available in the framework.

I'm going to show you three approaches to how you can define custom middleware:

  • With Request Delegates
  • By Convention
  • Factory-Based

Let's go over each of them and see how we can implement them in code.

Adding Middleware With Request Delegates

The first approach to defining a middleware is by writing a Request Delegate .

You can do that by calling the Use method on the WebApplication instance and providing a lambda method with two arguments. The first argument is the HttpContext and the second argument is the actual next request delegate in the pipeline RequestDelegate .

Here's what this would look like:

By awaiting the next delegate, you are continuing the request pipeline execution. You can short-circuit the pipeline by not invoking the next delegate.

This overload of the Use method is the one suggested by Microsoft .

Adding Middleware By Convention

The second approach requires us to create a class that will represent our middleware. We have to follow the convention when creating this class so that we can use it as middleware in our application.

I'm first going to show you what this class looks like, and then explain what is the convention we are following here.

Here's how this class would look like:

The convention we are following has a few rules:

  • We need to inject a RequestDelegate in the constructor
  • We need to define an InvokeAsync method with an HttpContext argument
  • We need to invoke the RequestDelegate and pass it the HttpContext instance

There's one more thing that's required, and that is to tell our application to use this middleware.

We can do that by calling the UseMiddleware method:

And with this, we have a functioning middleware.

Adding Factory-Based Middleware

The third and last approach requires us to also create a class that will represent our middleware.

However, this time we're going to implement the IMiddleware interface. This interface has only one method - InvokeAsync .

Here's what this class would like:

The FactoryMiddleware class will be resolved at runtime from dependency injection.

Because of this, we need to register it as a service:

And like the previous example, we need to tell our application to use our factory-based middleware:

With this, we have a functioning middleware.

A Word On Strong Typing

I'm a big fan of strong typing whenever possible. Out of the three approaches I just showed you, the one using the IMiddleware interface satisfies this constraint the most. This is also my preferred way to implement middleware .

Since we're implementing an interface, it's very easy to create a generic solution to never forget to register your middleware.

You can use reflection to scan for classes implementing the IMiddleware interface and add them to dependency injection, and also add them to the application by calling UseMiddleware .

Whenever you're ready, there are 3 ways I can help you:

  • Pragmatic Clean Architecture: This comprehensive course will teach you the system I use to ship production-ready applications using Clean Architecture. Learn how to apply the best practices of modern software architecture. Join 2,400+ students here.
  • Patreon Community: Join a community of 1,050+ engineers and gain access to the source code I use in my YouTube videos, early access to future videos, and exclusive discounts for my courses. Join 1,050+ engineers here.
  • Promote yourself to 41,000+ subscribers by sponsoring this newsletter.

Become a Better .NET Software Engineer

Join 41,000+ engineers who are improving their skills every Saturday morning.

Subscribe to the Newsletter

Join 41,000+ readers of The .NET Weekly for practical tips and resources to improve your .NET and software architecture skills.

Share This Article On:

DZone

  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
  • Manage My Drafts

DZone Research Report : A look at our developer audience, their tech stacks, and topics and tools they're exploring.

Getting Started With Large Language Models : A guide for both novices and seasoned practitioners to unlock the power of language models.

Managing API integrations : Assess your use case and needs — plus learn patterns for the design, build, and maintenance of your integrations.

  • Identifying, Exploiting, and Preventing Host Header Attacks on Web Servers
  • Modern Web Applications Authentication Using Face Recognition
  • Streamlining Your Workflow With the Jenkins HTTP Request Plugin: A Guide to Replacing CURL in Scripts
  • A Deep Dive Into Distributed Tracing
  • Prompt Engineering Tutorial for AI/ML Engineers
  • Implementing CI/CD Pipelines With Jenkins and Docker
  • How To Integrate NCache With JPA Hibernate for Caching in Spring Boot Applications
  • Top Visual Regression Testing Tools
  • Software Design and Architecture
  • Cloud Architecture

An Absolute Beginner's Tutorial on Middleware in ASP.NET Core/MVC

Let's see how middleware plays an important part in the request-response pipeline and how we can write and plug in our custom middleware..

Rahul Rajat Singh user avatar

Join the DZone community and get the full member experience.

writing custom middleware in asp net core

in this article, we will try to understand the concept of middleware in asp.net core. we will see how middleware plays an important part in the request-response pipeline and how we can write and plug-in our custom middleware.

before we can get into the what middleware is and the value it brings, we need to understand how the request-response works in a classic asp.net model. in earlier days, the request and response objects in asp.net were very big and had a very tight coupling with iis. this was a problem because some of the values in these objects are filled by the iis request-response pipeline, and unit testing such bloated objects was a very big challenge.

so, the first problem that needed to be solved was to decouple the applications from web servers. this was very nicely defined by a community-owned standard called open web interface for .net (owin) since the older asp.net applications were dependent on system. web dll, which internally had a very tight coupling with iis, it was very difficult to decouple the applications from web servers. to circumvent this problem, owin defines to remove the dependency of web applications on system.web assembly so that the coupling with a web server (iis) gets removed.

owin primarily defines the following actors in its specifications:

  •  server  — the http server directly communicates with the client and then uses owin semantics to process requests. servers may require an adapter layer that converts to owin semantics.
  •  web framework  — a self-contained component on top of owin exposing its own object model or api that applications may use to facilitate request processing. web frameworks may require an adapter layer that converts from owin semantics.
  •  web application  — a specific application, possibly built on top of a web framework, which is run using owin compatible servers.
  •  middleware  — pass-through components that form a pipeline between a server and application to inspect, route, or modify request and response messages for a specific purpose.
  •  host  — the process an application and server execute inside of, primarily responsible for application startup. some servers are also hosts.

since owin is just a standard, there have been multiple implementations for this in last few years starting from katana to the present day implementation in asp.net core. we will now focus on how the middleware implementation looks like in asp.net core.

before that, let's try to understand what a middleware is. for the developer coming from the asp.net world, the concept of  httpmodule  and  httphander  is fairly familiar. these are used to intercept the request-response pipeline and implement our custom logic by writing custom modules or handlers. in the owin world, the same thing is achieved by the middleware.

owin specifies that the request coming from web server to the web application has to pass through multiple components in a pipeline sort of fashion where each component can inspect, redirect, modify, or provide a response for this incoming request. the response will then get passed back to the web server in the opposite order back to the web server, which can then be served back to the user. the following image visualizes this concept:

writing custom middleware in asp net core

if we look at the above diagram, we can see that the request passes through a chain of middleware and then some middleware decides to provide a response for the request and then the response travels back to the web server passing through all the same middleware it passed through while request. so a middleware typically can:

  • process the request and generate the response.
  • monitor the request and let it pass through to next middleware in line.
  • monitor the request, modify it and then let it pass through to next middleware in line.

if we try to find the middleware with actual use cases defined above:

  • process the request and generate the response: mvc itself is a middleware that typically gets configured in the very end of the middleware pipeline
  • monitor the request and let it pass through to next middleware in line: logging middleware which simply logs the request and response details
  • monitor the request, modify it, and then let it pass through to next middleware in line: routing and authentication module where we monitor the request decide which controller to call (routing) and perhaps update the identity and principle for authorization (auth-auth).

using the code

in this article, we will create 2 owin middleware. first one to demonstrate the scenario where we are not altering the request. for this, we will simply log the request and response time in the log —  timingmiddleware  . the second one to check the incoming response, find a specific header value to determine which tenant is calling the code and then returning back if the tenant is not valid —  mytenantvalidator  .

 note  : before we get started with the sample implementation, its good to highlight the point that middleware is an implementation of pipes and filter patterns. pipes and filter patterns say that if we need to perform a complex processing that involves a series of separate activities, it's better to separate out each activity as a separate task that can be reused. this gives us benefits in terms of reusability, performance, and scalability.

let's start by looking at how the middleware class definition should look. there are two ways to define our custom middleware:

custom middleware class

Inline custom middleware.

the first way is to have a custom class containing our middleware logic.

what this class does is gets called once the request reached to this middleware. the  invokeasync  function will get called and the current  httpcontext  will be passed to it. we can then execute our custom logic using this context and then call the next middleware in the pipeline. once the request is processed by all middleware after this middleware, the response is generated and the response will follow the reverse chain and the function will reach after our _next call where we can put the logic that we want to execute before the response goes back to the previous middleware.

for our middleware to get into the pipeline, we need to use the  configure  method in our  startup  class to hook our middleware.

the above code shows how we have hooked in our custom middleware as the first middleware in the pipeline. the middleware will be called in the same order that they are hooked in this method. so in the above code, our middleware will be called first and the mvc middleware will be the last one to get called.

the inline custom middleware is directly defined in the  configure  method. the following code shows how to achieve this:

the end result will be the same for both approaches. so if our middleware is doing some trivial things that do not impact the readability of code if we put as inline, we could create the inline custom middleware. if the code that we want to significant code and logic in our middleware, we should use the custom middleware class to define our middleware.

coming back to the middleware that we are going to implement, we will use the inline approach to define the  timingmiddleware  and the custom class approach to define the  mytenantvalidator  .

implementing the timingmiddleware

the sole purpose of this middleware is to inspect the request and response and log the time that this current request took to process. let's define it as inline middleware. the following code shows how this can be done.

we have hooked this middleware just before mvc middleware so that we can measure the time our request processing is taking. it is defined after  usestaticfiles  middleware so that this middleware will not get invoked for all static files that are being served from our application.

implementing the mytenantvalidator

now let's implement a middleware that will take care of tenant verification. it will check for the incoming header and if the tenant is not valid, it will stop the request processing.

 note  : for the sake of simplicity, i will be looking for a hard-coded tenant id value. but in real-world applications, this approach should never be used this is being done only for demonstration purposes. for not, we will be using the tenant id value as 12345678.

this middleware will be written in its separate class. the logic is simple; check for the headers in the incoming request. if the header matches the hard coded tenant id, let the request proceed to the next middleware else terminate the request by sending a response from this middleware itself. let's look at the code of this middleware.

now let's register this middleware in our  startup  class.

with this code in place, if we try to run the application, we can see the response as an error.

writing custom middleware in asp net core

to circumvent this issue, we need to pass the tenant id in the header.

writing custom middleware in asp net core

with this change, when we access the application again, we should be able to browse our application.

writing custom middleware in asp net core

 note  : even though we were talking in the context of asp.net core, the concept of middleware is same in all mvc implementations that are adhering to owin standards.

point of interest

in this article, we talked about asp.net core middleware. we looked at what middleware is and how we can write our own custom middleware. this article has been written from a beginner's perspective. i hope this has been somewhat informative.

  •  owin: open web server interface for .net 
  •  asp.net core middleware 
  •  pipes and filters pattern 

download the sample code for the article here:  owintest 

Published at DZone with permission of Rahul Rajat Singh , DZone MVB . See the original article here.

Opinions expressed by DZone contributors are their own.

Partner Resources

  • About DZone
  • Send feedback
  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone
  • Terms of Service
  • Privacy Policy
  • 3343 Perimeter Hill Drive
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

Exception Not Found

Writing Custom Middleware in ASP.NET Core 1.0

Buy Me a Coffee!

One of the new features from ASP.NET Core 1.0 is the idea of Middleware . Middleware are components of an application that examine the requests responses coming in to and going out from an ASP.NET Core application. It's a long-overdue piece of customization for ASP.NET apps that gives us developers total control over the HTTP pipeline. It might even help you avoid endless questions from annoying coworkers (maybe!).

As part of my ongoing learning process about ASP.NET Core, I decided to build a sample application that has a few pieces of middleware, so that I could play around with order, tasks, and so forth. It helped me understand what Middleware does, and why it might be important, so hopefully it'll help you too. Let's get started!

NOTE: This post was written using RC1 (Release Candidate 1) of ASP.NET Core, and as the framework gets closer to final release, some things may change. If they do, I'll do my best to keep this post up-to-date. If you notice anything that needs to be updated, let me know in the comments.

What Is Middleware?

Middleware, as explained above, are components that "sit" on the HTTP pipeline and examine requests and responses. This means that they are effectively "gateway" classes that can decide whether or not to continue allowing the request to be processed by other Middleware components further down the stream. The pipeline looks like this:

writing custom middleware in asp net core

The idea of Middleware, at least in ASP.NET, comes from the Open Web Interface for .NET (OWIN) project. OWIN's stated goal is to

...decouple server and application, encourage the development of simple modules for .NET web development, and, by being an open standard, stimulate the open source ecosystem of .NET web development tools.

Considering their ideas have been fully integrated into ASP.NET Core 1.0, I'd say they've more than achieved this goal.

At any rate, Middleware defines a system by which we can exert complete control over the HTTP pipeline into and out of our apps. It effectively replaces the functionality that was formerly covered by things like HttpModules and HttpHandlers .

Default Middleware

In some default ASP.NET Core 1.0 apps, particularly the ones created by Visual Studio, you are already using Middleware. Here's a sample from my earlier post covering the Startup.cs file in ASP.NET Core 1.0 :

In this method, any time you see app.UseX() , you are using some of ASP.NET's default Middleware components. The concept of Middleware and the HTTP pipeline is central to how ASP.NET Core apps are developed. You can check out the other built-in Middleware by reading the docs .

Defining a Custom Middleware Component

A Middleware component, in an ASP.NET Core project, is a class like any other. The difference is that the Middleware component needs to have a private property of type RequestDelegate, like so:

The _next property represents a delegate for the next component in the pipeline. Each component must also implement an async task called Invoke:

At the moment, this method does nothing other than call the next Middleware component in the pipeline. Let's see a simple task that we can do with our new Middleware component.

Middleware Tasks

Since each piece of Middleware can examine the incoming request and the corresponding response, one possible task Middleware could accomplish is that of authorization.

For a (trivial) example, let's say that each request must NOT have a header "X-Not-Authorized", and if it does, the response must be returned immediately with a 401 Unauthorized status code. Our Middleware component's Invoke method would now look like this:

If we call any method in our app with a tool such as Postman , we'll get the following response:

writing custom middleware in asp net core

Middleware can accomplish many sorts of things. For example:

  • You might want to examine each incoming request to see if they have requested an image, and if they have, redirect them to an image handler, much like you would when we used HttpHandlers.
  • You might have a component that logs all requests.
  • You might have a component that checks to see if you annoying coworker Doug from down the hall is making a request, and if he is, redirect all his requests to Mary just so you don't have to deal with him anymore.

The possibilities are endless!

Other Example Middleware

For our sample project, we've already got one Middleware component (AuthorizationMiddleware) defined. Now we will define two more. First up is RequestHeaderMiddleware:

This Middleware component does two things:

  • If the request contains a header called "X-Cancel-Request" then the server returns 500 Internal Server Error as the response.
  • If the request contains a header called "X-Transfer-By" then the server adds a header to the response called "X-Transfer-Success".

Finally, let's add a third piece of middleware, called ProcessingTimeMiddleware:

This component starts an instance of Stopwatch to record how long each request takes, then returns a header called "X-Processing-Time-Milliseconds" with that time in the response.

Now that we've got all the Middleware components we're going to use, let's see how we can insert them into our ASP.NET Core 1.0 app's pipeline!

Adding Middleware to the HTTP Pipeline

The environment for an ASP.NET Core 1.0 is set up in that app's Startup.cs file . In order to use our newly-created Middleware, we need to register them with the environment created by Startup.

There are two ways we can register the Middleware in the pipeline. One way is to go to the Startup file's Configure method and call a method on the IApplicationBuilder interface (simplified):

Another way, and the way we're going to use, is to create extension methods for each piece of Middleware you want to register, and then call those methods from the Configure() method. Here's our Extensions class:

Now we can call these extensions in Startup like so ( the below code contains a bug, read it carefully ):

Did you spot it?

When you are registering Middleware with your environment, the order in which you add the Middleware components is very important . In the above code, we add ProcessingTimeMiddleware first, then RequestHeaderMiddleware, then AuthorizationMiddleware. This is the exact opposite order of what we should be using. The correct order looks like this (simplified):

Testing With Postman

Now that we've got our Middleware components in place, let's see some example request/response calls to a controller action in our app. The controller action we're using is very simple:

NOTE: Don't forget that, in ASP.NET Core 1.0 and MVC 6, MVC and Web API use the same stack .

Now let's make some Postman calls. First, let's make a call with no headers at all.

A Postman response, showing the status code 200 OK and including the "X-Processing-Time-Milliseconds" response header

This is what we would expect to see. Neither the Authorization nor the RequestHeader Middleware components prevents execution, so the ProcessingTime component added the header and we got back the Action's 200 OK response.

Now let's see what happens if we add in the X-Not-Authorized header:

A Postman response, showing the status code 401 Unauthorized and missing the "X-Processing-Time-Milliseconds" response header

Great! The AuthorizationMiddleware component returned 401 Unauthorized, and because there's no "X-Processing-Time-Milliseconds" header isn't included in the response, the ProcessingTimeMiddleware component didn't fire. This is what we expect.

I'm sure you see where this is going by now. For the last test, let's see a request without "X-Not-Authorized" header but including "X-Transfer-By":

A Postman response, showing status code 200 OK and including "X-Transfer-Success" response header.

In this case, we see that both "X-Processing-Time-Milliseconds" and "X-Transfer-Success" returned, which means that both RequestHeaderMiddleware and ProcessingTimeMiddleware successfully fired. Looks like our scenarios work!

Let's try one more request.

A Postman response, showing a request header "X-Asker" with a value of "Doug" and a response header "X-Question-Response" with value "Go ask Mary!"

Remember these three major points about Middleware in ASP.NET Core 1.0:

  • Middleware components allow you complete control over the HTTP pipeline in your app.
  • Among other things, Middleware components can handle authorization, redirects, headers, and even cancel execution of the request.
  • The order in which Middleware components are registered in the Startup file is very important .

You can see the sample code for this project in the GitHub repository . As always, let me know what you think about this post in the comments, particularly if I missed something important.

Happy Coding!

Re-thinking the Visitor Pattern with the Double-Dispatch Approach

Re-thinking the Visitor Pattern with the Double-Dispatch Approach

Middleware in ASP.NET 6 - Conditionally Adding Middleware to the Pipeline

Middleware in ASP.NET 6 - Conditionally Adding Middleware to the Pipeline

The Catch Block #99 - Finishing the Dapper Where Clause Builder

The Catch Block #99 - Finishing the Dapper Where Clause Builder

May we suggest a tag?

May we suggest an author.

Matthew Jones

Matthew Jones

Vladimir Vozar

Vladimir Vozar

Cesar Aguirre

Cesar Aguirre

Ram Hemasri

Ram Hemasri

Joe Middour

Joe Middour

Maverick Jones

Maverick Jones

Huy Luong

Code Maze

  • Blazor WASM 🔥
  • ASP.NET Core Series
  • GraphQL ASP.NET Core
  • ASP.NET Core MVC Series
  • Testing ASP.NET Core Applications
  • EF Core Series
  • HttpClient with ASP.NET Core
  • Azure with ASP.NET Core
  • ASP.NET Core Identity Series
  • IdentityServer4, OAuth, OIDC Series
  • Angular with ASP.NET Core Identity
  • Blazor WebAssembly
  • .NET Collections
  • SOLID Principles in C#
  • ASP.NET Core Web API Best Practices
  • Top REST API Best Practices
  • Angular Development Best Practices
  • 10 Things You Should Avoid in Your ASP.NET Core Controllers
  • C# Back to Basics
  • C# Intermediate
  • Design Patterns in C#
  • Sorting Algorithms in C#
  • Docker Series
  • Angular Series
  • Angular Material Series
  • HTTP Series
  • .NET/C# Author
  • .NET/C# Editor
  • Our Editors
  • Leave Us a Review
  • Code Maze Reviews

Select Page

ASP.NET Core Middleware – Creating Flexible Application Flows

Posted by Marinko Spasojević | Updated Date Dec 22, 2021 | 8

ASP.NET Core Middleware – Creating Flexible Application Flows

ASP.NET Core Middleware is software integrated inside the application’s pipeline that we can use to handle requests and responses. When we talk about the ASP.NET Core middleware, we can think of it as a code section that executes with every request. In this article, we are going to learn more about the ASP.NET Core middleware and how to use different methods (Run, Map, Use) during the configuration. Additionally, we are going to explain the process of creating custom middleware.

Let’s get started.

More About the ASP.NET Core Middleware and Pipeline

Usually, we have more than a single middleware component in our application. Each component can:

  • Pass the request to the next middleware component in the pipeline and also
  • It can execute some work before and after the next component in the pipeline

To build a pipeline, we are using request delegates, which handle each HTTP request. To configure request delegates, we use the Run , Map , and Use extension methods. In this article, we are going to see that we can configure request delegate as an anonymous method, or as a separate reusable class. Whether we use anonymous methods or separate classes, we are creating middleware components.

Inside the request pipeline, an application executes each component in the same order they are placed in the code – top to bottom:

Become a patron at Patreon!

Additionally, we can see that each component can execute custom logic before using the next delegate to pass the execution to another component. The last middleware component doesn’t call the next delegate, which means that this component is short-circuiting the pipeline. This is a terminal middleware because it stops further middleware from processing the request. Basically, it executes the additional logic and then returns the execution to the previous middleware components.

Middleware Order in ASP.NET Core

Before we start with examples, it is quite important to know about the order in which we should register our middleware components. The order is important for the security, performance, and functionality of our applications:

Middleware Order of Configuration

As we can see, we should register the exception handler in the early stage of the pipeline flow so it could catch all the exceptions that can happen in the later stages of the pipeline. When we create a new ASP.NET Core app, many of the middleware components are already registered in the order from the diagram. We have to pay attention to register additional existing components or the custom ones to fit this recommendation.

For example, when adding CORS to the pipeline, the app in the development environment will work just fine if you don’t add it in this order. But we have received several questions from our readers stating that they face the CORS problem once they deploy the app. But once we suggest moving the CORS registration to the required place, the problem disappears.

We can visualize this diagram in the code as well:

As you can see, we are using the Configure method in the Startup class to add components to the pipeline.

Creating a First Middleware Component in ASP.NET Core

Let’s start by creating a new ASP.NET Core Web API application.

In the launchSettings.json file, we are going to add some changes regarding the launch profiles:

Now, inside the Configure method, we are going to use an anonymous method to create a first middleware component:

We use the Run method, which adds a terminal component to the app pipeline. We can see we are not using the next delegate because the Run method is always terminal and terminates the pipeline. This method accepts a single parameter of the RequestDelegate type. If we inspect this delegate we are going to see that it accepts a single HttpContext parameter:

So, we are using that context parameter to modify our requests and responses inside the middleware component. In this specific example, we are modifying the response by using the WriteAsync method. For this method, we need the Microsoft.AspNetCore.Http namespace.

Let’s start the app and inspect the result:

Using Run method to configure middleware in the pipeline

There we go.

Working with the Use Method

To chain multiple request delegates in our code, we can use the Use method. This method accepts a Func delegate as a parameter and returns a Task as a result:

So, this means when we use it, we can make use of two parameters, context and next :

As you can see, we add several logging messages to be sure what the order of executions inside middleware components is. First, we write to a console window, then we invoke the next delegate passing the execution to another component in the pipeline. In the Run method, we write a second message to the console window and write a response to the client. After that, the execution is returned to the Use method and we write the third message (the one below the next delegate invocation) to the console window.

The Run method doesn’t accept the next delegate as a parameter, so without it to send the execution to another component, this component short-circuits the request pipeline.

Now, let’s start the app and inspect the result, which proves our execution order:

Using the Use method in the pipeline

Important Note

We shouldn’t call the next.Invoke after we send the response to the client. This can cause exceptions if we try to set the status code or modify the headers of the response.

For example:

Here we write a response to the client and then call next.Invoke . Of course, this passes the execution to the next component in the pipeline. There, we try to set the status code of the response and write another one. But let’s inspect the result:

Error while setting the status code of the response after the response is sent to the client in the ASP.NET Core Middleware

We can see the error message, which is pretty self-explanatory. 

Using the Map and MapWhen Methods for Branching

To branch the middleware pipeline, we can use both Map and MapWhen methods. 

The Map method is an extension method that accepts a path string as one of the parameters:

When we provide the pathMatch string, the Map method will compare it to the start of the request path. If they match, the app will execute the branch.

So, let’s see how we can use this method by modifying the Configure method:

By using the Map method, we provide the path match, and then in the delegate, we use our well-known Use and Run methods to execute middleware components.

Now, if we start the app and navigate to /usingmapbranch , we are going to see the response in the browser:

Using Map to branch middleware pipeline

But also, if we inspect console logs, we are going to see our new messages:

Console logs for the map branch

Here, we can see the messages from the Use method before the branch, and the messages from the Use and Run methods inside the Map branch. We are not seeing any message from the Run method outside the branch. It is important to know that any middleware component that we add after the Map method in the pipeline won’t be executed. This is true even if we don’t use the Run middleware inside the branch.

Using the MapWhen Method

If we inspect the MapWhen method, we are going to see that it accepts two parameters:

This method uses the result of the given predicate to branch the request pipeline.

So, let’s see it in action:

Here, if our request contains the provided query string, we execute the Run method by writing the response to the client. So, as we said, based on the predicate’s result the MapWhen method branch the request pipeline.

Now, we can start the app and navigate to https://localhost:5001?testquerystring=test :

MapWhen branching the request pipeline

And there we go. We can see our expected message. Of course, we can chain multiple middleware components inside this method as well.

Creating a Middleware in a Separate Class

In this section, we are going to show you a simple example of creating a custom middleware in a separate class and using it in the application’s pipeline. After you understand everything from this example, feel free to read our Global Error Handling in ASP.NET Core article , to see the custom middleware implementation in action for handling all exceptions globally in ASP.NET Core applications.

So to start, let’s create a new CustomMiddleware class in the root of our app:

Here, we are injecting the RequestDelegate next parameter and use it inside the InvokeAsync method to pass the execution to the next component. It is important that our middleware contains a public constructor with the injected RequestDelegate parameter and the method named Invoke or InvokeAsync .

After this, we can create another class and place a single extension method inside:

We create a static method that returns an IApplicationBuilder as a result and extends the IApplicationBuilder interface. In the method’s body, we just call the UseMiddleware method to add our custom middleware to the application’s pipeline.

Finally, we have to modify the Configure method in the Startup class below the first Use method:

And that’s it. As soon as we start our app and navigate to https://localhost:5001, we are going to see a familiar response from the previous Run method. But once we inspect the console window, we are going to find our message from the custom middleware:

Custom middleware logic from a separate class

Excellent. As we said, feel free to read our Global Error Handling in ASP.NET Core article to learn more about the custom middleware implementation.

Working with Factory-Based Middleware with the IMiddleware Interface

In the previous example, in the MiddlewareExtension class, we’ve called the UseMiddleware method to add the custom middleware to the application’s pipeline. The UseMiddleware method checks if the middleware’s registered type implements the IMiddleware interface. If it does, it means that our app is going to use the IMiddlewareFactory instance to resolve the IMiddleware implementation instead of using the convention-based middleware activation logic (as we have it now in our app).

There are some benefits of this approach:

  • The app activates our custom middleware per client request
  • We can use strongly typing with our middleware

Since IMiddleware is activated per client request, we can inject other scoped services into the middleware’s constructor.

So, let’s see how we can use the IMiddleware interface.

Usage of the IMiddleware Interface

The first thing we are going to do is to create a new FactoryActivatedCustomMiddleware class:

We can see that our class implements the IMiddleware interface. Additionally, we can see that we don’t have to use constructor injection to provide the RequestDelegate next parameter. In this case, we have that parameter inside the InvokeAsync method that we have to implement due to the IMiddleware’s contract implementation.

Next, we can add one more method inside the MiddleareExtension class:

If you inspect the UseMiddleware method, you can see that it accepts the params object[] args parameter. But for the factory-activated middleware, passing any parameter to the UseMiddleware method will cause the NotSupportedException at runtime.

After this, we have to register our factory middleware in the ConfigureServices method:

Finally, we can call our extension method in the Configure method:

You can start the app, navigate to the required URI and inspect the console logs to see the message from the factory-activated custom middleware class.

In this article we have learned:

  • About middleware components and the pipeline
  • To add middleware components to the request pipeline in a proper order
  • How to use different methods (Run, Use, Map, MapWhen)
  • And how to create middleware components in a separate class

So, there we go. After this article, we should have great knowledge about the middleware configuration in ASP.NET Core applications.

Until the next one.

All the best.

guest

Very well explained. Got to know more in deep about middlewares and their methods. I have been reading code maze articles from past 2 years and i enjoy these a lot.

Marinko Spasojevic

Thank you very much for the support. I am glad our content is useful to you.

How do we replace request/response body in the middleware?

Marinko Spasojević

Maybe this link can help. https://stackoverflow.com/questions/44508028/modify-middleware-response Bottom line is that you have to use a new memory stream because the body of the response is the stream itself.

i tried the above link… but the Seek() method throws exception…. ‘Specific Method not supported’ … if you have any article related to that…could you share?

Trust me, if we had something like that, I wouldn’t share the StackOverflow link with you 🙂

But it is very strange that you have that error. The Seek method is perfectly applicable on the Stream class and since the body of the response is of type Stream, I am not sure why you get such an error message.

This is a really good refresher on middleware. Thanks!

Thank you too, Brad, for reading.

wpdiscuz

Join our 20k+ community of experts and learn about our Top 16 Web API Best Practices .

writing custom middleware in asp net core

  • Latest Articles
  • Top Articles
  • Posting/Update Guidelines
  • Article Help Forum

writing custom middleware in asp net core

  • View Unanswered Questions
  • View All Questions
  • View C# questions
  • View C++ questions
  • View Javascript questions
  • View PHP questions
  • View Python questions
  • CodeProject.AI Server
  • All Message Boards...
  • Running a Business
  • Sales / Marketing
  • Collaboration / Beta Testing
  • Work Issues
  • Design and Architecture
  • Artificial Intelligence
  • Internet of Things
  • ATL / WTL / STL
  • Managed C++/CLI
  • Objective-C and Swift
  • System Admin
  • Hosting and Servers
  • Linux Programming
  • .NET (Core and Framework)
  • Visual Basic
  • Web Development
  • Site Bugs / Suggestions
  • Spam and Abuse Watch
  • Competitions
  • The Insider Newsletter
  • The Daily Build Newsletter
  • Newsletter archive
  • CodeProject Stuff
  • Most Valuable Professionals
  • The Lounge  
  • The CodeProject Blog
  • Where I Am: Member Photos
  • The Insider News
  • The Weird & The Wonderful
  • What is 'CodeProject'?
  • General FAQ
  • Ask a Question
  • Bugs and Suggestions

writing custom middleware in asp net core

An Absolute Beginner's Tutorial on Middleware in ASP.NET Core/MVC (and Writing Custom Middleware)

writing custom middleware in asp net core

  • Download source code - 1.6 MB

Introduction

In this article, we will try to understand the concept of middleware in ASP.NET core. We will see how middleware plays an important part in request response pipeline and how we can write and plug-in our custom middleware.

Before we could get into what middleware is and the value it brings, we need to understand how the request response worked in classic ASP.NET model. In earlier days, the request and response objects in ASP.NET were very big and had very tight coupling with IIS. This was a problem because some of the values in these objects are filled by the IIS request-response pipeline and unit testing such bloated objects was a very big challenge.

So the first problem that needed to be solved was to decouple the applications from web servers. This was very nicely defined by community owned standards called Open Web Interface for .NET (OWIN). Since the older ASP.NET applications were dependent on System.Web DLL which internally had very tight coupling with IIS, it was very difficult to decouple the applications from web servers. To circumvent this problem, OWIN defines is to remove the dependency of web applications on System.web assembly so that the coupling with web server (IIS) gets removed.

OWIN primarily defines the following actors in its specifications:

  • Server — The HTTP server that directly communicates with the client and then uses OWIN semantics to process requests. Servers may require an adapter layer that converts to OWIN semantics.
  • Web Framework — A self-contained component on top of OWIN exposing its own object model or API that applications may use to facilitate request processing. Web Frameworks may require an adapter layer that converts from OWIN semantics.
  • Web Application — A specific application, possibly built on top of a Web Framework, which is run using OWIN compatible Servers.
  • Middleware — Pass through components that form a pipeline between a server and application to inspect, route, or modify request and response messages for a specific purpose.
  • Host — The process an application and server execute inside of, primarily responsible for application startup. Some Servers are also Hosts.

Since OWIN is just a standard, there are multiple implementations for this in the last few years starting from Katana to the present day implementation in ASP.NET core. We will now focus on how the middleware implementation looks like in ASP.NET core.

Before that, let's try to understand what a middleware is. For the developer coming from the ASP.NET world, the concept of HTTPModule and HTTPHander is fairly familiar. These are used to intercept the request-response pipeline and implement our custom logic by writing custom modules or handlers. In the OWIN world, the same thing is achieved by the middleware.

OWIN specifies that the request coming from web server to the web application has to pass through multiple components in a pipeline sort of fashion where each component can inspect, redirect, modify or provide a response for this incoming request. The response then will get passed back to the web server in the opposite order back to the web server which then can be served back to the user. The following image visualizes this concept:

Image 1

If we look at the above diagram, we can see that the request passes through a chain of middleware and then some middleware decides to provide a response for the request and then response travels back to web server passing through all the same middleware it passed through while request. So a middleware typically can:

  • Process the request and generate the response
  • Monitor the request and let it pass thorough to next middleware in line
  • Monitor the request, modify it and then let it pass through to next middleware in line

If we try to find the middleware with actual use cases defined above:

  • Process the request and generate the response: MVC itself is a middleware that typically gets configured in the very end of middleware pipeline
  • Monitor the request and let it pass through to the next middleware in line: Logging middleware which simply logs the request and response details
  • Monitor the request, modify it and then let it pass through to the next middleware in line: Routing and Authentication module where we monitor the request decide which controller to call (routing) and perhaps update the identity and Principle for authorization (Auth-Auth).

Using the Code

In this article, we will create 2 owin middleware. First one will demonstrate the scenario where we are not altering the request. For this, we will simply log the request and response time in the log - TimingMiddleware . Second one will check the incoming response, find a specific header value to determine which tenant is calling the code and then returning back if the tenant is not valid - MyTenantValidator .

Note : Before we get started with the sample implementation, it's good to highlight the point that middleware is an implementation of pipes and filter pattern. Pipes and filter pattern says that if we need to performs a complex processing that involves a series of separate activity, it's better to separate out each activity as a separate task that can be reused. This gives us benefits in terms of reusability, performance and scalability.

Let's start by looking at how the middleware class definition should look like. There are two ways to define our custom middleware:

  • Custom middleware class
  • Inline custom middleware

Custom Middleware Class

First way is to have a custom class containing our middleware logic.

What this class does is that it gets called once the request reached this middleware. InvokeAsync function will get called and the current HttpContext will be passed to it. We can then execute our custom logic using this context and then call the next middleware in the pipeline. Once the request is processed by all middleware after this middleware, the response is generated and the response will follow the reverse chain and the function will reach after our _next call where we can put the logic that we want to execute before the response goes back to the previous middleware.

For our middleware to get into the pipeline, we need to use the Configure method in our Startup class to hook our middleware.

The above code shows how we have hooked in our custom middleware as the first middleware in the pipeline. The middleware will be called in the same order as they are hooked in this method. So in the above code, our middleware will be called first and the MVC middleware will be the last one to get called.

Inline Custom Middleware

The inline custom middleware is directly defined in the Configure method. The following code shows how to achieve this:

The end result will be the same for both approaches. So if our middleware is doing some trivial things that do not impact the readability of code if we put as inline, we could create the inline custom middleware. If the code that we want has significant code and logic in our middleware, we should use the custom middleware class to define our middleware.

Coming back to the middleware that we are going to implement, we will use the inline approach to define the TimingMiddleware and the custom class approach to define the MyTenantValidator .

Implementing the TimingMiddleware

The sole purpose of this middleware is to inspect the request and response and log the time that this current request took to process. Let's define it as inline middleware. The following code shows how this can be done.

We have hooked this middleware just before MVC middleware so that we can measure the time our request processing is taking. It is defined after UseStaticFiles middleware so that this middleware will not get invoked for all static files that are being served from our application.

Implementing the MyTenantValidator

Now let's implement a middleware that will take care of tenant verification. It will check for the incoming header and if the tenant is not valid, it will stop the request processing.

Note : For the sake of simplicity, I will be looking for a hard coded tenant id value. But in real world applications, this approach should never be used. This is being done only for demonstration purposes. Note that we will be using the tenant id value as 12345678 .

This middleware will be written in its separate class. The logic is simple, check for the headers in incoming request. If the header matches the hard coded tenant id, let the request proceed to the next middleware else terminate the request by sending response from this middleware itself. Let's look at the code of this middleware.

Now let's register this middleware in our Startup class.

With this code in place, if we try to run the application, we can see the response as error.

Image 2

To circumvent this issue, we need to pass the tenant id in the header.

Image 3

With this change, when we access the application again, we should be able to browse our application.

Image 4

Note : Even though we were talking in context of ASP.NET core, the concept of middleware is the same in all MVC implementations that are adhering to OWIN standards.

Points of Interest

In this article, we talked about ASP.NET core middleware. We looked at what middleware is and how we can write our own custom middleware. This article has been written from a beginner's perspective. I hope this has been somewhat informative.

  • OWIN: Open Web Server Interface for .NET
  • ASP.NET Core Middleware
  • Pipes and Filters pattern
  • 12 th September, 2018: First version

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

I Started my Programming career with C++. Later got a chance to develop Windows Form applications using C#. Currently using C#, ASP.NET & ASP.NET MVC to create Information Systems, e-commerce/e-governance Portals and Data driven websites.

My interests involves Programming, Website development and Learning/Teaching subjects related to Computer Science/Information Systems. IMO, C# is the best programming language and I love working with C# and other Microsoft Technologies.

  • Microsoft Certified Technology Specialist (MCTS): Web Applications Development with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Accessing Data with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Windows Communication Foundation Development with Microsoft .NET Framework 4

If you like my articles, please visit my website for more: www.rahulrajatsingh.com [ ^ ]

  • Microsoft MVP 2015

Twitter

Comments and Discussions

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

writing custom middleware in asp net core

Dot Net Tutorials

ASP.NET Core Middleware Components

Back to: ASP.NET Core Tutorials For Beginners and Professionals

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. As part of this article, we will discuss the following concepts related to the ASP.NET Core Middleware Components .

  • What are the ASP.NET Core Middleware Components?
  • Where do we use the Middleware Components in the ASP.NET Core application?
  • How do you configure Middleware Components in the ASP.NET Core application?
  • Examples of using Middleware Components?
  • What is the Execution Order of Middleware Components in ASP.NET Core?

What are Request Delegates in ASP.NET Core?

  • What is Use, Run, and Map Methods in ASP.NET Core?
  • What is the UseDeveloperExceptionPage Middleware Component?
  • How do you configure Middleware components using the Run() and Use() Extension Methods?
  • What is the difference Between MapGet and Map Methods?
  • What are the differences between Mao, Use, and Run Extension Methods?

What are ASP.NET Core Middleware Components?

ASP.NET Core Middleware Components are the basic building blocks of the request processing pipeline in an ASP.NET Core application. Middleware components handle specific tasks while processing incoming HTTP requests and outgoing HTTP responses. They enable us to add various functionalities to our application, such as authentication, routing, logging, etc, in a highly modular and customizable manner.

So, the ASP.NET Core Middleware Components are the software components (technically, components are nothing but the Methods) that are configured into the Application Request Processing Pipeline to handle the HTTP Requests and Responses. 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 component registered in the request processing pipeline. This can be achieved by calling the next() method within the Middleware. In this article, we will discuss how to Register the Middleware component and how to call the next() method.
  • Can perform certain tasks before and after the next component is invoked in the pipeline.

Each Middleware component has the ability to process requests, modify responses, or perform other actions before and after passing the request to the next middleware component. 

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

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

Some of the examples of using Middleware components in the ASP.NET Core application are as follows.

  • We have a Middleware component ( UseAuthentication ) for authenticating the user.
  • We have a middleware component ( UseHttpsRedirection ) for redirecting HTTP Requests to HTTPS.
  • Another Middleware component ( UseHttpLogging ) is used to log the HTTP Requests and Responses.
  • Another Middleware component ( UseDeveloperExceptionPage ) will execute when an unhandled exception occurs in the development environment. 
  • Similarly, we have a Middleware Component ( UseExceptionHandler ) that is used to catch exceptions, log them, and re-execute the request in an alternate pipeline.
  • We have a Middleware component ( UseStaticFiles ) that handles static files such as Images, Javascript, CSS files, etc.
  • We have a Middleware component ( UseAuthorization ) that is used to Authorize the users while accessing a specific resource.
  • The UseRouting Middleware component adds the End Points Routing to the Request Processing Pipeline. If you want to define the Route using Pattern or Attribute Routing, then using the UseRouting Middleware Component is mandatory.

We generally use the Middleware components to set up the Request Processing Pipeline in the ASP.NET Core Application. If you have worked with previous versions of the .NET Framework, then you may know we use HTTP Handlers and HTTP Modules to set up the Request Processing Pipeline. The Request Processing Pipeline is the pipeline that will determine how the HTTP Requests and Responses are going to be processed in the ASP.NET Core Application.

How do you configure Middleware Components in the ASP.NET Core (.NET 6) application?

From the .NET 6, we need to configure the Middleware components within the Main() method of the Program class, which is present inside the Program.cs class file. This is the class that is going to run when the application starts, and the application execution is going to start from the Main method, i.e., the Main method is the entry point for any ASP.NET Core Web Application.

When we create a new ASP.NET Core Empty Web Application, then by default, the Program class is created with the Main method, as shown in the below image.

ASP.NET Core 6 Main Method

In the above Main method, by default, we have configured two middleware components, i.e., MapGet and Run . Suppose you want to configure a middleware component in an ASP.NET Core Web Applications. In that case, you must configure it within the Main() method of the Program class using the WebApplication instance. For a better understanding, please modify the Main Method of the Program class as follows. Here, we have configured a few Middleware Components using the WebApplication instance (using the variable app), such as UseDeveloperExceptionPage() , UseRouting() , and UseEndpoints() .

As you can see in the above code, the Main() method sets up the request processing pipeline with a few middleware components as follows.

  • UseDeveloperExceptionPage() Middleware component
  • UseRouting() Middleware component
  • UseEndpoints() Middleware component

Before understanding the above Built-in Middleware Components in ASP.NET Core Applications, let us first understand what Middleware Components are and How Exactly These Middleware Components Work in ASP.NET Core Web 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 that is configured in the Application Request Processing Pipeline.
  • Process the outgoing HTTP response, modify it, and then pass it on to either the previous middleware component or to the ASP.NET Core Web Server.

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

Understanding Middleware Components in ASP.NET Core

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 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. This concept is 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.

As we already discussed, 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 in ASP.NET Core Application?

It is very important to understand the execution order of Middleware Components in ASP.NET Core Web Applications. The ASP.NET Core Middleware Components are executed in the same order as they are added to the Request Processing Pipeline. So, we need to take proper care when adding the Middleware Components to the Request Processing Pipeline of the ASP.NET Core Web Application.

As per your Application’s Business Requirements, you may add any number of Middleware Components. For example, if you are developing a static web application with some static HTML pages and images, then you may require only “StaticFiles” middleware components in the Request Processing Pipeline.

But, if you are developing a secure Dynamic Data-Driven Web Application, you may require several Middleware Components such as Logging Middleware, Authentication Middleware, Authorization Middleware, MVC Middleware, etc.

In ASP.NET Core, Request Delegates are used to build the Request Processing Pipeline, i.e., Request Delegates are used to handle each incoming HTTP request. You can configure the Request Delegates using the Run, Map, and Use Extension Methods in ASP.NET Core.

You can specify a Request Delegate using an in-line anonymous method (called in-line middleware) or specify the Request Delegates using a reusable method. These reusable methods and in-line anonymous methods are called Middleware or Middleware Components. Each Middleware Component in the Request Processing Pipeline is responsible for invoking the Next Middleware Component in the Pipeline or Short-Circuiting the Pipeline by not calling the Next Middleware Component.

What is the use of the Use and Run Extension Method in ASP.NET Core Web Application?

In the ASP.NET Core Web Application, we can use the “ Use ” and “ Run ” Extension Methods to register the Inline Middleware Component into the Request Processing Pipeline. The “ Run ” extension method allows us to add the terminating middleware (the middleware that will not call the Next Middleware Components in the Request Processing Pipeline) component. On the other hand, the “ Use ” extension method allows us to add the middleware components, which may call the next Middleware Component in the Request Processing Pipeline.

If you observe the Main method of the Program class, then you will see that it gets an instance of WebApplication, and using the WebApplicatio instance (app) along with the extension methods such as Use and Run, it configures the Middleware Components. As you can see, in the Main method of the Program class, three Middleware Components are registered into the Request Processing Pipeline. They are as follows:

  • UseDeveloperExceptionPage() Middleware Component
  • UseRouting() Middleware Component
  • UseEndpoints() Middleware Component

What is the DeveloperExceptionPage Middleware Component?

As you can see, the UseDeveloperExceptionPage() Middleware Component is registered into the request processing pipeline, and this middleware component will come into the picture only when the hosting environment is set to Development. This middleware component will execute when an unhandled exception occurs in the application. Since it is in Development mode, it will show you the exception details on the webpage. You can consider this as a replacement for the Yellow Screen of Death. In a later article, we will see the use of this middleware component in detail with examples.

What is the UseRouting() Middleware Component?

The UseRouting() middleware component adds Endpoint Routing to the request processing pipeline. Endpoint Routing means it will map the URL (or incoming HTTP Request) to a particular resource. We will discuss this in detail in our Routing articles.

What is the UseEndpoints() Middleware Component?

To use the UseEndpoints() Middleware Component, you must first add the UseRouting() middleware component. In this UseEndpoints() Middleware Component, the Map extension method will take the routing decisions. As part of this UseEndpoints() Middleware Component, we can register multiple URL patterns using the MapGet or Map methods.

For a better understanding, please have a look at the following example. As you can see, in the MapGet Extension Method, we have specified multiple URL patterns like “/”, “/api”, and “/home”. So, based on the URL pattern, the corresponding middleware component will be executed.

Instead of MapGet, you can also use the Map method, as shown below.

Now run the application, and you should get the output as expected.

  • UseRouting(): It matches a request to an endpoint.
  • UseEndpoints(): It executes the matched endpoint.

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

In ASP.NET Core, both MapGet and Map extension methods are used for configuring request handling in the application’s routing system, but they serve slightly different purposes and have different use cases.

MapGet Method:

  • Purpose: MapGet is specifically designed for handling HTTP GET requests. It’s used to define endpoints that respond only to GET requests.
  • Usage: You typically use MapGet when you want to retrieve data from the server without modifying the server’s state. For example, fetching a list of items or getting details about a specific item.
  • Syntax: 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:

  • Purpose: Map is a more general method used for handling all types of HTTP requests (GET, POST, PUT, DELETE, etc.). It’s more flexible compared to MapGet.
  • Usage: You use Map when you need to set up endpoints that might handle multiple types of HTTP requests or when you have custom logic to determine the type of request to be handled.
  • Syntax: Similar to 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, & DELETE requests using the Map method.

How do you configure Middleware components using the Run() Extension Method?

Now, let us see how to configure new Middleware Components using the Run Extension Method in the ASP.NET Core Web Application. From the .NET 6, we need to configure the Middleware Components within the Main method of the Program class. So, modify the Main method of the Program class as follows to add a new custom Inline Middleware Component using the Run Extension Method.

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

Middleware Components in ASP.NET Core Application

Now, if you go to the definition of the Run Extension Method configuring the Middleware Component, you will see the following signature. So, it basically adds a terminal middleware delegate to the application’s request pipeline.

Run Extension Method Definition in ASP.NET Core

Here, you can see it is clearly saying that this Extension Method is used for adding terminal middleware. Terminal Middleware is the last middleware component. If you are new to the extension method, please read the article below, where we discussed the extension methods in detail.

https://dotnettutorials.net/lesson/extension-methods-csharp/

You can also see from the above definition of the Run() Extension method that it takes an input parameter of RequestDelegate . Now, if you go to the definition of RequestDelegate, then you will see the following.

RequestDelegate 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. If you are new to delegates, I strongly recommend reading the following article, discussing the delegates in detail.

https://dotnettutorials.net/lesson/delegates-csharp/

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

ASP.NET Core Middleware Components with Examples

Note: Instead of passing the request delegate inline as an anonymous method, you can also define the request delegate in a separate class and pass it here, which we will discuss later.

Add one More Middleware Component to the Application Request Processing Pipeline.

To do so, modify the Main method of the Program class as shown below.

Now, we have two middleware components registered with the Run() extension method. If you run the application, then you will get the following output.

Getting Response from First Middleware

The output comes from the first middleware component. The reason is that we register a middleware component using the Run() extension method. That component becomes a terminal component, which means it will not call the next middleware component in the request processing pipeline.

Configuring Middleware Components Using the Use Extension Method

Then, the question that comes to your mind is how to call the next component in the request processing pipeline. The answer is to register your middleware component using the Use extension method, as shown below. As you can see in the below code, in the first Use Extension method, we are passing two input parameters to the anonymous method, i.e., context and next. Then, we call the next method, which will call the next middleware component registered in the Request Processing Pipeline.

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

Configuring Components using Use Extension Method in ASP.NET Core

Understanding the Use Extension Method in ASP.NET Core:

The Use extension method adds a middleware delegate defined in-line to the application’s request pipeline. Following is the definition of the Use extension method:

Understanding the Use Extension Method in ASP.NET Core

This method is also implemented as an extension method on the IApplicationBuilder interface. This is the reason why we can invoke this method using the IApplicationBuilder instance. 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., it is a generic delegate that can handle the request or call the next middleware component in the request pipeline. 

Note: If you want to send the request from one middleware to the next, you need to call the next method.

Differences Between Run, Map, and Use Extension Method in ASP.NET Core:

Use extension method:.

  • Purpose: The Use Extension method adds middleware to the application’s request pipeline. Middleware components added using Use can handle requests and then pass them on to the next component in the pipeline (by calling the next delegate).
  • Behavior: A middleware component in the Use method can pass the request to the next component or short-circuit the pipeline (not call the next delegate). This makes it flexible for tasks like logging, authentication, etc.
  • Example: Adding a custom logging middleware.

Run Extension Method:

  • Purpose: The Run Extension method adds a terminal middleware to the request pipeline. This means it does not call the next middleware in the pipeline.
  • Behavior: Since Run is a terminal operation, it is used when the response is fully formed and ready to be returned to the client. After a Run delegate is executed, the pipeline is short-circuited.
  • Example: Returning a static file directly or a simple message at the end of the pipeline.

Map Extension Method:

  • Purpose: The Map Extension method branches the pipeline based on the request path. It allows configuring a sub-pipeline that is executed for specific routes.
  • Behavior: When a request matches a specified path, the Map delegate will handle that request using its sub-pipeline. Requests that don’t match the path continue through the main pipeline.
  • Example: Mapping different routes to different middleware pipelines, like /api going to API-specific middleware and /home going to UI-specific middleware.

In summary:

  • Use is for general-purpose middleware that can pass the request along.
  • Run is for terminal middleware that completes the response.
  • Map is for conditional branching of the pipeline based on request paths.

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 ASP.NET Core Middleware Components with Examples article.

dotnettutorials 1280x720

About the Author: Pranaya Rout

Pranaya Rout has published more than 3,000 articles in his 11-year career. Pranaya Rout has very good experience with Microsoft Technologies, Including C#, VB, ASP.NET MVC, ASP.NET Web API, EF, EF Core, ADO.NET, LINQ, SQL Server, MYSQL, Oracle, ASP.NET Core, Cloud Computing, Microservices, Design Patterns and still learning new technologies.

5 thoughts on “ASP.NET Core Middleware Components”

writing custom middleware in asp net core

Please write a one section for Web API using .Net Core

writing custom middleware in asp net core

Add a section for asp.net core webapi (dotnet new webapi)

writing custom middleware in asp net core

Awesomeness

writing custom middleware in asp net core

This article is just next to Perfection..

writing custom middleware in asp net core

excellent article and explanation

Leave a Reply Cancel reply

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

Steve Collins head shot

Steve Talks Code

Coding thoughts about .NET

Styles of Writing ASP.NET Core Middleware

twitter icon

In this post, I discuss the differences between convention and factory styles of writing middleware in ASP.NET Core along with the differences in how the instances are created and interact with dependency injection.

If you have been using ASP.NET Core for a while, you are probably familiar with the concept of middleware. If not, I would recommend reading the Microsoft Docs page that provides an overview of how middleware conceptually works

In this post, I will be delving deeper into how middleware is added into the request-response pipeline with references to the code in UseMiddlewareExtensions.cs.

The link I have used here is to the excellent https://source.dot.net/  web site where you can easily search for .NET Core/5 code by type or member name instead of trawling through the ASP.NET Core GitHub repos.

Before delving into the mechanics of how the pipeline is built and works, lets start with how the middleware gets registered with your application.

Registering Your Own Custom Middleware

When you need to add middleware to your ASP.NET Core application, it is usually done within your Startup class in the Configure method.

There are three main ways of registering middleware in the Configure method , namely by using the generic and non-generic UseMiddleware extension methods and lastly the Use method on IApplicationBuilder .

Let's look at each of these in a bit more detail in order of ease of use (which also happens to be a top down order of execution).

" class="pageLink" href="#use-middleware-t-middleware">UseMiddleware

In most cases, you will be encapsulating your middleware into a class which adheres to either a convention or an interface (more on this in a bit). This allows you to reuse your middleware code if it is in its own class library project.

The simplest way to register your middleware class within the Configure method is to use the UseMiddleware extension method on the IApplicationBuilder instance that is passed into the Startup's Configure method.

To call this method, you need to supply a generic parameter that is set to the type of your middleware class as shown here.

The method has an optional parameter (args) for passing in an array of objects that represent parameters that can be passed into the constructor of your class. This can be of use when not all of the constructor parameters can be resolved by dependency injection.

Behind the scenes, this method makes a call to the non-generic UseMiddleware method. To do this, the generic method gets a Type instance from the generic type parameter and passes it (with the optional args array if present) to the non-generic method which does the hard work.

UseMiddleware (Non-Generic Version)

Most of the time, you will be using the generic version, but it is worth knowing there is a non-generic version if you need to derive the type at runtime.

Let's look at the start of the method to see what is going on

In this method, the code checks to see if the middleware type passed in as a parameter implements the IMiddleware interface. If it does, the method branches off to use a  middleware factory that will use dependency injection to create the instance of the middleware class

Otherwise, it makes a call to the IApplicationBuilder's Use method by passing in an anonymous function that uses reflection to create the required request delegate (not show here as it is a lot of code - if interested, look here ).

The IApplicationBuilder Use Method

The IApplicationBuilder.Use method is the 'raw' way of registering middleware. The method takes a single parameter of type

Func<RequestDelegate, RequestDelegate>

This delegate may be a method or an anonymous function created by a lambda expression, but must adhere to the delegate signature of

Task RequestDelegate(HttpContext context)

In this example from the Microsoft Docs web site, we are not actually doing anything, but it gives an example of an implementation where you may want to intercept the pipeline and do something before and/or after the next middleware in the pipeline is executed (by the next.Invoke() in this example).

What is interesting is seeing how the RequestDelegate is expressed as an anonymous function.

The context parameter gives us access to an HttpContext instance which in turn gives us access to the request and response objects. However, you must not  make any changes to the response if another middleware is to be invoked as once the response has started (by a later middleware in the pipeline), any changes to it will cause an exception.

If you do want to return a response, your middleware becomes a terminating or a short-circuiting middleware and does not invoke any further middlewares in the pipeline.

In this post I want to keep the focus on understanding how middleware works with dependency injection lifetimes rather than the mechanics of how the middleware pipeline itself is built and executes each pipeline middleware in turn .

For a deeper dive into how request delegates interact with each other to form a pipeline, I highly recommend Steve Gordon's   Deep Dive - How Is The Asp Net Core Middleware Pipeline Built?  which goes deep into the chaining of request delegates.

Middleware Styles : In-Line vs Factory vs Convention

Ultimately, all middleware eventually boils down to becoming a request delegate function that gets passed into the Use method on the IApplicationBuilder implementation instance.

In-Line Middleware

You can write your middleware directly inside an anonymous function (or method) that gets passed to the Use method via a delegate parameter. The call to the Use method is written inside the Configure method of the Startup class (on via the Configure method on the HostBuilder).

This is the approach you usually take if want to do something simple in your middleware that has no dependencies  that would need to be resolved by the dependency injection container as the delegate does not interact with the container.

That does not mean that you cannot get the container to resolve instances for you. It just means that you have to explicitly ask the container to resolve a service via the RequestServices property on the HttpContext instance (that is passed as a parameter into the delegate).

This moves you into the realms of the service locater anti-pattern, but given that you are usually creating the delegate within the confines of the  application startup, this is not so much of a concern as doing it elsewhere in your application landscape.

As the code is all written in-line, it can become a bit of a pain to read and debug if it is doing many things or you have multiple Use entries as the Configure method becomes a but unwieldy.

To avoid this, you could extract the contents of the Use anonymous function to their own methods within the Startup. However this still limits your middleware to the confines of your project.

in most cases, you will want to make the middleware code self-contained and reusable and take advantage of getting the dependency injection container do the work of resolving instances without having to explicitly call the container (as we've had to in the above example).

This is where the other two styles of writing middleware come into their own by writing classes that encapsulate the functionality that will be called by the pipeline.

Factory Style Middleware

Now I have a confession. I have been using .NET Core for quite a while now and, until recently, this had passed me by.

This may be because I learnt about middleware with ASP.NET Core 1.1 and factory style middleware was not a 'thing' until ASP.NET Core 2.0,  when it was introduced without any fanfare (it was not included in the What's New in ASP.NET Core for either version 2.0 or 2.1 ).

It was not until I recently read Khalid Abuhakmeh's blog post that then led be to read the this Microsoft Docs page  that I even became aware of factory style middleware.

If you are interested in how the the factory style was introduced into ASP.NET Core, have a look at this Git issue which shows how it evolved with a lot of commentary from David Fowler

The introduction of factory style middleware brings the following benefits over convention style middleware:

  • Activation per request, so allows injection of scoped services into the constructor
  • The explicitly defined InvokeAsync method on the interface moves away from the unstructured Invoke/InvokeAsync methods in convention style middleware that allowed additional parameters to be added
  • It is more aligned with the way you write other classes in your application as it is based on the premise of constructor injection over method parameter injection
  • Whilst there is a default implementation of IMiddlewareFactory that gets registered by default by the default WebHostBuilder , you can write your own implementation of IMiddlewareFactory that may be of use if you are using another container such as AutoFac where you may want to resolve instances using functionality that is not present in the out-of-the-box Microsoft implementation of IServiceProvider

So how do we implement the factory style of middleware ?

The key to this is by writing your middleware class as an implementation of the IMiddleware interface which has a single method, InvokeAsync.

The method has two incoming parameters

  • an instance of  HttpContext  this holds all the request/response information
  • a RequestDelegate instance that provides the link to the next middleware in the pipeline to call

Inside the method is where you can do whatever it is that you need to do in your custom middleware. This may be  either

  • intercepting the request-response chain to do something before and after the next middleware in the chain, such as logging or manipulating the request (or response), or
  • acting as terminating middleware that sends a response back (such as the static file middleware ) and therefore does not proceed to the next middleware in the pipeline (unless it cannot handle the request).

Lastly, if you are not terminating the pipeline in your middleware, you need to ensure that the request delegate is invoked, passing the HttpContext instance to it as a parameter.

In the above example, I have taken the in-line style we used earlier and refactored it into its own factory-style middleware by implementing the IMiddleware interface. By doing this, I could put it into its own project and share between multiple other projects, avoiding the repetition of the in-line style.

We also benefit from not having to get the instance of ILogger from the context parameter (so avoiding the service locator anti-pattern) and also have a proper type to use with the logger (as the Startup type felt wrong in the in-line style).

To use the factory style middleware, there are two things that need to be done to use it in your application.

The first, as with all middleware (regardless of style), is to register the middleware in the Configure method of your Startup class as discussed above (alternatively, you may want to use the Configure method directly on the host builder)

The next step is to go back up in to the ConfigureServices method (either in the StartUp class or directly on the HostBuilder) and register the middleware class with the dependency injection container.

To do this, you need to adhere to two simple rules

  • You need to register the middleware with the concrete type as the service, not the IMiddleware interface (or any other interface it may implement)
  • Think very carefully lifetime of the registration - for now, we will assume that the lifetime will be scoped (as opposed to transient or singleton) as the purpose of factory middleware is that is is invoked per request.

The second point is important as you could be in danger of creating a captured dependency if you register your middleware as a singleton, but the service types of the parameters in the constructor have shorter lifetimes.

Convention Style Middleware

Convention style middleware is the way you will find most examples are written and indeed how most Microsoft written middleware works (and as per the comments in the Git issue, remains for backward compatibility).

As it is well documented in many places on the internet (and of course, in the Microsoft Docs - see Writing Custom ASP.NET Core Middleware ), I will concentrate on the key differences with factory style middleware here

The first obvious difference is that the class does not have to implement a specific interface (E.g. IMiddleware). Instead, you expected to adhere to a convention of implementing one of two methods Invoke or InvokeAsync.

  • Both methods have the same signature, the naming choice is up to you, though given that both return a Task, it is usual to append Async to asynchronous method names
  • You cannot have both Invoke and InvokeAsync methods - this will cause an exception to be thrown
  • The first parameter must be of type HttpContext - if this is not present, an exception will the thrown
  • The return type must be a Task

So given that the RequestDelegate for the next delegate is no longer passed into the InvokeAsync as a parameter, we need to obtain it from somewhere else. As we are adhering to a convention, we should stick with constructor injection and have the next delegate injected here.

We are still missing our ILogger instance, but this is where things get a bit more complex.

When it comes to interactions with dependency injection, the key thing to be aware of is that the instance of our convention-style middleware class is not created by the dependency injection container, even if you register the class in ConfigureServices. Instead, the UseMiddleware extension method uses a combination of reflection and the ActivatorUtilities class to create the instance - once, and only once! - so it is effectively a singleton.

The reason for this is that the code that is of interest to the middleware pipeline is the Invoke/InvokeAsync method, as it is a call to this will be wrapped inside the anonymous function that gets passed to the Use method in the IApplicationBuilder instance. In other words, creating the class instance is a stepping stone to creating the delegate and once created, the class constructor is never interacted with again.

Why does this matter? It comes back to understanding how we obtain dependencies in our custom middleware.

If we specified dependencies in the constructor that have been registered with shorter lifetime that singleton (transient and scoped), we end up with captured dependencies that are locked until the singleton is released (which in the case of middleware is when the web application shuts down).

If you require transient or scoped dependencies, these should be added as parameters to the Invoke/InvokeAsync method.

When the UseMiddleware scans the class through reflection, it does several things such as validating the class adheres to the expected conventions, but the main thing we are interested in is the mapping of our middleware's Invoke or InvokeAsync method to the RequestDelegate signature required by the ApplicationBuilder's Use method.

The mapping is decided by checking if the signature of the Invoke/InvokeAsync method exactly matches the RequestDelegate signature (e.g. it only requires a single parameter of type HttpContext), it will use the method directly as the RequestDelegate function

Otherwise, it will create a wrapping function that matches the RequestDelegate signature, but that then uses a the ActivatorUtilities class to  resolve the method parameters from the dependency injection container accessed via the ApplicationBuilder's ApplicationServices property.

You can view this from the source code here

At this point, once the UseMiddleware has mapped the RequestDelegate that represents our class's middleware invocation method into the ApplicationBuilder, our middleware is baked into the pipeline.

Whether you use convention or factory based middleware is a design decision to be made based on what your middleware is trying to achieve and what dependencies it needs resolved from the dependency injection container.

  • In-line style is find for 'quick and dirty' middleware that you do not plan to reuse and is either terminating or does very little when intercepting the pipelines with few dependencies
  • If there are many scoped or transient dependencies, you may want to consider the Factory-style approach for coding simplicity as it aligns with the constructor injection pattern that you are probably more familiar with for getting dependencies from the container and if registered with the correct scope , avoids captured dependencies
  • If there are no dependencies, or you know the only dependencies are guaranteed to have  a singleton lifetime, you may lean towards convention-style middleware as these can be injected into the container when the pipeline is first built and, as there are no additional parameters to the InvokeAsync method, the method can be used as a direct match to the RequestDelegate function that gets used in the pipeline
  • If you are already familiar with using  convention-style middleware and specifying transient and scoped dependencies in the Invoke/InvokeAsync  parameter list, there is no pressing need to change to the factory-style approach.

I hope this post has been of use. If so, please spread the word by linking to it on Twitter and mentioning me @stevetalkscode .

I have created a demo solution at https://github.com/stevetalkscode/middlewarestyles   which you can download and have a play with the different styles of writing middleware and see the effects of different dependency injection lifetime registrations for the factory style vs the singleton captured in conventional style middleware.

I plan to revisit this topic in a future post to dig deeper into the how the different styles can affect start up and request performance and also the memory usage (which in turn affects garbage collection) which may sway the decision between using factory or convention style way of writing middleware.

Photo of Steve Collins (Steve Talks Code)

writing custom middleware in asp net core

Learn about API Management from experts on today’s innovative API architectures to accelerate growth, improve discoverability, transform existing services, and more! All with a hybrid, multi-cloud management platform for APIs across all environments.

Introducing ASP.NET Core metrics and Grafana dashboards in .NET 8

' data-src=

James Newton-King

February 14th, 2024 11 12

Metrics report diagnostics about your app. .NET 8 adds over a dozen useful metrics to ASP.NET Core:

  • HTTP request counts and duration
  • Number of active HTTP requests
  • Route matching results
  • Rate limiting lease and queue durations
  • SignalR transport usage
  • Low-level connection and TLS usage from Kestrel
  • Error handling diagnostics

Metrics are numerical measurements reported over time. For example, each HTTP request handled by ASP.NET Core has its duration recorded to the http.server.request.duration metric. Tooling such as the .NET OpenTelemetry SDK can then be configured by an app to export metric data to a telemetry store such as Prometheus or Azure Monitor . Metrics are part of the OpenTelemetry standard and all modern tools support them.

Metrics data are useful when combined with tooling to monitor the health and activity of apps:

  • Display graphs on a dashboard to observe your app over time. For example, view activity from people using the app.
  • Trigger alerts in real-time if the app exceeds a threshold. For example, send an email if request duration or error count exceeds a limit.

Using metrics

ASP.NET Core’s built-in metrics are automatically recorded. How you use these metrics is up to you. Let’s explore some of the options available.

.NET Aspire dashboard

.NET Aspire is an opinionated stack for building observable, distributed applications. The Aspire dashboard includes a simple, user-friendly UI for viewing structured logs, traces and metrics. Aspire apps are automatically configured to send telemetry data to the dashboard during development.

Here you can see a collection of available metrics, along with name, description, and a graph of values. The Aspire UI includes metrics filters. Filtering is possible using a powerful feature of metrics: attributes.

Each time a value is recorded, it is tagged with metadata called attributes. For example, http.server.request.duration records a HTTP request duration along with attributes about that request: server address, HTTP request method, matched route, response status code and more. Attributes can then be queried to get the exact data you want:

  • HTTP request duration to a specific endpoint in your app, e.g. /product/{name} .
  • Count the number of requests with 4xx HTTP response codes.
  • View request count that threw a server exception over time.
  • HTTP vs HTTPS request duration.
  • Number of visitors using HTTP/1.1 vs HTTP/2.

ASP.NET Core Grafana dashboards

Grafana is powerful open-source tool for building advanced dashboards and alerts. It allows you to create interactive, customizable dashboards with a variety of panels, graphs, and charts. Once complete, a dashboard displays data from your telemetry store. Grafana is a good choice to monitor apps deployed to production and a dashboard gives a real-time view of an app health and usage.

Grafana gives you the power to build exactly what you want, but it takes time to build high-quality dashboards. As part of adding metrics in .NET 8, the .NET team created pre-built dashboards designed for ASP.NET Core’s built-in metrics.

A screenshot of the ASP.NET Core Grafana dashboard

The ASP.NET Core Grafana dashboards are open source on GitHub and available for download on grafana.com . You can use the dashboard as they are or customize them further to build a solution tailored to your needs.

Quickly try out Grafana + ASP.NET Core using the .NET Aspire metrics sample app .

  • Metrics aren’t limited to what is built into .NET. You can create custom metrics for your apps.
  • dotnet-counters is a command-line tool that can view live metrics for .NET Core apps on demand. It doesn’t require setup, making it useful for ad-hoc investigations or verifying that metric instrumentation is working.
  • Use metrics in unit tests . ASP.NET Core integration testing, MetricCollector and IMeterFactory can be combined to assert values recorded by a test.

.NET 8, ASP.NET Core Grafana dashboards and .NET Aspire (preview) are available now. Try using metrics today and let us know what you think:

  • Download the latest .NET 8 release .

Use metrics in your tool of choice:

  • Learn more about the .NET Aspire dashboard and get started .
  • Download ASP.NET Core Grafana dashboards .
  • Install dotnet-counters command-line tool.

Want to try things hands on? Checkout our new cloud-native training modules on Microsoft Learn.

Thanks for trying out .NET 8 and metrics!

' data-src=

James Newton-King Principal Software Engineer, .NET

writing custom middleware in asp net core

11 comments

Leave a comment cancel reply.

Log in to join the discussion.

' data-src=

Why is the date on this blog post six days in the future?

' data-src=

The blog post’s date metadata was wrong and is fixed.

' data-src=

@James, do these libraries work with .NET 7? Or are them .NET 8 specific?

Everything discussed requires .NET 8 or later.

' data-src=

Thanks @James for this insightful share.

Can you tell us more about the benefits of using this instead of Azure Monitor in a cloud scenario ?

I don’t have a huge amount of experience with Azure Monitor. I’m not qualified to give a good comparison between Azure Monitor vs Prometheus/Grafana.

One notable difference is that while Grafana and Prometheus have managed offerings, e.g. Azure Managed Grafana or Grafana Cloud , they can also be run on your own machine. If you want a solution that is portable then Prometheus/Grafana are a good choice.

' data-src=

Thank you James. Also think about adding a “lite” version of these metrics dashboards directly in the Aspire dashboard app. In other words, this solution requires both Prometheus and Grafana containers. It would be nice to have a ‘lite’ dashboard built in blazor/html directly inside the Aspire Dashboard app (without needing those two extra containers) – just displaying the transient in-memory telemetry. That would be a fun job for an intern to spend a few weeks on.

The Aspire dashboard has a capability to view metrics today. Because we have a simple solution, and it’s quite easy to setup Prometheus and Grafana in Aspire, we probably won’t add something like metrics dashboards to the Aspire dashboard app.

But if you think it is important then create an issue at https://github.com/dotnet/aspire and we can see how much demand there is by Aspire users.

' data-src=

Is there any recommended Grafana dashboard for http.client.* metrics?

We haven’t made a dashboard that includes client metrics, but you could copy or extend the ASP.NET Core dashboards to include them.

http.client.request.duration is very similar to http.server.request.duration so charts could be reused without significant changes.

' data-src=

fair discussion everything explained clearly

light-theme-icon

Insert/edit link

Enter the destination URL

Or link to existing content

Search code, repositories, users, issues, pull requests...

Provide feedback.

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly.

To see all available qualifiers, see our documentation .

  • Notifications

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AddMiddlewareAnalysis does not detect custom middleware #54166

@suneel-sh

suneel-sh commented Feb 22, 2024

@gfoidl

No branches or pull requests

@gfoidl

writing custom middleware in asp net core

Rick Strahl's Weblog  

writing custom middleware in asp net core

Reading Raw ASP.NET Request.Body Multiple Times

Raw Ahi Banner

Some time ago I wrote about retrieving raw HTTP request content from an incoming request and - surprisingly - it's one of the most popular posts on this blog. The post discusses a few ways how you can capture raw request content in ASP.NET Core applications in situations when traditional model binding/mapping doesn't work and you need to access the underlying raw request data.

You can directly read the Request.Body stream to access content in raw form which is reading the request data explicitly, or if you're using Model Binding you implicitly get the data bound to objects in [FromBody] either from JSON and or HTML form content.

This all works fine if you're doing typical request operations, but in that post I left out one bit of important information: The Request.Body request stream is read-once by default, meaning you can read the request data only once . If you repeatedly access the stream you'll get an empty stream and by extension, empty data.

While it's not common that you need to read request data multiple times it comes up occasionally, especially in scenarios where you need to track the request data for auditing or custom logging.

In this post I look at ways how you can read from Request.Body multiple times using the newish Request.EnableBuffering feature in ASP.NET, as well as discussing some of the pitfalls you have to watch out for in the process.

writing custom middleware in asp net core

Reading Request Body Multiple Times

The previous post has a lot of detail and the mechanics of the actual process of retrieving request data. That post shows how to capture raw request content and also how to create custom InputFormatter that can automatically return raw data to your controller code using standard parameters.

The gist of the raw request retrieval - with a few adjustments since the last post - is summed up in the code at the end of this post via an HttpRequest extension method helper to retrieve raw request content. The very short TLDR version is that you can use the newish Request.EnableBuffering() feature along with resetting the Request.Body stream after reading to allow multiple reads of the request buffer.

What's up with reading Request.Body multiple times?

So, the problem with reading Request.Body by default is that it's a Read-Forward only data stream meaning you can only read it once . This applies both to your own code that's doing something custom with the Request.Body explicitly, or the internal use of ASP.NET - typically for endpoint model binding that implicitly reads Request.Body . In either case, once the Request.Body gets read, you or ASP.NET itself can't read the request content again.

To give you a real world scenario, I ran into this recently with a customer who requested that we log incoming request POST/PUT data for audit purposes. We need custom logging that logs both some of the incoming Request which includes the incoming POST/PUT data, but also some application specific data. In that scenario the first body read occurs for our custom logging, and then again when ASP.NET performs the [FromBody] binding to provide the model data to our HttpPost/HttpPut endpoints.

Of course, I initially forgot that Request.Body can't be read more than once, and when I initially wrote the log code I was happy to see the captured data written to the custom logging, but didn't immediately notice that the endpoint requests were not receiving their request data . 😄

In my case the first request data capture happens in a small custom middleware implemented via app.Use() in startup code:

The key bit are in this block:

The problem with this code is that it reads the request content before ASP.NET gets to it . My logging code gets the request content just fine, but because the stream is read-once by default, ASP.NET's model binding now fails to retrieve the data on the second read. End result: The Controller API endpoints get nada for data !

To illustrate this scenario, this endpoint:

ends up with a null input, because there's no data in the Request.Body stream on the second read.

Null Post Data

Request.Body Stream

Under normal operation the Read-Once default behavior of the Request.Body stream is what you want: A request comes in and the framework reads the body stream and parses the data into your Model for an API or ViewModel in an MVC or Razor page request.

Reading the stream once is very efficient as the stream is read only as needed and doesn't need to be buffered in memory or on disk. The incoming stream can be directly read and immediately bound to the data from the stream.

But... if for any reason you need to read the stream multiple times, like in my example of the pre-flight logging, that's not going to work, as only the first read operation captures the data. The second operation which is ASP.NET's model binding gets an empty stream.

Use EnableBuffering to Re-Read the Stream

Luckily there's a workaround: You can use Request.EnableBuffering() which essentially changes the Request.Body stream's behavior so that it CanSeek and therefore can be reset to the 0 position and then be re-read.

Note that this is usually a 3 step process:

  • Enable Buffering
  • Read the stream
  • Reset the Stream pointer to 0

So, you can now do this before the stream is read for the first time :

Note that EnableBuffering() supports an optional bufferThreshold parameter that indicates the size of the maximum memory buffer used, before buffering buffers to disk. The values is in bytes and the default if not specified is 30kb which seems reasonable, but if you know the size of your inbound data you can fine tune the buffer to match. See docs for more info .

Then you can read the stream:

Finally, if you expect the stream to be read again, make sure you reset the stream pointer to 0:

This leaves the stream as you found it before your read, and it can then be read again. If you read the stream after ASP.NET has processed the body, you'll need to reset the position yourself before you read the stream .

writing custom middleware in asp net core

How Stream Buffering works

Stream buffering works, by enabling buffering before any read operation occurs . When you call the Request.EnableBuffering() method, ASP.NET swaps out the stream used by Request.Body transparently:

Before EnableBuffering() - uses HttpRequestStream

Unbuffered File Stream

After EnableBuffering() - uses FileBufferingReadStream

Buffer File Stream

Make sure you Enable Buffering Before the First Read

The key is:

You have to call Request.EnableBuffering() before any other operation that reads the body .

Seems straight forward, but there are scenarios where this is not obvious. If you want to capture request content in the context of a API Controller action for example, you can't call Request.EnableBuffering() there, because the request likely has already been read by ASP.NET for model binding. If you need to capture request data after ASP.NET has captured it, you will have to find a way to set Request.EnableBuffering() as part of your middleware pipeline to ensure you can read request data multiple times.

In my request data capture logging scenario shown earlier this works fine, because I can plug into the ASP.NET middleware pipeline early enough to guarantee that buffering is enabled before the controller model binding gets a hold of the request buffer. The downside is that you basically end up buffering every request and with that comes a little bit of extra request overhead both in performance and resources usage (especially if you have large POST buffers for things like uploads).

To put it all together:

If you use a Stream reader of some sort make sure you set it to leave the stream open after you're done, or else the reader will close it and that also will break subsequent access to the stream.

I can now read the request data for logging and get the request data to show up in the controller:

Working  Post Data

Read Request Data Helper

I already mentioned the request helper to read the content above, but there are some improvements since the version from the last post that includes support for enabling buffering as part of the HttpRequest extension method.

Here's the updated version from Westwind.AspNetCore :

By using this you can simplify the middleware code from before to:

With the enableBuffering flag on, buffering is enabled if it's not already on, and the stream is automatically reset at the end of the read operation so that a potential secondary read can be done.

The same caveat as before applies: enableBuffering may have no effect if you do it too late in the pipeline, if ASP.NET has already processed the request data.

For example, I couldn't do this:

because ASP.NET has already read the request. If I want this to work I have to add some explicit middleware prior to the controller processing to enable buffering separately:

With that in place, the previous code works and retrieve both the model data and read the body string for a second read.

Reading raw request content is not the most straight forward operation in ASP.NET core, as it's hidden away behind the more approachable model binding approaches. And rightly so, as reading raw request content tends to be relatively infrequent, and usually related to custom auditing or logging requirements more so than actual request semantics.

In this post I've covered one of the caveats with raw Request.Body access related to reading the request content multiple times. Thankfully recent versions have made this easier via Request.EnableBuffering() but even so you have to understand how to take advantage of this functionality and where to apply it for multiple request access to work. This post provides what you need to know and some practical code you can use or build on to be on your way for multiple reqeuest access...

  • HttpRequest.EnableBuffering() Documentation
  • Accepting Raw Body Content in ASP.NET Core Controllers
  • Westwind.AspNetCore library
  • GetRawBodyStringAsync()
  • GetRawBodyBytesAsync()

writing custom middleware in asp net core

Other Posts you might also like

  • HSTS: Fix automatic re-routing of http:// to https:// on localhost in Web Browsers
  • Map Physical Paths with an HttpContext.MapPath() Extension Method in ASP.NET
  • Keeping Content Out of the Publish Folder for WebDeploy
  • Back to Basics: Rewriting a URL in ASP.NET Core

Make Donation

The Voices of Reason

writing custom middleware in asp net core

# re: Reading Raw ASP.NET Request.Body Multiple Times

EnableBuffering has an overload to specify the memory buffer size. Would prefer that over using a file baked buffer if the size and RPS fit.

writing custom middleware in asp net core

@kapsiR - good catch. Might be useful to add that as another optional parameter to the helper.

IMAGES

  1. Writing Custom Middleware in ASP.NET Core 6.x-iaspnetcore.com

    writing custom middleware in asp net core

  2. How to create custom Middleware in ASP.NET Core Request Pipeline

    writing custom middleware in asp net core

  3. #38: Create Custom Middleware In Asp.Net Core Web API

    writing custom middleware in asp net core

  4. How To Create Custom Middleware In Asp Net Core

    writing custom middleware in asp net core

  5. Creating Custom Middleware in ASP.NET Core (Part 1)

    writing custom middleware in asp net core

  6. Middleware in ASP .NET Core 3.1

    writing custom middleware in asp net core

VIDEO

  1. Learn ASP NET 2008 Part 128

  2. ASP. NET Tutorials

  3. C# ASP.NET Core MVC

  4. Middleware in ASP.NET Core

  5. CRUD Operation In Asp.Net Core Edit, Update, And Delete Operation #aspdotnetcore #biharideveloper

  6. ASP NET Core 7 Custom Middleware

COMMENTS

  1. Write custom ASP.NET Core middleware

    ASP.NET Core provides a rich set of built-in middleware components, but in some scenarios you might want to write a custom middleware. This topic describes how to write convention-based middleware. For an approach that uses strong typing and per-request activation, see Factory-based middleware activation in ASP.NET Core. Middleware class

  2. Add custom middleware in ASP.NET Core application

    Add Custom Middleware in ASP.NET Core Application Here, you will learn how to create and add your own custom middleware into the request pipeline of ASP.NET Core application. The custom middleware component is like any other .NET class with Invoke () method.

  3. Custom Middleware in ASP.NET Core

    Step1: Inject the service to the built-in dependency injection container Remember if you want to use any custom service, before using it, you must inject the service into the built-in IoC Container. You can inject the service using the ConfigureService method of the Startup class as services.AddTransient<MyCustomMiddleware1> ();.

  4. Best Practices for Developing Middleware in ASP.NET Core

    Writing custom middlewares provides a powerful way to extend and enhance the functionality of your ASP.NET Core application's request pipeline.

  5. Custom middleware in an ASP.NET Core application

    Custom middleware in ASP.NET Core allows developers to execute code before or after the request-response cycle. It provides a flexible and extensible way for developers to add custom functionality to their applications.

  6. How to build custom middleware in ASP.NET Core

    { app.UseDeveloperExceptionPage(); app.UseStaticFiles(); app.UseMvcWithDefaultRoute(); } The above code snippet illustrates how you can add MVC to the ASP.NET Core request execution pipeline....

  7. How to Create a Custom ASP.NET Core Middleware

    Step 1: Create a Middleware Class. Create a new class that will represent your middleware. You can name it anything you want, but for this tutorial, we'll name it "CustomMiddleware". The constructor of the middleware class takes a parameter of type RequestDelegate. This delegate represents the next middleware in the pipeline.

  8. Creating Custom Middleware In ASP.Net Core

    Basic Configuration The easiest way to get started with middleware is in the Configure method of your startup.cs file. In here is where you "chain" your pipeline together. It may end up looking something like the following : public void Configure(IApplicationBuilder app) { app.UseStaticFiles(); app.UseMvcWithDefaultRoute(); }

  9. 3 Ways To Create Middleware In ASP.NET Core

    Adding Middleware With Request Delegates. The first approach to defining a middleware is by writing a Request Delegate. You can do that by calling the Use method on the WebApplication instance and providing a lambda method with two arguments. The first argument is the HttpContext and the second argument is the actual next request delegate in ...

  10. An Absolute Beginner's Tutorial on Middleware in ASP.NET Core/MVC

    implementing the timingmiddleware. the sole purpose of this middleware is to inspect the request and response and log the time that this current request took to process. let's define it as inline ...

  11. Writing Custom Middleware in ASP.NET Core 1.0

    Writing Custom Middleware in ASP.NET Core 1.0 8 years ago by Matthew Jones ∙ 8 min read Originally published 8 years ago ∙ 8 min read ∙ One of the new features from ASP.NET Core 1.0 is the idea of Middleware. Middleware are components of an application that examine the requests responses coming in to and going out from an ASP.NET Core application.

  12. Create Custom Middleware In An ASP.NET Core Application

    First, we will create a simple ASP.NET Core MVC application, as shown below: Next, we will create a new folder called "Middlewares" in the main project, as shown below: Next, we will add a new Middleware component by adding a new item: Now, we will add the below code: using System.Diagnostics; using System.IO; using System.Threading.Tasks;

  13. ASP.NET Core Middleware

    ASP.NET Core Middleware is software integrated inside the application's pipeline that we can use to handle requests and responses. When we talk about the ASP.NET Core middleware, we can think of it as a code section that executes with every request.

  14. Add Custom Middleware In ASP.Net Core 6 App

    ASP.NET Core provides a rich set of built-in middleware components, but in some scenarios, you may need to write custom middleware. Let's see with a practical example Learn how to create your own custom middleware and add it to your ASP.NET Core application's request pipeline.

  15. An Absolute Beginner's Tutorial on Middleware in ASP.NET Core/MVC (and

    Download source code - 1.6 MB Introduction In this article, we will try to understand the concept of middleware in ASP.NET core. We will see how middleware plays an important part in request response pipeline and how we can write and plug-in our custom middleware. Background

  16. ASP.NET Core Middleware with Examples

    So, the ASP.NET Core Middleware Components are the software components (technically, components are nothing but the Methods) that are configured into the Application Request Processing Pipeline to handle the HTTP Requests and Responses. Middleware components are executed in the order they are added to the pipeline, and each middleware component ...

  17. Styles of Writing ASP.NET Core Middleware

    In-Line Middleware. You can write your middleware directly inside an anonymous function (or method) that gets passed to the Use method via a delegate parameter. The call to the Use method is written inside the Configure method of the Startup class (on via the Configure method on the HostBuilder).

  18. ASP.NET Core

    There are 2 ways to create Custom Middleware in Asp.net Core. Using IMiddleware interface Using the extension method. Let's try to learn how to create custom middleware using IMiddelware Interface the below example, Step 1 Create a class and name it " CustomeMiddlewareDemo " namespace WebApplication1 { public class CustomMiddlewareDemo {} } Step 2

  19. re writing response body asp.net core custome middleware

    I have created custom middleware asp.net core to modify response body but response is blank on client side after context.Response.Body = data; seems to not work any help on this is appreciated c#

  20. asp.net core

    Adding Response Headers with Custom Middleware Asp.Net-Core. 1. Modify response using middleware in ASP.NET Core 3. 12. re writing response body asp.net core custome middleware. 1. Adding an Attribute for Response processing. 0. Replacing Request/Response Body in asp.net core middleware. 9.

  21. How to write a middleware as custom router in asp.net core?

    1 Answer. You can create an extension method to encapsulate the router configuration. public static class HelloRouterExtensions { public static IApplicationBuilder UseHelloRouter (this IApplicationBuilder app) { var trackPackageRouteHandler = new RouteHandler (context => { var routeValues = context.GetRouteData ().Values; return context ...

  22. Introducing ASP.NET Core metrics and Grafana dashboards in .NET 8

    Grafana gives you the power to build exactly what you want, but it takes time to build high-quality dashboards. As part of adding metrics in .NET 8, the .NET team created pre-built dashboards designed for ASP.NET Core's built-in metrics. The ASP.NET Core Grafana dashboards are open source on GitHub and available for download on grafana.com ...

  23. AddMiddlewareAnalysis does not detect custom middleware #54166

    Middleware 'Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+InterfaceMiddlewareBinder+<>c__DisplayClass2_0' Expected Behavior. Output must also include custom middleware(s) and not just asp.net core built in middleware. Additionally clean up the naming with proper description. Steps To Reproduce

  24. Preventing redirects from URL parameter in ASP.NET Core 7.0 MVC app

    at work we have an ASP.NET Core 7.0 MVC app. It is a CMS with sites for several brands across many cultures, so there are a lot of URL variants used. ... From logs I can see that every single undesired URL which enters said middleware is the blocked, but the problem is some redirections are happening even before the middleware (which is placed ...

  25. Reading Raw ASP.NET Request.Body Multiple Times

    Some time ago I wrote about retrieving raw HTTP request content from an incoming request and - surprisingly - it's one of the most popular posts on this blog. The post discusses a few ways how you can capture raw request content in ASP.NET Core applications in situations when traditional model binding/mapping doesn't work and you need to access the underlying raw request data.