I'm trying to understand the concept of middleware in MVC6. It is still kind of vague to me. I don't really see the differences between a few "standard" variables you get in the Startup
class.
As far as I can tell there are 3 different ways to tell the application that it should use a specific middleware?
You can call middleware through services using. But this seems only for "adding" middleware?
services.AddMvc();
// Add other services
services.AddScoped<IMyCountriesRepository, MyCountriesRepository>();
services.AddScoped<IEmailer, Emailer>();
Then you have IApplicationBuilder app
. This is to actually use the middleware loaded in the services? So you can call it like:
app.UseMvc();
app.UseErrorPage(...);
app.UseIdentity(); // cookie authentication
And then there is a way to load and use middleware like this:
app.UseMiddleware<MyCustomMiddleware>();
What is the benefit having three types of registering / using middleware? What is the exact differences between them?
I would distinguish between adding the services and adding the middleware.
Adding the services
This is basically registering the classes needed by your feature into the dependency injection container built in ASP .Net 5. (The IServiceCollection
interface)
The most simple thing you can do is manually add them one by one as in:
services.AddScoped<IMyCountriesRepository, MyCountriesRepository>();
services.AddScoped<IEmailer, Emailer>();
If you are building a more complex app, or a self contained framework, you might want to create a function that registers all the services needed. A good way of doing that is by creating an extension method:
public static void AddMyServices(this IServiceCollection services)
{
services.AddScoped<IMyCountriesRepository, MyCountriesRepository>();
services.AddScoped<IEmailer, Emailer>();
...
}
//register all your services just by running the ext method:
services.AddMyServices();
That is exactly what services.AddMvc();
is doing.
In a more flexible way as it allows you to pass a lambda to further customize default services like the model binders (Like
services.AddMvc(opts => opts.ModelBinders ...)
) and is returning an IMvcBuilder you can use to further customize it things like the view engines (Likeservices.AddMvc().AddViewOptions(opts => opts.ViewEngines ...)
).
- Check the implementation of
MvcServiceCollectionExtensions
andMvcCoreServiceCollectionExtensions
Adding middleware
ASP .Net 5 is not based in HTTP modules and handlers, and instead is based on the OWIN idea of middleware. There is a nice blog entry by Andrei Dzimchuk describing the middleware which nicely summarizes it:
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.
And this definition applies to ASP.NET 5 as well. Middleware can be thought of as both HTTP modules and handlers that we've had in classic ASP.NET. Some middleware would implement various intermediate tasks when processing requests such as authentication, session state retrieval and persistence, logging and so on. Some of them would be the ultimate request handlers that would produce responses.
So now you want to add your own behavior into the ASP pipeline.
The most simple thing is define an inline middleware:
app.Use(async (context, next) =>
{
//do something before passing the request to the next middleware
await next.Invoke();
});
You can also create your own middleware class and register it:
app.UseMiddleware<MyMiddleware>();
Finally, you could again define extension methods to encapsulate complex setup logic.
This is what
app.UseMvc()
does. It lets you define your routes and it is then adding the routing middleware by callingapp.UseRouter()
. As you can see, the implementation ofapp.UseRouter
adds theRouterMiddleware
into the pipeline with the call tobuilder.UseMiddleware<RouterMiddleware>(router);
Any services needed by your middleware would have previously been registered. This means they will be available to your middleware through the built in DI container.
The end result is that the framework makes easier for you to basically mix and match the components(services) and behavior(middleware) needed by your application, including only the bits that you need.