Why can we configure dependency injection and piping in startup's "Lone" class?
When was it instantiated and called?
How did the Iservicecollection services in the parameter come from?
How is the processing pipeline built up?
What preparations did the system "silently" do during the start-up process?
The previous article described the Dependency Injection (series directory) in ASP., and its configuration is the configureservices (iservicecollection Services) method in the startup file, and the startup class does not inherit any classes or interfaces. In-depth thinking, there may be a lot of problems like the one listed above, the following with a picture to see it.
First, the overall flow chart
First, I think you can click to see the big picture or to enlarge the view after downloading.
Figure One (click to enlarge)
Second, Webhostbuilder
The application creates and configures Webhostbuilder after the main method by calling the Createdefaultbuilder method,
1 Public classWebhostbuilder:iwebhostbuilder2 {3 Private ReadOnlyList<action<webhostbuildercontext, iservicecollection>>_configureservicesdelegates;4 5 Privateiconfiguration _config;6 PublicIwebhostbuilder usesetting (stringKeystringvalue)7 {8_config[key] =value;9 return This;Ten } A PublicIwebhostbuilder configureservices (Action<webhostbuildercontext, iservicecollection>configureservices) at { - if(Configureservices = =NULL) - { - Throw NewArgumentNullException (nameof (configureservices)); - } in _configureservicesdelegates.add (configureservices); - return This; to } +}
Webhostbuilder There is an important set ① private readonly list<action< Webhostbuildercontext, iservicecollection>> _configureservicesdelegates; , the required action is added through the configureservices method.
Usesetting is a method for setting up Key-value, and some common configurations are written to _config in this way.
Third, usestartup<startup> ()
After Createdefaultbuilder calls usestartup<startup> (), specify startup as the Startup class.
Public StaticIwebhostbuilder Usestartup ( Thisiwebhostbuilder Hostbuilder, Type startuptype) { varStartupassemblyname =Startuptype.gettypeinfo (). Assembly.getname (). Name; returnHostbuilder. Usesetting (Webhostdefaults.applicationkey, Startupassemblyname). Configureservices (Services= { if(typeof(IStartup). GetTypeInfo (). IsAssignableFrom (Startuptype.gettypeinfo ())) {services. Addsingleton (typeof(IStartup), startuptype); } Else{Services. Addsingleton (typeof(istartup), SP = { varHostingenvironment = sp. Getrequiredservice<ihostingenvironment>(); return NewConventionbasedstartup (Startuploader.loadmethods (SP, Startuptype, hostingenvironment.environmentname)); }); } }); }
First get the corresponding assemblyname of the startup class, and call the Usesetting method to set it to the value of Webhostdefaults.applicationkey ("applicationname").
Then call Webhostbuilder's ②configureservices method to write an action to the Webhostbuilder The configureservicesdelegates.
This action means that if the specified class Startuptype is a class that implements the IStartup, it is registered to the services servicecollection by Addsingleton, if not, Then it is "transformed" into Conventionbasedstartup, which implements the IStartup class before registering. Here comes a startuploader loadmethods () method that looks for "configureservices", "configure{ environmentname}" through a string Services "approach.
Note: This simply writes an action to Configureservicesdelegates instead of registering the IStartup because the action has not been executed and the services do not yet exist. like a bodhisattva to the eight Commandments: Eight commandments (Startup) You first wait in the GAO, in the future a monk to lead a servicecollection services to come over when you join them.
In fact, in the Createdefaultbuilder method of several Usexxx method is also this way through the configureservices will be the corresponding action written to Configureservicesdelegates, waiting for the monk's arrival.
Iv. Webhostbuilder.build ()
The creation and configuration of the Webhostbuilder begins with the build method to create the webhost, first of all buildcommonservices,
1 PrivateIservicecollection Buildcommonservices ( outaggregateexception hostingstartuperrors)2 {3 //... Omit ...4 varServices =Newservicecollection ();5 Services. Addsingleton (_hostingenvironment);6 Services. Addsingleton (_context);7 //.... Various add ....9 foreach(varConfigureservicesinch_configureservicesdelegates)Ten { One configureservices (_context, services); A } - returnservices; the}
In this method to create the Servicecollection services (to the Tang's monk-led team), and then through the various add methods to register a lot of content (Received Goku), and then ③foreach each action in the Configureservicesdelegates is previously staged, and the incoming services are executed individually, registering the content that was previously required for registration with the services, including the Startup (eight commandments), Note that this is only a method of registering and not executing the startup.
The handled services are assigned to Hostingservices after the buildcommonservices is returned , and hostingservices is generated by Clone (). ApplicationServices, and then by this applicationservices getproviderfromfactory (hostingservices) generates a IServiceProvider Hostingserviceprovider. After a series of processing, you can create a webhost.
var New webhost ( applicationservices, hostingserviceprovider, _options, _config, hostingstartuperrors); host. Initialize ();
The generated applicationservices and Hostingserviceprovider are passed as parameters to the newly generated webhost. The next step is the Webhost Initialize ().
Wu, Webhost.initialize ()
The main work of Webhost's Initialize () is buildapplication ().
ensureapplicationservices (): private IServiceProvider _applicationservices for handling webhost ,④startup's Configureservices method is called here .
_startup = _hostingserviceprovider.getrequiredservice<istartup>= _startup. Configureservices (_applicationservicecollection);
Get to our _startup by getrequiredservice<istartup> () and call this _startup's ⑤configureservices method, This is the Configureservices method we use for the startup class that relies on injection.
Therefore,_applicationservices is a iserviceprovider that is regenerated based on _applicationservicecollection plus the content we registered in _StartUp .
ensureserver ()⑥: Gets the server through Getrequiredservice<iserver> () and configures the listening address.
var builderfactory = _applicationservices.getrequiredservice<iapplicationbuilderfactory>(); var builder == _applicationservices;
Get to Iapplicationbuilderfactory and create iapplicationbuilder through it ⑦ , and create the _ ApplicationServices is assigned to its applicationservices, and it has an important set _components
Private ReadOnly New List<func<requestdelegate, requestdelegate>> ();
From the _components type we can see that it is actually a collection of middleware, is the time to call our _startup configure method.
Get the defined Istartupfilter first, ⑧foreach these istartupfilter and write the configured middleware to configure along with the _StartUp _components method, and then pass the Build () Create Requestdelegate _application,
The build request processing pipeline is processed in build () for _components, and the section on Istartupfilter and build pipeline is described in detail in the next article.
Liu, Webhost.run ()
Webhost is created, the last step is run up, Webhost's run () will call its method Startasync ()
Public Virtual AsyncTask Startasync (CancellationToken cancellationtoken =default(CancellationToken)) { //......varHostingapp =Newhostingapplication (_application, _logger, Diagnosticsource, httpcontextfactory); awaitServer.startasync (Hostingapp, CancellationToken). Configureawait (false); _hostedserviceexecutor.startasync (CancellationToken). Configureawait (false); //.....}
In the previous article we know that the request is handled by the server listener = = and processed into httpcontext=>application processing, so here first the _application created above and a httpcontextfactory to ⑨ generates a hostingapplicationand passes this hostingapplication to the Startasync () of the server, and when the server hears the request, The work behind it is done by Hostingapplication.
The ⑩hostedserviceexecutor.startasync () method is used to open a service that runs in the background, and some operations that need to be run in the background, such as periodically refreshing the cache, can be put here.
ASP. NET Core 2.0: seven. A picture sees through the secret behind the start