你的位置:首页 > ASP.net教程

[ASP.net教程]asp.net core 源码系列(一)

前言

asp.net core 出来一个来月了,自己在工作课余时间准备读一下它的源代码,会把一系列的理解和想法记录下来,同时更希望能够得到园子里同行的指点,共同进步,这里只是我对源代码的理解,有错误地方,望大家指正,这将会是一系列的文章。

 

入口

创建一个asp.net core项目后可以看到一个Program.cs和一个Startup.cs,今天主要研究一下Program.cs到底都做了些什么,

public static void Main(string[] args)    {      var host = new WebHostBuilder()        .UseKestrel()        .UseContentRoot(Directory.GetCurrentDirectory())        .UseIISIntegration()        .UseStartup<Startup>()        .Build();      host.Run();    }

View Code

这里main方法是应用程序的入口不用多说,可以看到在入口处创建了一个WebHostBuilder的实例对象,然后对他进行了一系列的配置,最后执行Build方法返回一个IWebHost对象的实例,最后执行他的Run,方法,至此,应用程序启动起来了,那么这一系列的配置到底做了什么,我们需要看WebHost这个类,我们去github上面把源代码下载下来慢慢看。链接是aspnet/hosting,下载下来后可以直接用VS2015 update3 打开。首先我们要先来看WebHostBuilder这个类

WebHostBuilder

这个类的实例是为了创建WebHost的类实例而准备的,我们看一下他的构造方法:

public WebHostBuilder()    {      _hostingEnvironment = new HostingEnvironment();      _configureServicesDelegates = new List<Action<IServiceCollection>>();      _configureLoggingDelegates = new List<Action<ILoggerFactory>>();      _config = new ConfigurationBuilder()        .AddEnvironmentVariables(prefix: "ASPNETCORE_")        .Build();      if (string.IsNullOrEmpty(GetSetting(WebHostDefaults.EnvironmentKey)))      {        // Try adding legacy environment keys, never remove these.        UseSetting(WebHostDefaults.EnvironmentKey, Environment.GetEnvironmentVariable("Hosting:Environment")           ?? Environment.GetEnvironmentVariable("ASPNET_ENV"));      }      if (string.IsNullOrEmpty(GetSetting(WebHostDefaults.ServerUrlsKey)))      {        // Try adding legacy url key, never remove this.        UseSetting(WebHostDefaults.ServerUrlsKey, Environment.GetEnvironmentVariable("ASPNETCORE_SERVER.URLS"));      }    }

View Code

这个方法里面初始化一些基本的变量,_hostingEnvironment(host的环境配置,包括环境名字,应用程序的名字,webroot的路径,ContentRoot的路径),_configureServicesDelegates(从名字上来看是服务操作的委托集合),_configureLoggingDelegates(从名字上看是日志操作的委托集合),_config(配置创建器的一个实例),然后会向_config中写入两个配置(“environment”和“urls”)。

然后调用扩展方法UseKestrel(),我们来看代码:

 public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder)  {   return hostBuilder.ConfigureServices((Action<IServiceCollection>) (services =>   {    ServiceCollectionServiceExtensions.AddTransient<IConfigureOptions<KestrelServerOptions>, KestrelServerOptionsSetup>(services);    ServiceCollectionServiceExtensions.AddSingleton<IServer, KestrelServer>(services);   }));  }

View Code

这个方法是调用WebHostBuilder的ConfigureServices方法增加了Kestrel对host的一些委托处理方法,这些委托方法主要包括将Kestrel以及它的一些配置选项加入到应用程序的服务处理集合。

然后调用UseContentRoot(Directory.GetCurrentDirectory())方法,我们来看代码:

public static IWebHostBuilder UseContentRoot(this IWebHostBuilder hostBuilder, string contentRoot)  {   if (contentRoot == null)    throw new ArgumentNullException("contentRoot");   return hostBuilder.UseSetting(WebHostDefaults.ContentRootKey, contentRoot);  }

View Code

这个扩展方法依旧是调用UseSeeting()方法给_config配置中添加配置项“contentRoot”(应用程序的内容目录,详见链接),值为当前的目录.

然后调用UseIISIntegration()这个扩展方法,我们来看代码:

public static IWebHostBuilder UseIISIntegration(this IWebHostBuilder app)  {   if (app == null)    throw new ArgumentNullException("app");   string str1 = app.GetSetting(WebHostBuilderIISExtensions.ServerPort) ?? Environment.GetEnvironmentVariable(string.Format("ASPNETCORE_{0}", (object) WebHostBuilderIISExtensions.ServerPort));   string str2 = app.GetSetting(WebHostBuilderIISExtensions.ServerPath) ?? Environment.GetEnvironmentVariable(string.Format("ASPNETCORE_{0}", (object) WebHostBuilderIISExtensions.ServerPath));   string pairingToken = app.GetSetting(WebHostBuilderIISExtensions.PairingToken) ?? Environment.GetEnvironmentVariable(string.Format("ASPNETCORE_{0}", (object) WebHostBuilderIISExtensions.PairingToken));   if (!string.IsNullOrEmpty(str1) && !string.IsNullOrEmpty(str2) && !string.IsNullOrEmpty(pairingToken))   {    string str3 = "http://localhost:" + str1 + str2;    app.UseSetting(WebHostDefaults.ServerUrlsKey, str3);    HostingAbstractionsWebHostBuilderExtensions.CaptureStartupErrors(app, true);    app.ConfigureServices((Action<IServiceCollection>) (services =>    {     ServiceCollectionServiceExtensions.AddSingleton<IStartupFilter>(services, (IStartupFilter) new IISSetupFilter(pairingToken));     OptionsServiceCollectionExtensions.Configure<ForwardedHeadersOptions>(services, (Action<ForwardedHeadersOptions>) (options =>     {      options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;      bool flag = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WEBSITE_INSTANCE_ID"));      options.RequireHeaderSymmetry = !flag;     }));    }));   }   return app;  }

View Code

这里主要是对IIS的一些配置,我的理解是IIS会把它监听的到的请求转交给Kestrel来做处理,所以真正的监听还是在IIS,当然这一步也可以直接省去,直接有Kestrel来监听端口的请求。注释掉这个方法的调用,启动应用程序直接访问 localhost:5000一样可以(你可以试一试的)。

接着是 UseStartup<Startup>() 这个方法,这个方法和Startup这个类,我会在下一篇做单独的讲解,主要是设置Aspnet core的处理模块(我们这里就是MVC的处理)

最后是Builder()方法:

public IWebHost Build()    {      // Warn about deprecated environment variables      if (Environment.GetEnvironmentVariable("Hosting:Environment") != null)      {        Console.WriteLine("The environment variable 'Hosting:Environment' is obsolete and has been replaced with 'ASPNETCORE_ENVIRONMENT'");      }      if (Environment.GetEnvironmentVariable("ASPNET_ENV") != null)      {        Console.WriteLine("The environment variable 'ASPNET_ENV' is obsolete and has been replaced with 'ASPNETCORE_ENVIRONMENT'");      }      if (Environment.GetEnvironmentVariable("ASPNETCORE_SERVER.URLS") != null)      {        Console.WriteLine("The environment variable 'ASPNETCORE_SERVER.URLS' is obsolete and has been replaced with 'ASPNETCORE_URLS'");      }      var hostingServices = BuildHostingServices();      var hostingContainer = hostingServices.BuildServiceProvider();      var host = new WebHost(hostingServices, hostingContainer, _options, _config);      host.Initialize();      return host;    }

View Code

这个方法根据之前注册的一系列的服务(监听服务,日志服务等等)和配置,生成一个应用程序的最终宿主host,并且初始化他(里面的调用和创建方法源代码都很清晰)。

然后调用host.run()方法,启动服务,run方法的具体调用会单独一个章节来分析。

总结

这篇文章只是对创建一个host对象做了一些系统的描述,里面的具体实现真的很多很多,有一些我还没有看到,感觉每一个方法都有很多的东西,我会慢慢完善,有理解错误的地方,希望大家指出来。愿.NET的生态圈越来越好,大家一起努力。给大家推荐一个网址链接

里面有关于aspnet的在线讨论。

 

如果你感觉对你有帮助,麻烦推荐一下。