How is the pipeline built up?
In the how is the pipeline handling HTTP requests? , we have detailed the structure of the request processing pipeline for ASP. NET core and the process of processing the request, and then we need to understand how such a pipeline is built. Such a pipeline consists of a server and a HttpApplication, which is responsible for listening to the request and passing the received request to the Httpappkication object processing, which delegates the request processing task to the registered middleware to complete. The registration of middleware is done by Applicationbuilder objects, so let's look at what this is all about.
Directory
Applicationbuilder
Startuploader
Webhost
Wehostbuilder
Summarize
First, Applicationbuilder
What we call Applicationbuilder is a general designation of all the types and their objects that implement the Iapplicationbuilder interface. The startup type registered on the Webhostbuilder has a configure method for the value of the pipe, which uses the Applicationbuilder object as a parameter to register the middleware. Since Applicationbuilder has a direct relationship with the middleware that makes up the pipeline, we have to first say what kind of object the middleware embodies in the pipeline.
The middleware is represented as a delegate object of type func<requestdelegate,requestdelegate> in the request processing flow, which may be a little difficult to understand for many readers who have just contacted the request processing pipeline. So Junglaillo for explanation. We've already mentioned requestdelegate. A delegate that is equivalent to a func
In most applications, we register a number of different middleware for specific request processing requirements, which are arranged in order of registration time and form what we call the request processing pipeline. For a middleware, after it has completed its own request processing task, it needs to pass the request to the next middleware for subsequent processing. The Requestdelegate object in func<requestdelegate,requestdelegate> as the input parameter represents a delegate chain, which embodies the processing of the request by the following middleware. The current middleware adds its own implementation of the request processing task to the delegate chain, and the returned Requestdelegate object represents the most recent delegate chain.
As an example of the pipeline shown on the right, if a func<requestdelegate,requestdelegate> is used to represent middleware B, then the Requestdelegate object as an input parameter represents the C-to-request processing operation. The return value represents both B and C processing operations at the request. If a func<requestdelegate,requestdelegate> represents the first middleware to receive requests from the server (for example, a), Then the requestdelegate returned by executing the delegate object actually represents the entire pipeline processing of the request.
After a good understanding of the middleware, let's look at the definition of the Iapplicationbuilder interface used to register the middleware. As shown below is the definition of the clipped Iapplicationbuilder interface, we only retain two core methods, in which the use method implements the registration for the middleware, The other build method converts all the registered middleware into a Requestdelegate object.
1:public Interface Iapplicationbuilder
2: {
3: requestdelegate Build ();
4: iapplicationbuilder use (func<requestdelegate, requestdelegate> middleware);
5:}
In terms of programming convenience, many of the pre-defined middleware have extension methods for registration, such as we call the extension method usestaticfiles to register the middleware that handles requests for static files. For the application of the published picture that we demonstrated, it also registers the middleware to process the picture request by invoking an extension method Useimages defined as follows.
1:public Static Class Applicationbuilderextensions
2: {
3: Public static Iapplicationbuilder Useimages (this iapplicationbuilder app, string directory)
4: {
5: func<requestdelegate, requestdelegate> middleware = next + =
6: {
7: Return context =
8: {
9: String fileName = context. Request.Url.LocalPath.TrimStart ('/');
Ten: if (string. IsNullOrEmpty (Path.getextension (fileName)))
One: {
: FileName + = ". jpg";
: }
: filename = path.combine (directory, filename);
: context. Response.WriteFile (FileName, "image/jpg");
: return to next (context);
: };
: };
: return app. Use (middleware);
: }
21:}
ASP. NET core uses an object of type Applicationbuilder to register the middleware by default, and we use the following code snippet to emulate its implementation logic. We use a list<func<requestdelegate, requestdelegate>> object to store all the registered middleware, and call the aggregate method to convert it to a Requestdelegate object.
1:public class Applicationbuilder:iapplicationbuilder
2: {
3: private ilist<func<requestdelegate, requestdelegate>> middlewares = new list<func< Requestdelegate, requestdelegate>> ();
5: Public requestdelegate Build ()
6: {
7: Requestdelegate seed = context = Task.run (() + = {});
8: return middlewares. Reverse (). Aggregate (seed, (next, current) = current (next));
9: }
10:
One: Public iapplicationbuilder Use (func<requestdelegate, requestdelegate> middleware)
: {
: middlewares. ADD (middleware);
: return this;
: }
16:}
ASP. NET core does not directly create a Applicationbuilder object to register the middleware, but instead uses the corresponding factory to create it. Create a factory that loves you applicationbuilder through interface iapplicationbuilderfactory, we simplify this interface in a simulated pipeline into the following form, The default applicationbuilderfactory for this interface creates an object of type Applicationbuilder directly.
1:public Interface Iapplicationbuilderfactory
2: {
3: iapplicationbuilder createbuilder ();
4:}
6:public class Applicationbuilderfactory:iapplicationbuilderfactory
7: {
8: Public iapplicationbuilder Createbuilder ()
9: {
Ten: return new Applicationbuilder ();
One: }
12:}
Second, Startuploader
A server and a set of middleware constitute the ASP. NET core HTTP request processing pipeline, the registration of the middleware is done by invoking the use method of Applicationbuilder, which is implemented in the Configure method registered as the startup type, We can abstract a call to this method into a delegate object of type action <IApplicationBuilder>. During pipeline initialization, Webhost must acquire and execute this delegate to complete the registration of the middleware. Specifically, the acquisition of this delegate object is done using a named Statuploader object.
The startuploader here is a generic term for all machine objects of all types that implement the Istartuploader interface, and we have made this interface as simplified as shown in the analog pipeline. The Istartuploader interface has the only method Getconfiguredelegate generates an action <IApplicationBuilder> based on the specified startup type. For the Startuploader class that implements the interface by default, the delegate returned by its Getconfiguredelegate method executes the Configure method defined in the specified startup type in a reflective manner. For simplicity, let's assume that the Configure method is an instance method, and the startup object can be created directly by invoking the default parameterless constructor.
1:public Interface Istartuploader
2: {
3: action<iapplicationbuilder> getconfiguredelegate (Type startuptype);
4:}
6:public class Startuploader:istartuploader
7: {
8: Public action<iapplicationbuilder> getconfiguredelegate (Type startuptype)
9: = + app = Startuptype.getmethod ("Configure"). Invoke (Activator.CreateInstance (Startuptype), new object[] {app});
10:}
Third, webhost
The request processing pipeline for ASP. NET core is created by the Webhost object that is the application host, which is a generic term for all the types and objects that implement the Iwebhost interface, and we simplify this interface in the analog pipeline by simply preserving the only method of start. As the webhost is opened due to the invocation of the Start method, the entire pipeline is built up with it.
1:public Interface Iwebhost
2: {
3: void Start ();
4:}
By the above introduction we know that the request processing pipeline can be understood as a combination of a server and a HttpApplication, when we create a server and specify a specific HttpApplication object to invoke its Start method when it starts, The pipe was built up. The creation of the server is done using Serverfactory, and the default HttpApplication type is hostingapplication.
When we create a Hostingapplication object, we need to specify a delegate object of type Requestdelegate, which is obtained by calling the Applicationbuilder build method. Represents the processing of all registered middleware for the current request. So the creation of hostingapplication requires an Applicationbuilder object, which is created by Applicationbuilderfactory. Before calling Applicationbuilder's Build method to convert the registered middleware into a requestdelegate delegate, you need to complete the registration work for the middleware. The implementation of the Configure method in the Startup type for middleware can be represented as an action <IApplicationBuilder> object, which can be obtained by Startuploader for the delegate object.
In summary, in order to create and start a server, webhost needs at least one serverfactory and applicationbuilderfactory to create the server and Applicationbuilder, A startuploader is also needed to finalize the registration of the middleware. In addition, you need to know the startup type registered to Webhostbuilder. Since dependency injection is widely applied to ASP. NET core's request processing pipeline, the first three objects are registered as services in the Di container, so webhost only need to take advantage of the ServiceProvider object to get the three objects based on the corresponding service interface.
1:public class Webhost:iwebhost
2: {
3: private IServiceProvider serviceprovider;
4: private Type startuptype;
6: Public webhost (iservicecollection appservices, Type startuptype)
7: {
8: This.serviceprovider = Appservices.buildserviceprovider ();
9: This.startuptype = Startuptype;
Ten: }
: Public void Start ()
: {
: iapplicationbuilder applicationbuilder = serviceprovider.getrequiredservice<iapplicationbuilderfactory > (). Createbuilder ();
: serviceprovider.getrequiredservice<istartuploader> (). Getconfiguredelegate (Startuptype) (Applicationbuilder);
: IServer Server = serviceprovider.getrequiredservice<iserverfactory> (). Createserver ();
: server. Start (New Hostingapplication (Applicationbuilder.build ()));
: }
19:}
This minimalist version of the Webhost class, provided by the preceding code snippet, provides the Servicecollection object and startup type that contains the original service registration through the parameters of the constructor, and we use the former to create the corresponding serviceprovider. In the Start method, we use ServiceProvider to get a Applicationbuilder object and a Startuploader object. We get a Action<iapplicationbuilder> object by invoking the Getconfiguredelegate method of the Startuploader with the start type as a parameter. Next, we call this action<iapplicationbuilder> delegate object as a parameter, which executes the Configure method defined in the startup type and ultimately applicationbuilder the middleware.
After that, we used serviceprovider to get a Servicefactory object and use it to create the server object for the code servers. In order to invoke its Start method, we need to create a Hostingapplication object as a parameter, and the latter is created with a Requestdelegate object representing all the middleware processing for the current request. This object is obtained directly by invoking the build method of the Applicationbuilder object. When the server is started due to the call of the Start method, the entire request processing pipeline is formally established.
Iv. Webhostbuilder
Webhost, the application host, created the request processing pipeline for ASP. Webhost was created by its factory webhostbuilder. Webhostbuilder is a generic term for all the types and objects that implement the Iwebhostbuilder interface, and we have made this interface a great simplification in the analog pipeline, preserving only the three method members shown in the following code fragment. The creation of the webhost is implemented by the build method, with an additional two methods (Usestartup and Useserver) for registering the startup type and the serverfactory used to create the server, respectively.
1:public Interface Iwebhostbuilder
2: {
3: iwebhostbuilder usestartup (Type startuptype);
4: iwebhostbuilder useserver (Iserverfactory factory);
5: iwebhost Build ();
6:}
Dependency injection has been greatly applied in the ASP. NET Core request processing pipeline, and the creation of the Servicecollection object provided by Webhost was originally provided by Webhostbuilder. The series of service objects (Applicationbuilderfactory and Startuploader) used by webhost to build the pipeline are initially registered by Webhostbuilder with this Servicecollection object. All of this is reflected in the Webhostbuilder type that is used by default, as shown below.
1:public class Webhostbuilder:iwebhostbuilder
2: {
3: private Type startuptype;
4: private iservicecollection services;
6: Public Webhostbuilder ()
7: {
8: services = new Servicecollection ()
9: . Addtransient<istartuploader, Startuploader> ()
Ten: . Addtransient<iapplicationbuilderfactory, applicationbuilderfactory> ();
One: }
: Public iwebhost Build () = new webhost (services, This.startuptype);
: Public Iwebhostbuilder Useserver (Iserverfactory Factory)
: {
: Services. Addsingleton<iserverfactory> (Factory);
: return this;
: }
20:
: Public Iwebhostbuilder Usestartup (Type startuptype)
: {
: this.startuptype = Startuptype;
: return this;
: }
26:}
V. Summary
To sum up, we have a certain understanding of how the ASP. NET core application uses Webhostbuilder to finally build the process of request processing pipeline and the process of processing requests by the pipeline itself, now let's make a simple summary. The request processing pipeline involves four core objects, namely Webhostbuilder, webhost, Server, and HttpApplication, which have a relationship of 11. We create the webhost through Webhostbuilder and lead the latter to build the request processing pipeline.
The request processing pipeline consists of a server and a HttpApplication object, which encapsulates all the registered middleware. When Webhost is started, it creates the server and HttpApplication objects and calls the server's Start method as a parameter to start the server. The startup server opens a listen request and uses HttpApplication to process the received request. When HttpApplication completes all the request processing work, it uses the server to complete the final response to the request.
All of the content described above is presented for our custom simulation pipeline, although we have greatly simplified the analog pipeline, but it still embodies the real process of ASP. NET core pipeline processing request, and the real pipeline is created in the same way as the analog pipeline. If the reader's friends can have a deep understanding of this analog pipeline, I believe it will be very easy to grasp the real pipe.
I. Using pipelines to process HTTP requests
Second, create a "mini-version" of the pipeline to simulate the real pipeline request processing process
Third, how the pipeline handles HTTP requests
Iv. how the pipeline was created
How is the pipeline built up?