Last update:
Custom middleware with dependency injection in ASP.NET Core
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.
EDIT (2017-12-21): I reviewed this post to make sure everything still applies to ASP.NET Core 2.0 – and it does. There were no breaking changes in this area between 1.0 and 2.0.
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.
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:
1 2 3 4 5 6 7 8 |
app.Use(next => { return async context => { await context.Response.WriteAsync("Hello!"); await next(context); }; }); |
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:
1 2 3 4 5 |
app.Use(async (ctx, next) => { await ctx.Response.WriteAsync("Hello!"); await next(); }); |
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.
1 |
app.Run(async context => await context.Response.WriteAsync("Hello, world!")); |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class MyMiddleware { private readonly RequestDelegate _next; public MyMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { await context.Response.WriteAsync("Hello!"); await _next(context); } } |
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):
1 |
app.UseMiddleware<MyMiddleware>(); |
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:
1 2 3 4 5 6 7 8 9 10 11 12 |
public class Greeter : IGreeter { public string Greet() { return "Hello from Greeter!"; } } public interface IGreeter { string Greet(); } |
The first step is to register it in the ConfigureServices
method
1 2 3 4 |
public void ConfigureServices(IServiceCollection services) { services.AddTransient<IGreeter, Greeter>(); } |
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.
1 2 3 4 5 6 |
app.Use(async (ctx, next) => { IGreeter greeter = ctx.RequestServices.GetService<IGreeter>(); await ctx.Response.WriteAsync(greeter.Greet()); await next(); }); |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class MyMiddleware { private readonly RequestDelegate _next; private readonly IGreeter _greeter; public MyMiddleware(RequestDelegate next, IGreeter greeter) { _next = next; _greeter = greeter; } public async Task Invoke(HttpContext context) { await context.Response.WriteAsync(_greeter.Greet()); await _next(context); } } |
Or, we can add this dependency to the Invoke method:
1 2 3 4 5 |
public async Task Invoke(HttpContext context, IGreeter greeter) { await context.Response.WriteAsync(greeter.Greet()); await _next(context); } |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; namespace AspNetCoreMiddleware { public class Greeter : IGreeter { public string Greet() { return "Hello from Greeter!\n"; } } public interface IGreeter { string Greet(); } public class MyMiddleware { private readonly RequestDelegate _next; private readonly IGreeter _greeter; public MyMiddleware(RequestDelegate next, IGreeter greeter) { _next = next; _greeter = greeter; } public async Task Invoke(HttpContext ctx) { await ctx.Response.WriteAsync("MyMiddleware class says: " + _greeter.Greet()); await _next(ctx); } } public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddTransient<IGreeter, Greeter>(); } public void Configure(IApplicationBuilder app) { // IApplicationBuilder.Use app.Use( next => { return async ctx => { await ctx.Response.WriteAsync("Hello from IApplicationBuilder.Use!\n"); await next(ctx); }; }); // Use extension app.Use(async (ctx, next) => { await ctx.Response.WriteAsync("Hello from extension method Use!\n"); await next(); }); // Use extension with RequestServices app.Use( async (ctx, next) => { var greeter = ctx.RequestServices.GetService<IGreeter>(); await ctx.Response.WriteAsync(greeter.Greet()); await next(); }); app.UseMiddleware<MyMiddleware>(); // Run extension app.Run(async context => await context.Response.WriteAsync("Hello from extension method Run!\n")); } } } |
The response from this application looks as follows:
1 2 3 4 5 |
Hello from IApplicationBuilder.Use! Hello from extension method Use! Hello from Greeter! MyMiddleware class says: Hello from Greeter! Hello from extension method Run! |
To read more about dependency injection in middleware, see my other post: Dependency lifetime in ASP.NET Core.
Good post. It really helped me understand middleware clearly.
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.
I’ve just added the description of how to use middleware classes. The final output is also present.
Did you keep this updated for beta6?
Not yet. I’m quite busy right now but I’ll try to validate it and update if necessary soon.
I updated the post for beta 7.
Really great article – thanks!
Dobrze przygotowany artykuł, dzięki.
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.
ConfigureServices is used in ASP.NET Core applications (it is called automatically by the framework). Based on the Configuration method signature I assume you’re using Katana, not ASP.NET Core.
Thank you for this tutorial. But I’m a bit stucked (using ASP.NET Core 2.0). I get “InvalidOperationException: Cannot resolve scoped service ‘…’ from root provider.” as error. I tested with two services, who are added as AddScoped. When I change one to AddTransient, then it’s working. Why is this?
Another service needs DB, so I’m getting an error when changing to AddTransient – and I would not really like this.
How can I resolve this error?
Hi Matt, take a look at my recent post: https://blog.dudak.me/2018/dependency-lifetime-in-asp-net-core. I described there exactly what you ask about.
I hope what I’m about to say helps someone greatly…
IF YOU ARE PERFORMING DBCONTEXT (EF) OPERATIONS within the middleware, you may very well need to inject the repository (or DBcontext if you don’t have repositories) into the INVOKE method and NOT the constructor. If you inject into the constructor, all of your injected instances with be the same (i.e. they will all be scoped to the single middleware instance).
Obviously this is avoidable in 2.0 with IMiddleware (factory implementation), but in 1.1 that feature is not available.
Don’t do what I did, and sped 2hours trying to troubleshoot the context.
I described it more detail in my recent post: https://blog.dudak.me/2018/dependency-lifetime-in-asp-net-core
Great post!
Can we inject IApplicationBuilder in the constructor of Middleware class? I need that to resolve an interface and call a method on that to get some data.
Thank you!
Yawar
Very good, this is exactly what I want, thank you very much!
Nice explanation indeed. However, I was looking for an example of IMiddleware implementation as well which microsoft failed explain clearly in it’s documentation here.
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/extensibility?view=aspnetcore-2.1
I’m writing a middleware that is supposed to inject some information into each implementation of IService.
However, only one implementation reaches the Invoke method, although I have at least 2 implementations, like UsersService : IService, ProfileService : IService.
public async Task Invoke(HttpContext context, IService theService)
{
UserInfo serInfo = await GetUserInfoAsync(context).ConfigureAwait(false);
theService.UserInfo = userInfo;
}
Any ideas how to fix this?
If you need to get all implementations of a service, inject
IEnumerable<IService>
instead of justIService
.Well, that seems a very ugly workaround.
To check all IService implementations, when the middleware just receives one.
But anyway, I tried using IEnumerable but the same error occurs.
The UserService has the data, the ProfileService doesn’t.
So, the problem might be in the DI registration code.
I thought that’s what you were aiming for, no? I understood your middleware needs to access all the implementations of
IService
. That’s not a workaround, it’s a pretty common practice to injectIEnumerable
to receive all implementations of a service. I couldn’t find anything in the ASP.NET Core docs but Autofac allows it as well: https://autofac.readthedocs.io/en/latest/resolve/relationships.html#enumeration-ienumerable-b-ilist-b-icollection-bOk, using IEnumerable instead of IService AND registering as InstancePerLifetimeScope() (with Autofac) does solve the problem.
However, I still think there is a problem to send all the services into the middleware.
Now there are 2 services, it’s estimated to get to around 30 services.
Good one. Helped me a lot. Thank you!