Interpretation of ASP. NET 5 & MVC6 series (6): Explanation of Middleware and interpretation of ASP. NET

Source: Internet
Author: User

Interpretation of ASP. NET 5 & MVC6 series (6): Explanation of Middleware and interpretation of ASP. NET

In Chapter 4 project structure analysis, we mentionedStartup.csAs the entry point of the entire program, it is equivalent to the traditionalGlobal.asaxFile: used to initialize system-level information (for example, the routing configuration in MVC ). In this chapter, we will analyze how to initialize system-level information here.

Pipeline differences between old and new versions

The biggest difference between ASP. NET 5 and earlier versions is the completely new rewriting of HTTP Pipeline. in earlier versionsHttpModuleIs a module component.HttpApplicationTo implement authentication, global error processing, logs, and other functions. Traditional Form authentication isHTTPModule.HTTPModuleNot only can filterRequestAndResponseRespond to interaction and modify. These HTTPModule components are inherited from the IHttpModule interface, which is located inSystem.Web.dll.

The HttpModule code can be added in each event cycle in Global. asax. It can also be compiled into a class library separately and registered in web. config.

The new version of ASP. NET 5 abandoned the heavyweight System. Web. dll and introducedMiddlewareConcept,MiddlewareThe official definition is as follows:

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.
The Pipeline between the server and the application is interspersed with multiple Middleware components for specific purposes to check the request and response
Query, route, or modify.

This definition and the traditionalHttpModuleAndHttpHandlerSpecial image.

Middleware registration and Configuration

In ASP. NET5, the access to the request Pipeline (Pipeline) is carried out in the Startup class. This class is a convention class, andConfigureServicesMethod,ConfigureMethods and corresponding parameters are also agreed in advance, so they cannot be modified.

Dependency processing in Middleware: ConfigureServices Method

In ASP. various default Middleware in NET5 use the dependency injection function, so when using the features in Middleware, the types and mappings required for dependency injection must be registered to the dependency injection Management System in advance, that is, the IServiceCollection set. The ConfigureServices method receives a parameter of the IServiceCollection type, this parameter is a collection of all registered types. It is managed by the native dependency injection component (about ASP. dependency injection in NET5, which will be explained in a separate chapter). In this method, we can add a new type and type ing relationship to the set, for example:

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

The code in the example is used to add the Service type related to the Mvc module to the system to support the MVC function. This method is an extension method used to add multiple MVC-related types to the collection.

Middleware registration and configuration: Configure Method

The Configure method signature is as follows:

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

ConfigureThe method receives three parameters:IApplicationBuilderType parameters are used to build the configuration information of the entire application,IHostingEnvironmentClassenvParameters are used to access content related to system environment variables,ILoggerFactoryTypeloggerfactoryUsed for log-related content processing, whereIApplicationBuilderType parameters are the most important. The parameter instance app has a series of extension methods used to register various Middleware into the request Pipeline (Pipeline. The main difference between this method and the HTTP pipeline in ASP. NET is that the combined model in the new version replaces the event model in the old version. This requires that the new ASP. in NET, the Middleware component registration sequence is very important, because the latter component may need to use the previous component, so it must be registered in the order of dependency, for example, the template code example of the current MVC project 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 exampleUseStaticFiles,UseIdentity,UseMvcAllIApplicationBuilderIn the extension method, the extension method is calledapp.UseMiddlewareMethod, and then callapp.UseMethod to register a new Middleware. The method is defined as follows:

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

The Code shows that middleware isFunc<RequestDelegate, RequestDelegate>The Func receivesRequestDelegateAnd returnsRequestDelegateType value.RequestDelegateThe source code is as follows:

public delegate Task RequestDelegate(HttpContext context);

Through the source code, we can see that,RequestDelegateIs a delegate function that receivesHttpContextType instance, and returnsTaskType of asynchronous object. That is to sayRequestDelegateIs a response that can return itselfRequestDelegateType function, the entire ASP. NET is used to construct the pipeline (Pipelien). Here, each middleware is chained to the next middleware, And you canHttpConextObject modification or maintenance, of course,HttpContextWhich includesHttpRequestAndHttpResponseInstance Object.

Note:HttpContext,HttpRequest,HttpResponseASP. NET 5 is a new type that is redefined.

Definition of Middleware

Since every middleare isFunc<RequestDelegate, RequestDelegate>Is the definition of Middleware to meet a rule? Is it inherited from an abstract base class or an excuse? By looking at the relevant code, we can see that Middleware is defined based on the agreed form. The specific agreed rules are as follows:

The first parameter of the constructor must be the next processing function in the processing pipeline, that is, RequestDelegate. There must be an Invoke function that accepts the context parameter (HttpContent) and returns the Task;

Example:

Public class MiddlewareName {RequestDelegate _ next; public MiddlewareName (RequestDelegate next) {_ next = next; // receives incoming RequestDelegate instance} public async Task Invoke (HttpContext context) {// Process Code, such as processing context. request content Console. writeLine ("Middleware starts processing"); await _ next (context); Console. writeLine ("Middleware end processing"); // Process Code, such as processing context. content in Response }}

The template Code shows that a Middleware constructor needs to receive a RequestDelegate instance, save it to a private variable, and then callInvokeMethod (and receiveHttpContentInstance) and returnsTaskAndInvokeInawait _next(context);Statement, chained to the next Middleware, our processing code is mainly to execute the relevant code before and after the chain statement.

For example, to record the page execution time, first define a TimeRecorderMiddleware. The Code is as follows:

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 ""> page processing time: {0} millisecond </div> </body> "; var text = string. format (newDiv, sw. elapsedMilliseconds); await context. response. writeAsync (text );}}

There are many ways to register Middleware:

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

Alternatively, you can use the UseMiddleware Extension Method for registration, for example:

App. UseMiddleware <TimeRecorderMiddleware> (); // app. UseMiddleware (typeof (TimeRecorderMiddleware); you can use either of the following methods:

Of course, you can also define your own extension method to register the Middleware. The Code is as follows:

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

Finally, register in the Configure method of the Startup class. The Code is as follows:

Public void Configure (IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory) {app. useTimeRecorderMiddleware (); // put it in front for statistics. If it is placed behind Mvc, the time cannot be counted. // And so on}

Compile, restart, and access the page. You can see the running time prompt at the bottom of the page.

Use of common Middleware functions

App. UseErrorPage ()
In IHostingEnvironment. when EnvironmentName is Development, the error message is displayed, and the display type of the error message can be set through the extra ErrorPageOptions parameter, and all display can be set, you can also set to display only one or more Cookies, Environment, predictiondetails, Headers, Query, and SourceCode SourceCodeLineCount.

App. UseErrorHandler ("/Home/Error ")
Capture all program exception errors and redirect requests to the specified page for friendly prompts.

App. UseStaticFiles ()
You can use this Pipeline to process static files.

App. UseIdentity ()
Enable cookie-Based ASP. NET identity authentication to support Pipeline request processing.

Define Middleware using delegation directly

Because Middleware isFunc<RequestDelegate, RequestDelegate>Therefore, we do not need to define a separate class.StartupClass, you can use the delegate call method, for example:

Public void Configure (IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory) {app. use (new Func <RequestDelegate, RequestDelegate> (next => content => Invoke (next, content ))); // others} // note the parameter private async Task Invoke (RequestDelegate next, HttpContext content) {Console. writeLine ("initialization component start"); await next. invoke (content); Console. writeLine ("Pipeline completed in the Next Step ");}

Make a simple Middleware base class

Although there are agreed methods, sometimes we often get confused during development and cannot figure out what the conventions are. Therefore, here we can define an abstract base class, in the future, all Middleware will inherit this abstract class and reload the Invoke method when defining it, so as to avoid forgetting the conventions. The Code is as follows:

/// <Summary> /// abstract base class /// </summary> public abstract class implements actmiddleware {protected RequestDelegate Next {get; set;} protected implements actmiddleware (RequestDelegate next) {this. next = next;} public abstract Task Invoke (HttpContext context) ;}/// <summary> /// example 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. ");}}

The usage is the same as above.

Terminate a chain call or block all Middleware

In some cases, you may not need to continue to execute the statements based on certain conditions. Instead, you want to know your friends and return the results. In this case, you can ignoreawait next.Invoke(content);Directly use the Response. WriteAsync method to output the content.

In addition, in some cases, you may need to implement functions similar to those of handler in earlier versions, that is, you may not frequently respond to Response directly by using any Pipeline. NET provides a run method for implementing this function, you only need to call 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 about ASP. NET 5 Runtime, visit: https://msdn.microsoft.com/en-us/magazine/dn913182.aspx

Legacy problems

In the Mvc project, all dependency injection types are obtained through the IServiceProvider instance. Currently, you can obtain the instance in the following form:

Var services = Context. RequestServices; // var services = app. ApplicationServices in the Controller; // Startup

After obtaining the instance, you can use the following method to obtain a type of object:

Var controller = (AccountController) services. GetService (typeof (AccountController); // you need to determine whether the obtained object is null.

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

Var controller2 = (AccountController) services. getService <AccountController> (); // you can determine whether the obtained object is null. // If the obtained AccountController instance is null, the field throws an exception instead of returning nullvar controller3 = (AccountController) services. getRequiredService (typeof (AccountController); var controller4 = (AccountController) services. getRequiredService <AccountController> ();

Why? How can I obtain the HttpContext and IApplicationBuilder instances without Startup and Controller to use these dependency injection services?

How can I obtain an IApplicationBuilder instance?
Answer: In Startup, save the IApplicationBuilder instance to a variable in the singleton. Later, the whole site can be used.

How do I obtain an HttpContext instance?
Answer: Refer to dependency injection for common classes.

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

Related Article

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.