• ASP.NET Core


      Program  

      我们先看一下1.x和2.x的程序入口项的一个差异

      1.x

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

      2.x

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

      2.x对默认配置进行了简化,把一些基本配置移动了 CreateDefaultBuilder 方法中  

      public static IWebHostBuilder CreateDefaultBuilder(string[] args)
        {
          IWebHostBuilder hostBuilder = new WebHostBuilder()
        .UseKestrel((Action<WebHostBuilderContext, KestrelServerOptions>) ((builderContext, options) => options.Configure((IConfiguration) builderContext.Configuration.GetSection("Kestrel"))))
        .UseContentRoot(Directory.GetCurrentDirectory())
        .ConfigureAppConfiguration((Action<WebHostBuilderContext, IConfigurationBuilder>) ((hostingContext, config) => { IHostingEnvironment hostingEnvironment = hostingContext.HostingEnvironment; config.AddJsonFile("appsettings.json", true, true)
          .AddJsonFile("appsettings." + hostingEnvironment.EnvironmentName + ".json", true, true); if (hostingEnvironment.IsDevelopment()) { Assembly assembly = Assembly.Load(new AssemblyName(hostingEnvironment.ApplicationName)); if (assembly != (Assembly) null) config.AddUserSecrets(assembly, true); } config.AddEnvironmentVariables(); if (args == null) return; config.AddCommandLine(args); }))
        .ConfigureLogging((Action
    <WebHostBuilderContext, ILoggingBuilder>) ((hostingContext, logging) => { logging.AddConfiguration((IConfiguration) hostingContext.Configuration.GetSection("Logging")); logging.AddConsole(); logging.AddDebug(); }))
        .ConfigureServices((Action
    <WebHostBuilderContext, IServiceCollection>) ((hostingContext, services) => { services.PostConfigure<HostFilteringOptions>((Action<HostFilteringOptions>) (options => { if (options.AllowedHosts != null && options.AllowedHosts.Count != 0) return; string str = hostingContext.Configuration["AllowedHosts"]; string[] strArray1; if (str == null) strArray1 = (string[]) null; else strArray1 = str.Split(new char[1]{ ';' }, StringSplitOptions.RemoveEmptyEntries); string[] strArray2 = strArray1; HostFilteringOptions filteringOptions = options; string[] strArray3; if (strArray2 == null || strArray2.Length == 0) strArray3 = new string[1]{ "*" }; else strArray3 = strArray2; filteringOptions.AllowedHosts = (IList<string>) strArray3; })); services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>((IOptionsChangeTokenSource<HostFilteringOptions>) new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration)); services.AddTransient<IStartupFilter, HostFilteringStartupFilter>(); }))
        .UseIISIntegration()
        .UseDefaultServiceProvider((Action
    <WebHostBuilderContext, ServiceProviderOptions>) ((context, options) => options.ValidateScopes = context.HostingEnvironment.IsDevelopment())); if (args != null) hostBuilder.UseConfiguration((IConfiguration) new ConfigurationBuilder().AddCommandLine(args).Build()); return hostBuilder; }

       这里我们可以看到在CreateDefaultBuilder生成器中,定义了默认使用的Web服务器(UseKestrel,使用的是KestrelServer)和一些基础的配置,包括文件路径、应用配置(按appsettings.json,appsettings.{Environment}.json次序加载)、环境变量、日志,IIS集成等,如果需要的话,还可以指定其他类型的Server(IIS HTTP Server,HTTP.sys Server)和自定义Server(继承IServer)。

      返回到Program中,在获取到了WebHostBuilder之后紧接着就指定了启动类UseStartup<Startup>(),Build方法是WebHostBuilder最终的目的(在这个方法里面构建了管道),将构造一个WebHost返回,这里引出了我们在ASP.NET Core - 开篇所说的重要对象:WebHost,并且运行它的Run方法用于启动应用并开始监听所有到来的HTTP请求。

       Startup

      Startup方法用来指定应用程序的启动类,这里主要有两个作用:

    1. 配置应用需要的服务(服务注册,ConfigureServices方法)。
    2. 创建应用的请求处理处理管道(Configure方法)。
    public class Startup
    {
       private readonly IHostingEnvironment _env;
        private readonly IConfiguration _config;
        private readonly ILoggerFactory _loggerFactory;
    
        public Startup(IHostingEnvironment env, IConfiguration config, 
            ILoggerFactory loggerFactory)
        {
            _env = env;
            _config = config;
            _loggerFactory = loggerFactory;
        }
    
        // 注入服务到容器中
        public void ConfigureServices(IServiceCollection services)
        {
            var logger = _loggerFactory.CreateLogger<Startup>();
    
            if (_env.IsDevelopment())
            {
                // Development service configuration
                logger.LogInformation("Development environment");
            }
            else
            {
                // Non-development service configuration
                logger.LogInformation($"Environment: {_env.EnvironmentName}");
            }
    
            ...
        }
    
        // 配置Http请求处理管道
        public void Configure(IApplicationBuilder app)
        {
            ...
        }
    }

      Startup 类的 执行顺序:构造 -> ConfigureServices -> Configure

         1)Startup Constructor(构造函数)

      上面的构造函数引出了我们开篇说的三个重要对象:IHostingEnvironment ,IConfiguration ,ILoggerFactory ,这里先讲构造函数的作用,这些对象后面会分篇讲。显而易见,这里主要是通过依赖注入实例化了该类中需要用到的对象(根据自己的业务),比较简单。

      2) ConfigureServices

      首先这个方法是可选的,它的参数是IServiceCollection,这也是我们开篇说的重要对象,而且是非常重要的对象,这是一个原生的Ioc容器,所有需要用到的服务都可以注册到里面,一般是通过约定风格services.Addxxx, 这样就可以让这些服务在应用和Configure方法使用(用来构建管道)。

      3)Configure

       用于构建管道处理Http请求,管道中的每个中间件(Middleware)组件负责请求处理和选择是否将请求传递到管道中的下一个组件,在这里我们可以添加自己想要的中间件来处理每一个Http请求,一般是使用上面的ConfigureServices方法中注册好的服务,一般的用法是 app.Usexxx,这个Usexxx方法是基于IApplicationBuilder的扩展。

       需要注意的有三个地方:

    1. 应尽早在管道中调用异常处理委托,这样就能捕获在后续管道发生的异常,所以能看到微软的经典写法是先把异常处理的中间件写在最前面,这样方可捕获稍后调用中发生的任何异常。
    2. 当某个中间件不将请求传递给下一个中间件时,这被称为“请求管道短路”。 我们通常都会需要短路,这样可以避免资源浪费,类似与当抛出异常时我们将不会再往下请求,因为这完全没有必要:)
    3. 如果你想某些模块不需要授权就能访问,应把这些模块放在认证模块前面,所以我们一般会把访问静态文件的中间件放在认证模块的前面。
    public void Configure(IApplicationBuilder app)
    {
        if (env.IsDevelopment())
        {//   Use the Developer Exception Page to report app runtime errors.
            app.UseDeveloperExceptionPage();
        }
        else
        {//   Enable the Exception Handler Middleware to catch exceptions
            //     thrown in the following middlewares.
            app.UseExceptionHandler("/Error");
        }
    // Return static files and end the pipeline.
        app.UseStaticFiles();
    
        // Use Cookie Policy Middleware to conform to EU General Data 
        // Protection Regulation (GDPR) regulations.
        app.UseCookiePolicy();
    
        // Authenticate before the user accesses secure resources.
        app.UseAuthentication();
    
        // If the app uses session state, call Session Middleware after Cookie 
        // Policy Middleware and before MVC Middleware.
        app.UseSession();
    
        // Add MVC to the request pipeline.
        app.UseMvc();
    }

      如果你不想使用Startup类的话,可以使用以下方式配置自己的服务注册和管道构建,虽然这种方式有点odd :)

    public class Program
    {
        public static IHostingEnvironment HostingEnvironment { get; set; }
        public static IConfiguration Configuration { get; set; }
    
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                })
                .ConfigureServices(services =>
                {
                    ...
                })
                .Configure(app =>
                {
                    var loggerFactory = app.ApplicationServices
                        .GetRequiredService<ILoggerFactory>();
                    var logger = loggerFactory.CreateLogger<Program>();
                    var env = app.ApplicationServices.GetRequiredServices<IHostingEnvironment>();
                    var config = app.ApplicationServices.GetRequiredServices<IConfiguration>();
    
                    logger.LogInformation("Logged in Configure");
    
                    if (env.IsDevelopment())
                    {
                        ...
                    }
                    else
                    {
                        ...
                    }
    
                    var configValue = config["subsection:suboption1"];
    
                    ...
                });
    }

       这里需要注意的是,Startup只是一个概念,类的名字是可以任意的,只需要在启动项UseStartup中指定你这个启动类即可。

      总结

      正如ASP.NET Core - 开篇所说的,一个ASP.NET Core应用其实就是一个控制台应用程序,它在应用启动时构建一个 Web 服务器,并且通过指定的Startup类来构建应用服务和请求管道,进而监听和处理所有的Http请求。

    如果你觉得该文章还不错且有所收获,请右下角推荐一下,也可留下您的问题或建议,让我们共同进步。 原创博客请在转载时保留原文链接或者在文章开头加上本人博客地址!
  • 相关阅读:
    高等数学(完结版)
    数据结构(c语言描述)
    leetcode-mid- 50. Pow(x,n)-NO
    leetcode-mid-math
    leetcode-mid-math-202. Happy Number-NO
    leetcode-mid-dynamic programming- Longest Increasing Subsequence-NO
    leetcode-mid-design-380. Insert Delete GetRandom O(1)
    leetcode-mid-design-297. Serialize and Deserialize Binary Tree¶-NO -??
    leetcode-mid-dynamic programming-322. Coin Change
    leetcode-mid-dynamic programming-62. Unique Paths
  • 原文地址:https://www.cnblogs.com/lex-wu/p/10693437.html
Copyright © 2020-2023  润新知