Middleware in ASP.Net Core refers to a piece of software code that is assembled in an app pipeline to process requests and responses. In other words, middleware determines how the application is going to react in response to HTTP requests.

Create a Custom Middleware in ASP.Net Core

Each of the components essentially performs two tasks, that of choosing whether it should pass on the request to the next component in the pipeline or it can also perform some work before and after the next component is activated in the pipeline.

A middleware in ASP.Net Core is also regarded as an object and has a very specific and limited role to play in the functioning of the application. Given its importance, ASP.Net Core comes with a library of built-in middleware components to suit a plethora of uses in an application.

However, there might also be scenarios where you might be needed to write a middleware tailor-made to suit specific requirements, something that is referred to as custom middleware.

Here is an example of the Middleware class:

As is evident below, the middleware class is usually encapsulated in a class and is exposed to an extension method. In the example below, the custom middleware sets the user-role for the current request from a query string.

public class Startup

{

    public void Configure(IApplicationBuilder app)

    {
        app.Use(async (context, next) =>

        {

            var userRole = context.Request.Query["UserRole"];

            if (!string.IsNullOrWhiteSpace(cultureQuery))

            {

                var user = new User();
                user.UserRole = userRole;

            }

            // Call the next delegate/middleware in the pipeline

            await next();

        });

        app.Run(async (context) =>

        {

            await context.Response.WriteAsync(

            $"Hello {User.UserRole}");

        });

    }

}

Example to show how Middleware delegate is moved to a class:

While the above code shows how a middleware component is created, here is another example that demos how middleware delegate is moved to a class.

using Microsoft.AspNetCore.Http;

using System.Globalization;

using System.Threading.Tasks;

namespace User

{
    public class RequestUserMiddleware

    {

        private readonly RequestDelegate _next;

        public RequestUserMiddleware(RequestDelegate next)

        {

            _next = next;

        }

        public async Task InvokeAsync(HttpContext context)

        {

            var userRole = context.Request.Query["userRole"];

            if (!string.IsNullOrWhiteSpace(userRole))

            {

                var user = new User();
                user.UserRole = userRole;

            }

            await _next(context);

        }

    }

}

Middleware class pre-requisites

As is evident above, it is imperative for the middleware class to include the following:

  • A public constructor with a parameter of type RequestDelegate.
  • A public method named Invoke or InvokeAsync. Again, this method should return a Task besides also accepting the first parameter of type HttpContext.

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

Middleware dependencies

It is also important to note that Middleware must follow the Explicit Dependencies Principle by exposing its dependencies in the constructor. There is only one middleware that is constructed in the lifetime of the application. Further, middleware components are able to resolve their dependencies from dependency injection DI by way of constructor parameters. Another method of making extra parameters to be accepted directly is by using UseMiddleware<T>.

Per-request middleware dependencies

Given that middleware is not constructed per-request but only at app startup, scoped lifetime services used by middleware constructors don’t get shared with other dependency injected types during each request. In such cases, if you are required to share a scoped service between your middleware and other types, you must add these services to the Invoke method’s signature. In that case, the invoke method can also accept additional parameters populated by DI.

Here is the sample code

public class CustomMiddleware

{

    private readonly RequestDelegate _next;
    public CustomMiddleware(RequestDelegate next)

    {

        _next = next;

    }

    public async Task Invoke(HttpContext httpContext, IMyScopedService svc)

    {

        svc.MyProperty = 1000;
        await _next(httpContext);

    }

}

Middleware extension method

Here is a sample code to demo the extension method exposing the middleware through IApplecationBuilder.

using Microsoft.AspNetCore.Builder;

namespace User

{
    public static class RequestUserMiddlewareExtensions

    {
        public static IApplicationBuilder UseRequestUser(

        this IApplicationBuilder builder)
        {

            return builder.UseMiddleware<RequestUserMiddleware>();

        }

    }

}

Here is another sample code to demo calling the middleware from Startup.Configure

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseRequestUser();
        app.Run(async (context) =>
    {
        await context.Response.WriteAsync(

        $"Hello {User.UserRole}");

    });

    }

}

Related Articles

Last modified: October 21, 2019

Comments

Write a Reply or Comment

Your email address will not be published.