Interpretation of ASP.net 5 & MVC6 Series (6): Middleware Details _ self-study process

Source: Internet
Author: User
Tags abstract error handling httpcontext

In the 1th chapter of project structure analysis, we mentioned that Startup.cs as the entry point for the entire program, it is equivalent to the traditional Global.asax file, that is, to initialize the system-level information (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 the ASP.net 5 and previous versions is a new rewrite of the HTTP pipeline, in which the request filter is typically HttpModule used for module components, which HttpApplication respond to events within the defined cycle, to implement authentication, global error handling , log and other functions. The traditional form form authentication is one HTTPModule . HTTPModulenot only can Request you filter the request, it can also interact with the Response response and modify it. These HttpModule components inherit from the IHttpModule interface, which is located System.Web.dll in.

HttpModule code can be added not only in each event cycle in Global.asax, but also as a separate class library and registered in Web.config.

The new version of ASP.net 5 abandons the heavyweight System.Web.dll, and accordingly introduces Middleware the concept of the Middleware official definition as follows:

Pass through components this 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, inserting multiple middleware components for a specific purpose to check the request and response responses
Check, route, or modify.

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

Registration and configuration of middleware

In Asp.net5, the request requests pipeline (Pipeline) is accessed in the Startup class, which is a contract class, and the ConfigureServices methods, Configure methods, and corresponding parameters are agreed in advance, so no changes can be made.

Dependency processing in Middleware: Configureservices method

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

ADD MVC Services to the Services container.
Services. Addmvc ();

The code in the example is used to add the service type associated with the MVC module to the system to support the MVC feature, which is an extension method for adding multiple types associated with MVC in 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 IApplicationBuilder parameter of the type is used to build the configuration information for the entire application, and IHostingEnvironment the parameters of the class are env used to access the content of the system environment variable, and the ILoggerFactory type of loggerfactory content processing for the log, which IApplicationBuilder The parameters of a type are most important, and the parameter instance has a series of extension methods for registering various middleware into the request pipeline (Pipeline). The main difference between this approach and the HTTP pipeline in the previous asp.net is that the composite model in the new version replaces the event model in the old version. This also requires that in the new ASP.net, the order of the middleware component registration is important because the latter component may have to be used to the previous component, so it must be registered in the order of dependency, for example, the template code example for 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 example, the extension method, which is all in the extension method, UseStaticFiles UseIdentity UseMvc IApplicationBuilder will register the new middleware by calling the extension method app.UseMiddleware method and eventually calling the method, app.Use which 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 type of value. RequestDelegateThe source code is as follows:

Public delegate Task Requestdelegate (HttpContext context);

By source, 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 the type. That RequestDelegate is, a function that can return a RequestDelegate function of its own type, The entire asp.net is the construction of the pipeline (Pipelien) in this way, 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 the common HttpRequest and instance objects that we normally manipulate HttpResponse .

Note: HttpContext , HttpRequest HttpResponse in asp.net 5, are new types that are redefined.

Definition of middleware

Since every middleare is Func<RequestDelegate, RequestDelegate> an instance, is that not middleware definition to satisfy a rule? Is it inherited from an abstract base class or is it an excuse? By looking up the relevant code, we see that the middleware is defined on the basis of the contract, the specific rules are as follows:

The first parameter of the constructor must be the next processing function in the pipeline, that is, the requestdelegate; You must have an Invoke function, 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;//Receive incoming requestdelegate instance
 } public

 Async Task Invoke (HttpContext context)
 {
  //process code, such as processing context. The content in the request is

  Console.WriteLine ("Middleware starts processing");

  Await _next (context);

  Console.WriteLine ("Middleware End Processing");

  Process code, such as handling the context. Content in response
 }
}

The template code can be seen, first of all, a middleware constructor to receive a Requestdelegate instance, first save in a private variable, and then by calling Invoke the method (and receiving HttpContent the instance) and return a Task , And in the calling Invoke method, to pass the await _next(context); statement, chained 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 the page, first, we 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} ms </div></body>;
  var text = string. Format (Newdiv, SW. Elapsedmilliseconds);
  Await context. Response.writeasync (text);
 }

There are many ways to register a middleware, as follows is an instance-type registration code:

App. Use (Next => new Timerecordermiddleware (next). Invoke);

Alternatively, you can use the Usemiddleware extension method for registration, as shown in the following example:

App. Usemiddleware<timerecordermiddleware> ();
App. Usemiddleware (typeof (Timerecordermiddleware)); Both ways can be

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

public static Iapplicationbuilder Usetimerecordermiddleware (this iapplicationbuilder app)
{return
 app. Usemiddleware<timerecordermiddleware> ();
}

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

public void Configure (Iapplicationbuilder app, Ihostingenvironment env, iloggerfactory loggerfactory)
{
 app. Usetimerecordermiddleware (); To put it in front for statistics, if you put it behind MVC, you can't count the time.

 //etc.
}

Compile, restart, and access the page, at the bottom of the page you can see the content of the page's running time.

Use of common middleware functions

App. Useerrorpage ()
In the case of ihostingenvironment.environmentname as development, the error message is displayed, and the type of display of the error message can be set by the additional errorpageoptions parameters, you can set up all the display, or you can set only show co One or more of the Okies, Environment, Exceptiondetails, Headers, Query, SourceCode sourcecodelinecount.

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

App. Usestaticfiles ()
Opening a static file can also take the function of the pipeline pipeline processing process.

App. Useidentity ()
Turn on the ASP.net identity authentication feature based on cookies to support pipeline request processing.

To define middleware functions directly using delegates

Since middleware is an Func<RequestDelegate, RequestDelegate> instance of a delegate type, we can also do without having to define a separate class, in the Startup class, by using the delegate invocation, as the following example:

public void Configure (Iapplicationbuilder app, Ihostingenvironment env, iloggerfactory loggerfactory)
{
 app. Use (New Func<requestdelegate, requestdelegate> (next => content => Invoke (next, content));
 Other
}

//Note the parameters of the Invoke method
private Async Task Invoke (requestdelegate Next, HttpContext content)
{
 Console.WriteLine ("Initialize component Start");
 Await next. Invoke (content);
 Console.WriteLine ("Pipe Next Step execution Complete");
}

Make a simple middleware base class

Although there are agreed methods, but sometimes we are in the development of the time will be confused, can not remember what kind of agreement, so, here we could define an abstract base class, and then all the middleware at the time of definition will inherit the abstract class and overload Invoke method, So as to avoid the problem of the agreed to forget. The code is as follows:

<summary>
///Abstract base class
///</summary> public
abstract class Abstractmiddleware
{
 Protected requestdelegate Next {get; set;}
 Protected Abstractmiddleware (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.");
 }

Use the same method as above.

Terminates a chained call or blocks all middleware

In some cases, of course, according to certain conditions after the judgement, may not need to continue to go on, but to think of a 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 might want to implement the functionality of the handler in the previous release, that is, not often any pipeline directly respond to response, The new ASP.net provides a run method to implement this feature, and you can achieve similar content output by invoking the following code in the Configure method.

App. Run (Async context =>
{context)
 . Response.ContentType = "text/html";
 Await context. Response.writeasync ("Hello world!");

For information on asp.net 5 runtime, please visit: https://msdn.microsoft.com/en-us/magazine/dn913182.aspx

Legacy issues

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

var services = context.requestservices;
var services = app in Controller. ApplicationServices; Startup in

After you get the instance, you can get an object of a type by using the following methods:

var controller = (AccountController) services. GetService (typeof (AccountController));
To determine if the object being fetched is 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> (); 
To determine if the object being fetched is null

//Two, and if the AccountController instance obtained is null, the field throws an exception instead of returning the null
var Controller3 = ( AccountController) Services. Getrequiredservice (typeof (AccountController));
var controller4 = (AccountController) services. Getrequiredservice<accountcontroller> ();

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

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

How do I get a HttpContext instance?
Answer: Reference dependency injection for the general class of the injection section

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.