ASP.NET MVC入门-Program类:程序的入口

摘要:
笔记的内容来自微软MVP教师杨旭(Yang Xu Solenovex)的视频程序课:Web程序的入门程序课本质上是一个控制台应用程序。首先,Program类中的Main方法调用CreateWebHostBuilder。Build()。Run()方法。publicclassProgram{publicstaticvoidMain{CreateWebHostBuilder.Build().Run();}publicstaticWebHostBuilderCreateWebHostBuilder=˃WebHost.CreateDefaultBuilder.UseStartup<Startup>();}CreateWebHostBuilder方法返回的对象由静态类WebHost的静态方法CreateDefaultBuilder方法返回。我们发现CreateDefaultBuilder方法首先创建了一个WebHostBuilder类型varbuilder=newWebHostBuilder();的对象;。WebHostBuilder类实现了我们需要返回的IWebHostBuilder接口类型。

笔记内容来源于微软 MVP 杨旭老师 solenovex 的视频

Program 类:Web程序的入口

Program 类的本质就是一个控制台应用。

其中的 Main 方法是 Web 应用的入口方法。

我们可以在 Main方法中启动 Web 服务。

Program 类的源码

首先,Program 类中的 Main方法调用了 CreateWebHostBuilder(args).Build().Run() 方法。

该方法的最终目的和意义就是使用 CreateWebHostBuilder 方法返回的 IWebHostBuilder 接口类型对象来构建(Build)一个 WebServe 然后运行(Run)这个 WebServe

public class Program
{
  public static void Main(string[] args)
  {
    CreateWebHostBuilder(args).Build().Run();
  }
  public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
    .UseStartup<Startup>();
}

CreateWebHostBuilder 方法返回的对象是静态类WebHost 的静态方法 CreateDefaultBuilder 方法返回的。

CreateWebHostBuilder 方法中我们可以看到一个 lambda 表达式,他返回了 WebHost.CreateDefaultBuilder(args).UseStartup<Startup>(); 

CreateDefaultBuilder 方法的源码

反编译 WebHost.CreateDefaultBuilder 方法的源码,我们先来看一下完整的代码实现。

我们发现 CreateDefaultBuilder 方法首先 new 了一个 WebHostBuilder 类型的对象  var builder = new WebHostBuilder(); 。  

而 WebHostBuilder 类就实现了我们所需要返回的的 IWebHostBuilder 接口类型。

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());
    }
    builder.ConfigureAppConfiguration((hostingContext, config) =>
    {
        var env = hostingContext.HostingEnvironment;
        config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
        if (env.IsDevelopment())
        {
            var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
            if (appAssembly != null)
            {
                config.AddUserSecrets(appAssembly, optional: true);
            }
        }
        config.AddEnvironmentVariables();
        if (args != null)
        {
            config.AddCommandLine(args);
        }
    })
    .ConfigureLogging((hostingContext, logging) =>
    {
        logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
        logging.AddConsole();
        logging.AddDebug();
        logging.AddEventSourceLogger();
    }).
    UseDefaultServiceProvider((context, options) =>
    {
        options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
    });
    ConfigureWebDefaults(builder);
    return builder;
}

ConfigureWebDefaults 方法的源码

在方法的末尾,调用了 ConfigureWebDefaults(builder); 方法。

该方法详细地配置了默认的 builder 的各种设置,我们也来看一下完整的源码实现。

internal static void ConfigureWebDefaults(IWebHostBuilder builder)
{
    builder.UseKestrel((builderContext, options) =>
    {
        options.Configure(builderContext.Configuration.GetSection("Kestrel"));
    })
    .ConfigureServices((hostingContext, services) =>
    {
        // Fallback
        services.PostConfigure<HostFilteringOptions>(options =>
        {
            if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)
            {
                // "AllowedHosts": "localhost;127.0.0.1;[::1]"
                var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                // Fall back to "*" to disable.
                options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });
            }
        });
        // Change notification
        services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>(
                    new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));

        services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();
    })
    .UseIIS()
    .UseIISIntegration();
}

builder 的默认配置

1.使用 Kestrel Web Serve

如上代码所示,我们可以看到 builder 首先调用了 UseKestrel 方法,配置了 Kestrel 服务器。

2.IIS 集成

然后 builder  使用了 UseIIS().UseIISIntegration(); 这两个方法配置了 IIS 服务器。

UseIISIntegration 方法和前者的区别就是它允许 IIS 通过 Windows 的验证来到 Kestrel 服务器,这有利于构建内网的 Web 应用。

而在项目的 csproj 文件中我们可以看到声明了 <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>  。

InProcess 模式下 IIS 会和 Web 程序运行在一个系统内。而与之相对的是 OutOfProcess 模型。

OutOfProcess 模式会把请求转发给 Kestrel 服务器。相比 OutOfProcess 这种分开的模式,InProcess 模式提高了性能。

3.Logger

回到 CreateDefaultBuilder 方法,这段代码配置了 ConfigureLogging,将 logger 输出到 ConsoleDebug EventSourceLogger。

.ConfigureLogging((hostingContext, logging) =>
{
    logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
    logging.AddConsole();
    logging.AddDebug();
    logging.AddEventSourceLogger();
}).

4.IConfiguration 接口

我们可以通过实现 IConfiguration 接口的类型对象里获取一些需要的配置信息。

前面提到 CreateDefaultBuilder 方法首先 new 了一个 WebHostBuilder 类型的对象。  var builder = new WebHostBuilder(); 

而 WebHostBuilder 类型就持有一个 IConfiguration 接口类型的成员字段 _config

IConfiguration 接口类型也很简单,其中的 stringthis[string key]{get; set;} 就是以 key-value 的形式,通过string来获取配置信息,封装的其他方法就在此省略了。

配置信息首先从json文件中获取,我们的项目中存在着 appsettings.json 和 appsettings.Development.json 两个默认的 json 文件。

打开 appsettings.json 文件,我们可以看到默认生成的配置如下所示。

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHost": "*"
}

获取配置信息的方法和顺序

回到 CreateDefaultBuilder 方法,我们可以找到这一句代码。

config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

其中,config 是 builder.ConfigureAppConfiguration() 调用的 lambda 表达式参数   (hostingContext, config) =>{}  ,其设置了配置文件的具体名称。

注意,config 调用 AddJsonFile 方法,调用了两次,第二个 json 文件是系统环境变量为名的json文件,默认是 Devolopment,也就是前面提到的 appsettings.Development.json

如果两个文件有相同的属性,后者就会覆盖掉前者的设置。但是 CreateDefaultBuilder 方法的代码中还有一句设置 config.AddEnvironmentVariables(); 

这一句代码是设置系统环境变量,如果有和以上配置文件相同的属性,也会覆盖的前者的设置。

在系统环境变量之后又有一句 config.AddCommandLine(args); ,命令行中如果有和以上配置文件相同的属性,也会覆盖的前者的设置。

所以最终的属性的覆盖顺序为 appsettings.json -> appsettings.{env.EnvironmentName}.json -> AddEnvironmentVariables -> AddCommandLine

UseStartup<> 方法

回到 Program 类的 CreateWebHostBuilder 方法,我们可以发现 WebHost.CreateDefaultBuilder(args).UseStartup<Startup>(); 。

其调用了 UseStartup<> 方法。 UseStartup<Startup>()  指定 StartupStartup 类,以该类来配置整个 Web 应用,如注册服务、使用中间件等等。

然后CreateWebHostBuilder 方法返回的 builder 回到 Main 方法,Build 后再调用 Run 方法,我们的 Web 应用就可以监听 Http/Https 的请求了。

Progarm 这个类主要是为了配置我们的 Web 应用的基础设施,如 Http 服务器以及如何集成到 IIS 等。

免责声明:文章转载自《ASP.NET MVC入门-Program类:程序的入口》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇第28本:《别逗了,费曼先生》[asp常用代码]文件上传代码下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

git clone error:RPC failed; curl 18 transfer closed with outstanding read data remaining

git clone时报RPC failed; curl 18 transfer closed with outstanding read data remaining 错误 error: RPC failed; curl 18 transfer closed withoutstanding read data remaining fatal: The re...

spring-session之二:简单配置

官方示例:https://docs.spring.io/spring-session/docs/current/reference/html5/#samples 配置Spring Session 在Web项目中配置Spring Session分为四步: 搭建用于Spring Session的数据存储 将Spring Session的jar文件添加到...

flask的配置设置的几种方式

Flask的配置对象(config)是一个字典(dict)的子类(subclass),所以你可以把配置用键值对的方式存储进去。 1、一些重要的配置,可以设置在系统环境变量里,又或者放到某个服务器里,用的时候下载配置文件并读取配置 #在linux系统里设置环境变量 export MAIL_USERNAME=me@greyli.com #用的时候取环境变量...

在tc上安装buildkit.tcz,vscode.tcz,打通vscodeonline与openfaas模拟cloudbase打造碎片化编程开发部署环境

本文关键字:rebuild kernel invalid magic number,failed to create diff tar stream: failed to get xattr for : operation not supported 在《一种用buildkit打造免registry的local cd/ci工具,打通vscodeonline...

【问题记录】IIS配置项

起因: 由于之前项目中出现过内存占用较高情况,为了保障业务不因程序问题导致停止;需要实现对进程资源占用限制。 需要利用IIS相关功能实现,所以对IIS相关配置多一些了解。 主要对以下高级设置重点项了解:包含: 网站高级配置: 进程池高级设置: 一、IIS重点配置项目: 连接数 连接数概念:[1] 浏览者访问站点,必需与站点通过TCP协议,建立连接。这个...

谷粒商城学习——P124 es 自定义扩展词库

P122中安装的ik分词器, 本身默认的词库并不支持一些新的词汇,这就需要修改ik分词器的配置文件,指定远程词库进行扩展词库。ik分词器向远程发送请求要到最新的单词,这样最新的单词就会做为新的词源远行分解。可以给nginx发送请求,nginx反回最新词库。 虚拟机装nginx,内存不够,先将虚拟机关机,打开设置,将内存调到3075,然后重启      然...