. NET Core Development Log--startup

Source: Internet
Author: User
Tags webhost

A typical ASP. NET core application will contain program and startup two files. The program class has an entry method for the application main, where the processing logic is usually to create a webhostbuilder, then generate the webhost, and finally start it.

A startup type is often specified when Webhostbuilder is created.

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>    WebHost.CreateDefaultBuilder(args)        .UseStartup<Startup>();

What has been done in this startup class?

Check the implementation of the Usestartup method:

public static IWebHostBuilder UseStartup(this IWebHostBuilder hostBuilder, Type startupType){    var startupAssemblyName = startupType.GetTypeInfo().Assembly.GetName().Name;    return hostBuilder        .UseSetting(WebHostDefaults.ApplicationKey, startupAssemblyName)        .ConfigureServices(services =>        {            if (typeof(IStartup).GetTypeInfo().IsAssignableFrom(startupType.GetTypeInfo()))            {                services.AddSingleton(typeof(IStartup), startupType);            }            else            {                services.AddSingleton(typeof(IStartup), sp =>                {                    var hostingEnvironment = sp.GetRequiredService<IHostingEnvironment>();                    return new ConventionBasedStartup(StartupLoader.LoadMethods(sp, startupType, hostingEnvironment.EnvironmentName));                });            }        });}

You can see that the specified startup type is registered as a singleton in the Di Container, and the registered processing is encapsulated as an action

The startup type can be implemented in two ways:

    • Customizing the class that implements the IStartup interface
    • Internally defined Conventionbasedstartup class

The startup class that is actually used is often the case:

public class Startup{    public Startup(IConfiguration configuration)    {        Configuration = configuration;    }    public IConfiguration Configuration { get; }    public void ConfigureServices(IServiceCollection services)    {        ...    }    public void Configure(IApplicationBuilder app, IHostingEnvironment env)    {        ...    }}

So it's obviously not the first way, so how does it relate to the second way?

The Startupmethods type parameter is passed into the Conventionbasedstartup constructor method, and more information is exposed in its Loadmethod method.

public static Startupmethods Loadmethods (IServiceProvider hostingserviceprovider, Type startuptype, string    Environmentname) {var configuremethod = findconfiguredelegate (Startuptype, environmentname);    var Servicesmethod = findconfigureservicesdelegate (Startuptype, environmentname);    var Configurecontainermethod = findconfigurecontainerdelegate (Startuptype, environmentname);    object instance = NULL; if (!configuremethod.methodinfo.isstatic | |    (Servicesmethod = null &&!servicesmethod.methodinfo.isstatic))    {instance = activatorutilities.getserviceorcreateinstance (Hostingserviceprovider, Startuptype); }//The type of the Tcontainerbuilder.    If There is no Configurecontainer method we can just use object as it's not//going to being used for anything. var type = Configurecontainermethod.methodinfo! = null?    Configurecontainermethod.getcontainertype (): typeof (Object);    var builder = (Configureservicesdelegatebuilder) activator.createinstance (    typeof (Configureservicesdelegatebuilder<>). MakeGenericType (type), Hostingserviceprovider, Servicesmethod, Configurecontainermethod, Insta    NCE); return new Startupmethods (instance, Configuremethod.build (instance), builder. Build ());}

Its internal processing will find three methods, Configureservices, configure and Configurecontainer.

 private static Configurebuilder findconfiguredelegate (Type startuptype, string environmentname) {var configureme Thod = FindMethod (Startuptype, "configure{0}", Environmentname, typeof (void), required:true); return new Configurebuilder (Configuremethod);} private static Configurecontainerbuilder Findconfigurecontainerdelegate (Type startuptype, string environmentname) { var Configuremethod = FindMethod (Startuptype, "Configure{0}container", Environmentname, typeof (void), Required:false) ; return new Configurecontainerbuilder (Configuremethod);} private static Configureservicesbuilder Findconfigureservicesdelegate (Type startuptype, string environmentname) {var s Ervicesmethod = FindMethod (Startuptype, "configure{0}services", Environmentname, typeof (IServiceProvider), required: False)?? FindMethod (Startuptype, "configure{0}services", Environmentname, typeof (void), required:false); return new Configureservicesbuilder (Servicesmethod);} 

The Configureservices method is used to register the various service interface types required in the container, and the Configure method can be configured with various middleware (middleware) for HTTP request pipeline (pipelines).
The two methods are basically consistent with the IStartup interface, while the Configurecontainer method provides a function to introduce a third-party di container.

public interface IStartup{    IServiceProvider ConfigureServices(IServiceCollection services);    void Configure(IApplicationBuilder app);}

With the implementation of the second startup type, the parameters for the Configure method can be more flexible, not only by passing in the Iapplicationbuilder type, but also by any other registered interface type.

The build method of the Configurebuilder class is simple and straightforward to handle the extra parameters, is the direct incoming parameter instance of the Iapplicationbuilder type, not the instance obtained from the DI container:

public class configurebuilder{Public action<iapplicationbuilder> Build (object instance) = Builder = Invo    Ke (instance, builder);  private void Invoke (object instance, Iapplicationbuilder Builder) {//Create a scope for Configure, this allows        Creating scoped dependencies//without the hassle of manually creating a scope. using (var scope = Builder. Applicationservices.createscope ()) {var serviceprovider = scope.            serviceprovider;            var Parameterinfos = Methodinfo.getparameters ();            var parameters = new Object[parameterinfos.length]; for (var index = 0; index < parameterinfos.length; index++) {var parameterinfo = Parameterin                Fos[index]; if (Parameterinfo.parametertype = = typeof (Iapplicationbuilder)) {Parameters[index] = bu                Ilder;                   } else {try {Parameters[index] = Serviceprovider.getrequiredservice (Parameterinfo.parametertype);            }                    ...                }        } methodinfo.invoke (instance, parameters); }    }}

In addition, environment variables can be seen in the process of finding various methods. Therefore, the second way can be based on different environment variables to define the same type but different names of the method, which can save if...else... a lot of processing.

The Usestartup method simply declares that the startup type needs to be registered, and the actual invocation occurs when the Webhostbuilder class executes the build method.

private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors){    ...    foreach (var configureServices in _configureServicesDelegates)    {        configureServices(_context, services);    }    return services;    }

As for the timing of the invocation of the method in the startup type, it needs to be traced to the Webhost class.

The first is that its initialize method ensures that an instance of the startup class is obtained and calls the Configureservices method to register the service interface.

private void EnsureApplicationServices(){    if (_applicationServices == null)    {        EnsureStartup();        _applicationServices = _startup.ConfigureServices(_applicationServiceCollection);    }}private void EnsureStartup(){    if (_startup != null)    {        return;    }    _startup = _hostingServiceProvider.GetService<IStartup>();    ...}

When the webhost instance is started, its Buildapplication method creates an Applicationbuilder instance as a configure method parameter, and calls the Configure method, In the Configure method, the methods of handling those middleware (i.e. Func<requestdelegate, requestdelegate> method) are added to the Applicationbuilder.

private RequestDelegate BuildApplication(){    try    {        _applicationServicesException?.Throw();        EnsureServer();        var builderFactory = _applicationServices.GetRequiredService<IApplicationBuilderFactory>();        var builder = builderFactory.CreateBuilder(Server.Features);        builder.ApplicationServices = _applicationServices;        var startupFilters = _applicationServices.GetService<IEnumerable<IStartupFilter>>();        Action<IApplicationBuilder> configure = _startup.Configure;        foreach (var filter in startupFilters.Reverse())        {            configure = filter.Configure(configure);        }        configure(builder);        return builder.Build();    }    ...}

The build method of the Applicationbuilder nested these processing logic, the bottom of which is to return 404 Not Found processing logic.

public RequestDelegate Build(){    RequestDelegate app = context =>    {        context.Response.StatusCode = 404;        return Task.CompletedTask;    };    foreach (var component in _components.Reverse())    {        app = component(app);    }    return app;}

The Buildapplication method returns a nested Requestdelegate delegate method, and in the resulting hostingapplication instance, it is passed into its constructor method.

  public virtual async Task Startasync (cancellationtoken cancellationtoken = default) {Hosting    EventSource.Log.HostStart ();    _logger = _applicationservices.getrequiredservice<ilogger<webhost>> (); _logger.    Starting ();    var application = Buildapplication (); _applicationlifetime = _applicationservices.getrequiredservice<iapplicationlifetime> () as    Applicationlifetime;    _hostedserviceexecutor = _applicationservices.getrequiredservice

In the above method, the Hostingapplication instance is eventually passed into the Kestrelserver's startup method, so that the Hostingapplication Processrequestasync method can be called inside. and begin to call many requestdelegate methods at layers.

public Task ProcessRequestAsync(Context context){ return _application(context.HttpContext);}

If you feel that using the startup class is a bit of a hassle, using the extension method provided by Webhostbuilder directly is the same effect.

public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostingContext, config) => { HostingEnvironment = hostingContext.HostingEnvironment; Configuration = config.Build(); }) .ConfigureServices(services => { services.AddMvc(); }) .Configure(app => { if (HostingEnvironment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); } app.UseMvcWithDefaultRoute(); app.UseStaticFiles(); });

However, with the additional benefit of using a standalone startup class, the startup class can be included in an assembly that is not used with the program class. Then through the Webhostoptions class in the Startupassembly property settings and other related processing, the Usestartup method to complete the same function.

  private Iservicecollection buildcommonservices (out AggregateException Hostingstartuperrors) {... if (!string. IsNullOrEmpty (_options. startupassembly) {try {var startuptype = Startuploader.findstartuptype (_options). startupassembly, _hostingenvironment.environmentname); if (typeof (IStartup). GetTypeInfo (). IsAssignableFrom (Startuptype.gettypeinfo ())) {services. Addsingleton (typeof (IStartup), startuptype); } else {services. Addsingleton (typeof (IStartup), sp = = {var hostingenvironment = sp. Getrequiredservice<ihostingenvironment> (); var methods = Startuploader.loadmethods (sp, Startuptype, hostingenvironment.environmentname); return new Conventionbasedstartup (methods); }); } } ... } ... return services;}  

. NET Core Development Log--startup

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.