asp.net core 源码系列(一)_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > asp.net core 源码系列(一)

asp.net core 源码系列(一)

 2016/7/24 5:31:06  老男人李  程序员俱乐部  我要评论(0)
  • 摘要:前言asp.netcore出来一个来月了,自己在工作课余时间准备读一下它的源代码,会把一系列的理解和想法记录下来,同时更希望能够得到园子里同行的指点,共同进步,这里只是我对源代码的理解,有错误地方,望大家指正,这将会是一系列的文章。入口创建一个asp.netcore项目后可以看到一个Program.cs和一个Startup.cs,今天主要研究一下Program.cs到底都做了些什么,publicstaticvoidMain(string[]args)
  • 标签:.net ASP.NET 源码 net

前言

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

 

入口

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

class="code_img_closed" src="/Upload/Images/2016072405/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('4b5f9b89-71bc-48a5-ae33-2a4ae8cbbeb5',event)" src="/Upload/Images/2016072405/2B1B950FA3DF188F.gif" alt="" />
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的在线讨论。

 

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

发表评论
用户名: 匿名