Applicationbuilder (Iapplicationbuilder interface), is the basis of Owin, and inside are agents, agents, all kinds of lambda expression, estimated to see this part of the code, many people have dizzy brain rise. Today, we will explain the classes and several extension methods.
By convention first Paste code (this is I modified, the interface inheritance removed, HttpContext class modified to their own Myhttpcontext class)
Public classApplicationbuilder {Private ReadOnlyIlist<func<requestdelegate, requestdelegate>> _components =NewList<func<requestdelegate, requestdelegate>>(); PublicApplicationbuilder () {}PrivateApplicationbuilder (Applicationbuilder builder) {} PublicApplicationbuilder use (func<requestdelegate, requestdelegate>middleware) {_components. ADD (middleware); return This; } PublicApplicationbuilder New () {return NewApplicationbuilder ( This); } Publicrequestdelegate Build () {requestdelegate app= Context ={context. StatusCode="404"; System.Console.WriteLine ("404"); returnTask.fromresult (0); }; foreach(varComponentinch_components. Reverse ()) {app=component (APP); } returnapp; } }
View Code
Requestdelegate is defined as follows:
Public Delegate Task requestdelegate (myhttpcontext context);
From the source code of Applicationbuilder we can focus on 3 points: _components, use method, build method.
- _components is also a list (IList) object, but the inside type is a bit special--a proxy that takes the proxy requestdelegate as the parameter, the proxy requestdelegate as the return value. Here with the agent say a little mouth, you can call the proxy function, that is, the type is a function, the function of the parameter is also a function, the return value is also a function.
- The use method is to add a new record after the list object above.
- The build method is to make the _components array in reverse order, making it into a chain structure (something like the feeling of a linked list). The following two illustrations illustrate the following:
Before build
After build
We can also see from the code that the ITEM1 parameter gives "404" and The returned result is the Requestdelegate type. This means that this return resembles void Requestdelegate (Myhttpcontext context). If the system gives us a context variable, then the pipeline can run from beginning to end. In fact, in the ASP.NET5, this pipeline is used to replace the traditional ihttpmodule (probably inaccurate), then the problem is now, Item1 parameter is the first ring of this pipe or the last ring it? From the graph it should be the first ring, but in fact it is a misunderstanding. Because both sides of the arrow are parameters, one is the execution body (the parameter is a method that executes in the execution of the body call). In the execution of the body, the contents of the parameters may be executed at the beginning, after the execution of specific content, you can execute the specific content, then execute the parameters, and finally in the implementation of some specific content, you can do the specific content, after the parameters, but also ignore the parameters, directly directly to their own content, the previous parameters will be ignored. That is, the order, 404 may be the first ring of the pipeline, it may be the last ring, may also be intermediate links, may not be executed at all. This is related to Item1, Item2 and other content specific wording. ( Although the chain structure is not the same as the list feeling )
is not feeling too odd, source also to Applicationbuilder do two extension methods, code collation as follows:
Public Static classrunextensions { Public StaticApplicationbuilder Use ( ThisApplicationbuilder app, Func<myhttpcontext, Func<task>, task>middleware) { returnApp. Use (next = { returnContext ={Func<Task> Simplenext = () =Next (context); returnMiddleware (context, simplenext); }; }); } Public Static voidRun ( Thisapplicationbuilder app, requestdelegate handler) { if(App = =NULL) { Throw NewArgumentNullException ("Why ?"); } if(Handler = =NULL) { Throw NewArgumentNullException ("How ?"); } app. Use (_=handler); } }
View Code
First, the use method is a change to the previous use method. Change the passed-in parameter to Func<myhttpcontext, Func<task>, task>. What is the benefit of doing this? Before the Func<requestdelegate, requestdelegate> object did not give a clear sense of clarity, and Func<myhttpcontext, Func<task> Task> is very clear. Parameters passed in: Myhttpcontext is the context object,func<task> is the executor of next. The return value is a task (similar to void). Glance.
Besides the run method, it is obvious that the Run method only executes its own content and does not execute the parameter body. So the chain structure in front of it will be discarded, will not be executed.
Finally put your own test examples, for everyone's reference
Example 1:
Static voidMain (string[] args) {Myhttpcontext Context=NewMyhttpcontext () {StatusCode ="A" }; Func<myhttpcontext, Func<task>, task> middleware =(x, y)= = {context. StatusCode + ="C"; System.Console.WriteLine (context. StatusCode);returny ();}; Func<myhttpcontext, Func<task>, task> middleware2 =(x, y)= = {context. StatusCode + ="End1"; System.Console.WriteLine (context. StatusCode);returnTask.fromresult (0); }; Applicationbuilder Builder=NewApplicationbuilder (); Builder. Use (Next= { return(Myhttpcontext o) ={O.statuscode+="B"; System.Console.WriteLine (context. StatusCode); Next (O); returnTask.fromresult (0); }; } ); Builder. Use (middleware); //Builder. Use (Middleware2); //Builder. Use (middleware); //Builder. Run (o = = {O.statuscode + = "End2"; return Task.fromresult (0);});Builder. Build (). Invoke (context); System.Console.ReadLine (); }
View Code
Execution Result:
Example 2:
Static voidMain (string[] args) {Myhttpcontext Context=NewMyhttpcontext () {StatusCode ="A" }; Func<myhttpcontext, Func<task>, task> middleware =(x, y)= = {context. StatusCode + ="C"; System.Console.WriteLine (context. StatusCode);returny ();}; Func<myhttpcontext, Func<task>, task> middleware2 =(x, y)= = {context. StatusCode + ="End1"; System.Console.WriteLine (context. StatusCode);returnTask.fromresult (0); }; Applicationbuilder Builder=NewApplicationbuilder (); Builder. Use (Next= { return(Myhttpcontext o) ={O.statuscode+="B"; System.Console.WriteLine (context. StatusCode); Next (O); returnTask.fromresult (0); }; } ); Builder. Use (middleware); Builder. Use (Middleware2); //Builder. Use (middleware); //Builder. Run (o + = {O.statuscode + = "End2"; System.Console.WriteLine (context. StatusCode); Return Task.fromresult (0); });Builder. Build (). Invoke (context); System.Console.ReadLine (); }
View Code
Execution Result:
Example 3:
Static voidMain (string[] args) {Myhttpcontext Context=NewMyhttpcontext () {StatusCode ="A" }; Func<myhttpcontext, Func<task>, task> middleware =(x, y)= = {context. StatusCode + ="C"; System.Console.WriteLine (context. StatusCode);returny ();}; Func<myhttpcontext, Func<task>, task> middleware2 =(x, y)= = {context. StatusCode + ="End1"; System.Console.WriteLine (context. StatusCode);returnTask.fromresult (0); }; Applicationbuilder Builder=NewApplicationbuilder (); Builder. Use (Next= { return(Myhttpcontext o) ={O.statuscode+="B"; System.Console.WriteLine (context. StatusCode); Next (O); returnTask.fromresult (0); }; } ); Builder. Use (middleware); //Builder. Use (Middleware2); //Builder. Use (middleware);Builder. Run (o + = {O.statuscode + ="End2"; System.Console.WriteLine (context. StatusCode);returnTask.fromresult (0); }); Builder. Build (). Invoke (context); System.Console.ReadLine (); }
View Code
Execution Result:
[ASP. 5] Applicationbuilder detailed