Custom middleware with dependency injection in ASP.NET Core

This article was posted by Michał Dudak on 2014-12-23 in ASP.NET

It is likely that a lot of ASP.NET Core projects will need to use custom middleware. In this post I will describe what are the simplest ways of creating an own ASP.NET Core middleware and using the built-in dependency injection system.

EDIT (2016-10-24): This article was updated to reflect changes in recent versions of ASP.NET Core 1.0.  I’ll keep it updated when newer versions are released.

Middleware

So, first, what is a middleware? In OWIN world (including ASP.NET Core), similarly to other web frameworks like node.js’ express, middleware is basically a piece of code that may be used to process a request. Middleware functions are usually chained together and it’s up to them to decide whether to invoke the next one in the chain.

mware

When a request comes into the application, the first middleware function is executed. Let’s say it contains some logging logic. It logs request properties and invokes the next middleware in the chain. The next one deal with authentication. It may check if a particular cookie is present in the request and either pass the control to the next middleware or set a 401 HTTP code and return the response. Before the response is actually returned, it is passed through all the functions that are earlier in the chain (the logger in our case).

In ASP.NET Core middleware functions are defined in the Configure method of the Startup class. This method is executed automatically by the framework when your application starts (there is also another method, ConfigureServices, but we’ll get to that). In this method the framework provides the IApplicationBuilder instance containing several useful properties and methods:

IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
This is the most important method for us at the moment. It registers a new middleware function adding it to the end of the chain.
IServiceProvider ApplicationServices { get; set; }
Inversion of control container. We’ll use this object to create instances of classes required by the middleware.
IDictionary<string, object> Properties { get; set; }
Initially this dictionary contains just the IServerInformation and IServiceProvider instances (which are the same objects returned by the properties described above). It can be used to store additional application-wide settings.
IApplicationBuilder New()
Creates a new instance of IApplicationBuilder. Currently I can’t think of a use case for it.
RequestDelegate Build()
Chains the registered middlewares and returns them as a single RequestDelegate.

The method we need to register our own middleware is Use. It accepts a single parameter – Func<RequestDelegate, RequestDelegate>, which is a function that takes a RequestDelegate and returns a RequestDelegate. But what RequestDelegate is? It’s a function that takes a HttpContext as a parameter and returns a Task instance. So, ultimately, the Use method requires a function that requires a function and returns a function… It surely looks pretty complicated and the implementation can take a few lines:

Not pretty at all. But let’s break it down anyway. The app.Use method is provided a lambda representing Func<RequestDelegate, RequestDelegate>. Its parameter, next, is the next middleware in the chain. In line 3 we’re creating and returning a new RequestDelegate. It accepts a context (an HttpContext instance), an object that we can finally be productive with. In my example, a “Hello!” string is written in response to every request, then another middleware is executed. If there is no other middleware in the chain, a framework-provided one will be executed (it just returns 404 status code).

Anyway, these 9 lines of code are certainly not something we’d like to write each time a new middleware is to be registered. Fortunately, alternatives do exist. The Microsoft.AspNetCore.Builder namespace that is home to the IApplicationBuilder contains a class with several extension methods that make our work easier. Let’s see how the above code may look:

5 lines, not bad. Here we just need to provide a function accepting both the HttpContext and the next middleware and returning a Task. No more nested lambdas, this looks a lot cleaner.

But can we do even better? Sometimes we can. If we’re going to write the last middleware in the chain (i.e. we do not intend to call next()), we can use the Run extension method. It’s like Use without the next parameter.

Both of these extension methods call the IApplicationBuilder.Use under the covers, so there’s no magic involved. I encourage you to take a look at the source code and see how it’s built (it’s open source, after all; let’s take advantage of it!).

There is yet another way of creating an own middleware, that allows you to encapsulate the logic in a class. Such a class class must have an Invoke method accepting an HttpContext as a first argument. This seems to be a great way to create reusable middleware for sharing across projects.

The class must have a constructor accepting a RequestDelegate instance. It can be used inside an Invoke method to call the next middleware in the chain.

As I stated before, the class must have a single Invoke method that returns a Task and accepts an HttpContext parameter. Why don’t we have an IMiddleware interface, then? – you may ask. The reason for this is dependency injection. As it turns out, we may add additional parameters to the Invoke method or the constructor. They will be resolved by the DI containter. I’ll describe it below in more detail. This made it impossible to create a common interface.

Registering such a class is possible via the IApplicationBuilder.UseMiddleware method (or its generic equivalent):

Dependency injection

Rarely (if at all) our code is as simple as shown on the examples above. In real world projects, middleware need to call methods from other objects. Of course we can create these dependent objects inside a middleware but thanks to built-in dependency injection system, we’re able to write more elegant code.

The first step is to register classes in the IoC container. I’ve mentioned the ConfigureServices method earlier – that’s the place for it. The ConfigureServices method is executed by the framework before Configure, so that all the dependencies are ready to be used in middleware.

Let’s have a Greeter class:

The first step is to register it in the ConfigureServices method

I used the AddTransient method which creates a new instance of the class each time it’s requested. The other options are AddSingleton, AddScoped or simple Add (which all of the former use under the covers). I won’t go into detail about these methods here as the whole DI system is described in the official docs. They all work pretty much the same as their equivalents in other DI frameworks (which, by the way, you can use in ASP.NET Core as well).

After we’ve got our dependencies registered, we finally can use them. The IApplicationBuilder instance available in Configure method has a handy RequestServices property which we can use to get our Greeter instance. Since we’ve registered the IGreeter interface, we don’t have to couple the middleware with the concrete Greeter implementation.

If the Greeter class had a parametrized constructor, its dependencies also would have to be registered within ConfigureServices.

Resolving dependencies is even easier with middleware classes. As I described in the previous section, we may add additional parameters to the middleware constructor:

Or, we can add this dependency to the Invoke method:

If types of these parameters are known to the DI system, they will be automatically resolved when the class is instantiated. It’s that simple.

Here’s the whole example:

The response from this application looks as follows:

 

10 comments

  1. Alex says:

    Good post. It really helped me understand middleware clearly.

  2. Ben says:

    Excellent post, has helped me understand the basics of middleware in ASP.NET 5 and how it’s implemented. One thing to add, it would be useful to see what the output should be of your finished example.

    1. I’ve just added the description of how to use middleware classes. The final output is also present.

  3. eXor says:

    Did you keep this updated for beta6?

    1. Not yet. I’m quite busy right now but I’ll try to validate it and update if necessary soon.

    2. I updated the post for beta 7.

  4. Mark Eastwood says:

    Really great article – thanks!

  5. Marzenka says:

    Dobrze przygotowany artykuł, dzięki.

  6. Rems says:

    Thanks for the article.
    I am using OWIN with the method public void Configuration(IAppBuilder appBuilder) in my StartUp class.
    I have added the method ConfigureServices(IServiceCollection services) in my Startup class as well but it does not get called at Startup.
    How to have both functions called at startup?
    Thank you.

    1. ConfigureServices is used in ASP.NET 5 applications (it is called automatically by the framework). Based on the Configuration method signature I assume you’re using Katana, not ASP.NET 5.

Leave a Reply

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