.NET Core原理(不知道怎么命名合适)

作者:cmliu;.NET Core启动都做了什么

.NET Core默认启动时的流程,您可以将图片另存为,在本地放大查看

.NET Core默认模板都做了些什么,首先贴出模板里面的Program.cs

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

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

  解读:

       1,入口main方法首先调用CreateWebHostBuilder(string[] args)方法获取一个[Web主机构建者WebHostBuilder]

       2,CreateWebHostBuilder(string[] args)方法首先是调用:WebHost.CreateDefaultBuilder(args)创建一个默认的WebHostBuilder

    在WebHost.CreateDefaultBuilder中,首先读取了命令行,ContentRoot配置;然后指定Kestrel的配置,日志提供程序,以及相关优先执行的中间件,并明确注入了IServer的实现类为KestrelServer;

    并配置了IIS相关的服//WebHost.CreateDefaultBuilder部分源码    

     public static IWebHostBuilder CreateDefaultBuilder(string[] args)
{
var builder = new WebHostBuilder(); if (string.IsNullOrEmpty(builder.GetSetting(WebHostDefaults.ContentRootKey))) { builder.UseContentRoot(Directory.GetCurrentDirectory()); } if (args != null) { builder.UseConfiguration(new ConfigurationBuilder().AddCommandLine(args).Build()); }
         //该方法底层指定了Server的实现类为KestrelServer()   builder.UseKestrel((builderContext, options)
=> { //省略其他代码
}) .ConfigureAppConfiguration((hostingContext, config) => { //省略其他代码 }) .ConfigureLogging((hostingContext, logging) => { //省略其他代码 }) .ConfigureServices((hostingContext, services) => { //省略其他代码 }) .UseIIS() .UseIISIntegration() .UseDefaultServiceProvider((context, options) => { //省略其他代码 }); return builder; }

  3, 调用WebHost.CreateDefaultBuilder(args)返回对象的UseStartup<Startup>()方法;用于将服务注册到容器(ConfigureServices方法),以及注册管道(Configure方法)

        这里也说明一下Startup中的ConfigureServices,Configure两个方法与【下面】的Program类中ConfigureServices,Configure方法作用是一样的,都是用于将服务注册到容器(ConfigureServices方法),以及注册管道(Configure方法)

        public static IWebHostBuilder CreateWebHostBuilder(string[] args)
        {
            var webHostBuilder = WebHost.CreateDefaultBuilder(args).ConfigureServices((services) =>
            {
                //省略其他代码,用于注册服务到容器
            }).Configure((app) =>
            {
                //省略其他代码,用于注册管道
            });
            return webHostBuilder;
        }

       4,Statrtup中的代码,省略,后面进行解读

       5,main方法中调用CreateWebHostBuilder(string[] args)返回的WebHostBuilder的Build方法

    在这个Build方法中,直接初始化并返回了一个WebHost,并指定了WebHost的IServiceCollection(服务),IServiceProvider(容器),该WebHost有一个Server对象,对象实际上为KestrelServer

       6,调用Build返回的WebHost对象的Run方法,用于启动服务器

    *******实际上WebHost.Run方法中,首先获取一个ApplicationBuilder(就是Startip中的Configure方法中那个用于注入管道的类),并使用ApplicationBuilder.Build方法倒序构建RequestDelegate委托链管道

    *******ApplicationBuilder.Build方法中,会把404中间件最为最后一个中间件注入到管道

    *******使用获得的RequestDelegate,日志,HttpContextFactory相关参数,构造一个HostingApplication

    *******最底层:以异步的方式启动WebHost.Server.StartAsync,即调用KestrelServer的StartAsync的方法,并在方法中指定了HostingApplication【此时KestrelServer已经有了一个拥有RequestDelegate管道的HostingApplication】

    internal class WebHost : IWebHost
    {
        //省略其他代码
        private readonly IServiceCollection _applicationServiceCollection;
        private readonly IServiceProvider _hostingServiceProvider;
        private IServiceProvider _applicationServices;
        private IServer Server { get; set; }
        //省略其他代码
        public WebHost(IServiceCollection appServices,IServiceProvider hostingServiceProvider,
            WebHostOptions options,IConfiguration config,AggregateException hostingStartupErrors)
        {
            //省略其他代码
            _applicationServiceCollection = appServices;
            _hostingServiceProvider = hostingServiceProvider;
            //省略其他代码
        }
        //省略其他代码
        public IServiceProvider Services
        {
            get
            {
                return _applicationServices;
            }
        }
        //省略其他代码
        public void Start()
        {
            StartAsync().GetAwaiter().GetResult();
        }
        //省略其他代码
        public virtual async Task StartAsync(CancellationToken cancellationToken = default)
        {
            //省略其他代码
            //构建RequestDelegate委托链管道
            var application = BuildApplication();

            _applicationLifetime = _applicationServices.GetRequiredService<IApplicationLifetime>() as ApplicationLifetime;
            _hostedServiceExecutor = _applicationServices.GetRequiredService<HostedServiceExecutor>();
            var diagnosticSource = _applicationServices.GetRequiredService<DiagnosticListener>();
            var httpContextFactory = _applicationServices.GetRequiredService<IHttpContextFactory>();
            //RequestDelegate委托链管道用于构建HostingApplication
            var hostingApp = new HostingApplication(application, _logger, diagnosticSource, httpContextFactory);
            //启动KestrelServer服务器,并将HostingApplication绑定到KestrelServer
            await Server.StartAsync(hostingApp, cancellationToken).ConfigureAwait(false);
            //省略其他代码
        }
        //省略其他代码

        private RequestDelegate BuildApplication()
        {
            try
            {
                //省略其他代码
                var builderFactory = _applicationServices.GetRequiredService<IApplicationBuilderFactory>();
                var builder = builderFactory.CreateBuilder(Server.Features);
                builder.ApplicationServices = _applicationServices;
          //省略其他代码
          return builder.Build(); } catch (Exception ex) {
          //省略其他代码
        } } //省略其他代码 }

  7,KestrelServer启动HttpListener后,开始监听来自客户端浏览器的请求

  8,KestrelServer接收到浏览器请求后,将请求参数构造出HttpContext,并选择对应的HTTP协议处理类,通过协议处理类的ProcessRequests方法(传说中的PR方法)

    public abstract partial class HttpProtocol : IHttpResponseControl
    {
        //HTTP协议类调用HttpApplication
        private async Task ProcessRequests<TContext>(IHttpApplication<TContext> application)
        {
            while (_keepAlive)
            {
                //省略其他代码
                try
                {
                    //省略其他代码
                    await application.ProcessRequestAsync(httpContext);
                    //省略其他代码
                }
                catch (BadHttpRequestException ex)
                {
                    //省略其他代码
                }
                //省略其他代码
            }
        }
    }

  9,PR方法会去调用KestrelServer的HostingApplication的ProcessRequestAsync,而ProcessRequestAsync则是把HttpContext交给RequestDelegate管道处理

public class HostingApplication : IHttpApplication<HostingApplication.Context>
    {
        //委托链管道
        private readonly RequestDelegate _application;
        //省略其他代码
        public HostingApplication(
            RequestDelegate application,
            ILogger logger,
            DiagnosticListener diagnosticSource,
            IHttpContextFactory httpContextFactory)
        {
            _application = application;
            //省略其他代码
        }

        //PR方法,调用委托链处理请求
        public Task ProcessRequestAsync(Context context)
        {
            return _application(context.HttpContext);
        }
    //省略其他代码
}

猜你喜欢

转载自www.cnblogs.com/cmliu/p/11760786.html