Interpreting ASP 5 & MVC6 Series (6): Middleware detailed

Source: Internet
Author: User

Original: Interpretation of ASP. 5 & MVC6 Series (6): Middleware detailed

In the 1th chapter of the project structure analysis, we mentioned that Startup.cs as an entry point for the entire program, it is equivalent to the traditional Global.asax file, i.e., the information used to initialize the system level (for example, the routing configuration in MVC). In this chapter we will analyze how to initialize these system-level information here.

Pipeline differences between old and new versions

The biggest difference between ASP. NET 5 and previous versions is a new rewrite of the HTTP pipeline, in previous versions, where request filters are typically HttpModule used for module components that respond to HttpApplication events that are defined within each cycle for authentication, global error handling , log and other functions. The traditional form forms authentication is one HTTPModule . HTTPModulenot only can Request the request be filtered, but it can also interact with and Response modify the response. These HttpModule components inherit from the IHttpModule interface, and the interface is System.Web.dll in.

The HttpModule code can be added not only in the various event cycles in Global.asax, but also in a separate compilation into a class library and registered in Web. config.

The new version of the ASP. NET 5 discards the heavyweight System.Web.dll, and accordingly introduces Middleware the concept, Middleware which is officially defined as follows:

Pass through components The form a pipeline between a server and application to inspect, route, or modify request and res Ponse messages for a specific purpose.
Between the pipeline pipeline between the server and the application, multiple middleware components are interspersed for a specific purpose, and the request and response responses are checked
routing, or modification.

The definition and the traditional HttpModule as well as the HttpHandler special image.

Registration and configuration of middleware

In Asp.net5, access to the request pipeline (Pipeline) is performed in the startup class, when the class is a contract class, and the ConfigureServices methods, Configure methods, and corresponding parameters in it are also pre-agreed and cannot be changed.

Dependency Handling in Middleware: Configureservices method

Dependency injection is used in the various default middleware in Asp.net5, so when using functionality in middleware, it is necessary to register the type and mapping relationships required for dependency injection in the dependency injection management system, the Iservicecollection collection, and con The Figureservices method receives a parameter of type iservicecollection, which is a collection of all registered types. Managed through the native Dependency injection component (about dependency injection in Asp.net5, which we'll explain in a separate section), within which we can add new types and type mappings to the collection, as shown in the following example:

// Add MVC services to the services container.services.AddMvc();

The code in the example is used to add an MVC module-related service type to the system to support the MVC feature, which is an extension method for adding multiple MVC-related types to the collection.

Registration and configuration of middleware: Configure method

The signature of the Configure method is as follows:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory){    // ...}

ConfigureThe method receives three parameters: the parameters of the IApplicationBuilder type are used to build the configuration information for the entire application, the parameters of the class are used to access the contents of the IHostingEnvironment env system environment variables, the ILoggerFactory type of loggerfactory content processing for the log-related, the IApplicationBuilder type of parameters is most important, The parameter instance app has a series of extension methods for registering various middleware in the request pipeline (Pipeline). The main difference between this approach and the previous HTTP pipeline in asp: The composite model in the new version replaces the event model in the old version. This also requires that in the new version of ASP. Middleware component registration is very important, because the latter component may be used to the previous component, so it must be registered in a dependent order, for example, the current MVC project template code example is as follows:

// Add static files to the request pipeline.app.UseStaticFiles();// Add cookie-based authentication to the request pipeline.app.UseIdentity();// Add MVC to the request pipeline.app.UseMvc(routes =>{ /*...*/});

In the example, the extension method, in the extension method, is UseStaticFiles UseIdentity called by the extension method method, and finally the UseMvc IApplicationBuilder method is app.UseMiddleware called app.Use to register the new middleware, the method is defined as follows:

public interface IApplicationBuilder{    //...    IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);}

By code, you can see that middleware is Func<RequestDelegate, RequestDelegate> an instance of the Func that receives a RequestDelegate parameter and returns a RequestDelegate value of type. RequestDelegateThe source code is as follows:

public delegate Task RequestDelegate(HttpContext context);

Through the source code, we can see that it RequestDelegate is a delegate function that receives an instance of the HttpContext type and returns an Task asynchronous object of type. That RequestDelegate is, a function that can return a RequestDelegate function of its own type. This is how the entire ASP. Pipelien is constructed, where each middleware is chained to the next middleware, and the object can be modified or maintained throughout the process, HttpConext of course, HttpContext Includes our often-manipulated HttpRequest and HttpResponse instance objects.

Note: HttpContext , HttpRequest HttpResponse in ASP. NET 5, are new types that are redefined.

Definition of middleware

Since each middleare is Func<RequestDelegate, RequestDelegate> an instance, is it not the definition of middleware to satisfy a rule? Is it inherited from an abstract base class or an excuse? By checking the relevant code, we see that middleware is defined in the form of a contract, with the following specific conventions:

    1. The first parameter of the constructor must be the next processing function in the processing pipeline, i.e. requestdelegate;
    2. You must have an Invoke function and accept the context parameter (that is, httpcontent), and then return to the Task;

Examples are as follows:

public class MiddlewareName{    RequestDelegate _next;    public MiddlewareName(RequestDelegate next)    {        _next = next;// 接收传入的RequestDelegate实例    }    public async Task Invoke(HttpContext context)    {        // 处理代码,如处理context.Request中的内容        Console.WriteLine("Middleware开始处理");        await _next(context);        Console.WriteLine("Middleware结束处理");        // 处理代码,如处理context.Response中的内容    }}

The template code can be seen, first of all, a middleware constructor to receive an instance of Requestdelegate, first saved in a private variable, and then by calling the Invoke method (and receiving the HttpContent instance) and returning one Task , and in the call Invokemethod, to pass the await _next(context); statement, the chain to the next middleware, our processing code is mainly in the chain statement before and after the execution of the relevant code.

For example, if we want to record the execution time of a page, first we define a timerecordermiddleware with the following code:

public class TimeRecorderMiddleware{    RequestDelegate _next;    public TimeRecorderMiddleware(RequestDelegate next)    {        _next = next;    }    public async Task Invoke(HttpContext context)    {        var sw = new Stopwatch();        sw.Start();        await _next(context);        var newDiv = @"<div id=""process"">页面处理时间:{0} 毫秒</div></body>";        var text = string.Format(newDiv, sw.ElapsedMilliseconds);        await context.Response.WriteAsync(text);    }}

There are many ways to register middleware, and the following is the instance registration code:

app.Use(next => new TimeRecorderMiddleware(next).Invoke);

Alternatively, you can register using the Usemiddleware extension method, as shown in the following example:

app.UseMiddleware<TimeRecorderMiddleware>();//app.UseMiddleware(typeof(TimeRecorderMiddleware)); 两种方式都可以

Of course, you can also define an extension method of your own to register the middleware, with the following code:

public static IApplicationBuilder UseTimeRecorderMiddleware(this IApplicationBuilder app){    return app.UseMiddleware<TimeRecorderMiddleware>();}

Finally, in the startup class of the Configure method to register, the code is as follows:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory){    app.UseTimeRecorderMiddleware(); // 要放在前面,以便进行统计,如果放在Mvc后面的话,就统计不了时间了。    // 等等}

Compile, restart, and access the page, and at the bottom of the page you will see the page's run-time prompt content.

Use of common middleware functions

App. Useerrorpage ()
In the case of ihostingenvironment.environmentname for development, the error message is displayed, and the type of error message is displayed, which can be set by an additional errorpageoptions parameter, can be set to display all, or it can be set to show only co One or more of okies, Environment, Exceptiondetails, Headers, Query, SourceCode sourcecodelinecount.

App. Useerrorhandler ("/home/error")
Captures all program exception errors and jumps the request to the specified page to achieve the purpose of friendly prompting.

App. Usestaticfiles ()
The ability to open a static file can also take the pipeline pipeline process.

App. Useidentity ()
Opens a cookie-based ASP. NET identity authentication feature to support pipeline request processing.

To define middleware functions directly using delegates

Since middleware is an instance of a Func<RequestDelegate, RequestDelegate> delegate type, we can also avoid having to define a separate class, in Startup which case it is possible to use a delegate invocation, as in the following example:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory){   app.Use(new Func<RequestDelegate, RequestDelegate>(next => content => Invoke(next, content)));   // 其它}// 注意Invoke方法的参数private async Task Invoke(RequestDelegate next, HttpContext content){   Console.WriteLine("初始化组件开始");   await next.Invoke(content);   Console.WriteLine("管道下步执行完毕");}
Make a simple middleware base class

Although there are agreed methods, but sometimes we in the development of the time often confused, can not think of what is the contract, so, here we could define an abstract base class, and then all the middleware at the time of definition to inherit the abstract class and overload the Invoke method, So you can avoid the problems that the Convention forgets. The code is as follows:

/// <summary>/// 抽象基类/// </summary>public abstract class AbstractMiddleware{    protected RequestDelegate Next { get; set; }    protected AbstractMiddleware(RequestDelegate next)    {        this.Next = next;    }    public abstract Task Invoke(HttpContext context);}/// <summary>/// 示例Middleware/// </summary>public class DemoMiddleware : AbstractMiddleware{    public DemoMiddleware(RequestDelegate next) : base(next)    {    }    public async override Task Invoke(HttpContext context)    {        Console.WriteLine("DemoMiddleware Start.");        await Next.Invoke(context);        Console.WriteLine("DemoMiddleware End.");    }}

Use the same method as above.

Terminates a chained call or blocks all middleware

In some cases, of course, according to certain conditions to judge, may not need to continue to carry on, but to the confidant to return the results, then you can ignore the call in your middleware await next.Invoke(content); , direct use · The Response.writeasync method outputs the content.

In addition, in some cases, you may need to implement a function similar to handler in previous versions, that is, not often any pipeline directly responds to response, The new version of ASP. NET provides a run method to implement this function, only need to invoke the following code in the Configure method to achieve similar content output.

app.Run(async context =>{    context.Response.ContentType = "text/html";    await context.Response.WriteAsync("Hello World!");});

For content on the ASP. NET 5 runtime, please visit: https://msdn.microsoft.com/en-us/magazine/dn913182.aspx

Legacy issues

In an MVC project, all the dependency injection types are obtained through the IServiceProvider instance, which can now be obtained in the following form:

var services = Context.RequestServices; // Controller中var services = app.ApplicationServices; // Startup中

Once the instance has been obtained, you can obtain an object of a type by using the following methods:

var controller = (AccountController)services.GetService(typeof(AccountController));// 要判断获取到的对象是否为null

If you refer to the Microsoft.Framework.DependencyInjection namespace, you can also use the following three extension methods:

var controller2 = (AccountController)services.GetService<AccountController>();  // 要判断获取到的对象是否为null//如下两种方式,如果获取到的AccountController实例为null的话,就会字段抛异常,而不是返回nullvar controller3 = (AccountController)services.GetRequiredService(typeof(AccountController));var controller4 = (AccountController)services.GetRequiredService<AccountController>();

So that's the problem? How can I get to HttpContext and Iapplicationbuilder instances in order to use these dependency injection services without the startup and controller?

    1. How do I get iapplicationbuilder instances?
      Answer: In startup, the Iapplicationbuilder instance is saved in a singleton variable, and the whole station can be used later.

    2. How do I get HttpContext instances?
      Answer: Dependency injection of a generic class referencing a Dependency injection section

Reference: Http://www.mikesdotnetting.com/article/269/asp-net-5-middleware-or-where-has-my-httpmodule-gone

Synchronization and recommendations

This article has been synchronized to the Catalog index: Interpreting ASP. & MVC6 Series

Interpreting ASP 5 & MVC6 Series (6): Middleware detailed

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.