asp.netcore 3.1 program、Startup 类详解

说明:此随笔主要详细解释asp.netcore 3.1的Program类和Startup类,以及两者之间的关系。

Program类 :为了详细解读,将此类的两个方法改写。

public class Program
    {
        #region 这两个方法是创建项目的时候自动创建的,为了详细解读,将这两个方法注释掉并重新改写。
        //public static void Main(string[] args)
        //{
        //    CreateHostBuilder(args).Build().Run();
        //}

        //public static IHostBuilder CreateHostBuilder(string[] args) =>
        //    Host.CreateDefaultBuilder(args)
        //        .ConfigureWebHostDefaults(webBuilder =>
        //        {
        //            webBuilder.UseStartup<Startup>();
        //        });
        #endregion

        #region 改写 Main 和 CreateHostBuilder 方法如下
        /// <summary>
        /// 应用程序入口,asp.netcore 本质上是控制台程序
        /// </summary>
        /// <param name="args"></param>
        public static void Main(string[] args)
        {
            //CreateHostBuilder(args).Build().Run(); 改写前
            //改写后
            var hostBuilder = CreateHostBuilder(args);//创建宿主host构建器
            var webHost = hostBuilder.Build();//用构建器 创建宿主host
            webHost.Run();//运行宿主host之后,就可以监听http或者https请求了。即 运行宿主host,开始监听HTTP或者HTTPS请求。
        }

        /// <summary>
        /// 改写后的 CreateHostBuilder 方法
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            //创建构建器hostbuilder
            var hostBuilder = Host.CreateDefaultBuilder(args);

            //配置 hostbuilder
            hostBuilder.ConfigureWebHostDefaults(webBuilder =>
            {
                //注册Startup类,startup类配置web应用的启动逻辑,asp.netcore运行时 会实例化这个类,
                webBuilder.UseStartup<Startup>();
            });

            return hostBuilder;
        }

        #endregion
    }

 

Startup 类

由运行时 调用 ConfigureServices 和Configure 这两个方法。调用的第一个方法是 ConfigureServices 方法,这个方法用于注册服务,
服务被注册后,才能传递对应的具体实现类。然后调用 Configure方法,这个方法用于配置管道中间件。
其中,管道的工作的工作流程如下:

当用户发出一起请求后,应用程序都会为其创建一个请求管道,在这个请求管道中,
每一个中间件都会按顺序进行处理(可能会执行,也可能不会被执行,取决于具体的业务逻辑),
等最后一个中间件处理完毕后请求又会以相反的方向返回给用户最终的处理结果
public class Startup
    {
        private readonly IConfiguration _configuration;
        /// <summary>
        /// 通过构造函数注入,由运行时自动注入
        /// </summary>
        /// <param name="configuration"></param>
        public Startup(IConfiguration configuration)
        {
            _configuration = configuration;
            var aa = _configuration["FyyAspnetcore:Name"];// 获取 appsettings.json文件的数据
        }

        #region  运行时同通过约定来调用这两个方法。先调用 ConfigureServices、再调用 Configure.
        /// <summary>
        /// 负责依赖注入配置,宿主启动后,会将服务都注册好。
        /// DI的优点:
        ///   1.解耦,没有强依赖,Controller与具体的服务类解耦
        ///   2.利于单元测试
        ///   3.不需要了解具体的服务类:Controller 不需要了解服务类及其工作细节。
        ///   4.也不需要管理服务类的生命周期:Controller 不需要管理服务类的生命周期,生命周期交给IOC容器DI来控制。
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {
            //当IHelloService 被请求时,IOC容器会返回一个HelloService的实例。

            //AddSingleton 表示所注册的服务周期 是整个应用程序生存期间,整个应用程序只有一个实例,只有应用程序停止,才会被销毁。
            services.AddSingleton<IHelloService, HelloService>();

            //所注册的服务的生命周期是整个请求期间。一次web请求产生一个实例,web请求处理完的时候,生命周期就结束了。
            //services.AddScoped<IHelloService, HelloService>;

            //所注册的服务的生命周期是暂时的,服务每次没请求的时候,都会实例化一个对象。
            //services.AddTransient<IHelloService, HelloService>;

            //注册webapi的服务
            //services.AddControllers();

            //注册mvc的服务
            //services.AddControllersWithViews();

            //将配置文件的Json,映射到类中。(配置到类中,配置依赖注入)
            services.Configure<FyyAspnetcore>(_configuration.GetSection("FyyAspnetcore"));
        }

        /// <summary>
        /// Development环境变量时,走这个方法。可以针对不同的环境,使用不同的方法。
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        //public void ConfigureDevelopment(IApplicationBuilder app, IWebHostEnvironment env)
        //{

        //}

        /// <summary>
        /// 负责配置了asp.netcore http请求管道的中间件。宿主启动后,中间件进入工作就绪状态。
        /// http/https 请求通过管道进来后,Configure方法中的组件(中间件)将决定如何响应http/https请求
        /// 请求从管道进来,处理完后再从管道出去,如果管道里什么都没有,请求进来再回去,就什么都不会发生。
        /// 
        /// 当ASP.NETCORE 调用configure方法的时候,会分析方法的参数,如果asp.netcore能解析这些参数,就会传入实现了该接口的服务(类)
        /// </summary>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IConfiguration configuration, IHelloService helloService, ILogger<Startup> logger)
        {
            /* 参数解释:
               IApplicationBuilder app:应用程序构建器,使用它来配置中间件。一般用app.use...这些方法来配置。由运行时注入。
               IWebHostEnvironment env:通过这个服务,获取应用程序运行的环境。由运行时注入
               IConfiguration configuration:通过这个服务,可获取配置文件appsetting.json 内容。由运行时注入。
               ILogger<Startup> logger:日志服务,由于运行时注入。
               IHelloService helloService:手动在 ConfigureServices 方法中注入。
             */

            //判断环境变量
            //env.IsEnvironment("OK"); 判断自定义环境变量
            if (env.IsDevelopment())
            {
                //开发模式下插入到管道的第一个中间件。
                //异常处理中间件:用于捕获管道中,位置在它之后的中间件抛出的异常。并返回开发者异常页面。
                app.UseDeveloperExceptionPage();
            }
            else//非开发环境
            {
                app.UseExceptionHandler("/Home/Error");
            }

            //使用授权中间件
            // app.UseAuthentication();

            //这种写法,比 app.Use...更底层。 RequestDelegate 传进的参数是 httpcontext
            //这里 next 代表着在管道里下一个将要执行的中间件。
            app.Use(

                //以next 为开始的这个方法,只在启动管道的时候走一遍。
                next => {
                    logger.LogInformation("--中间件准备就绪,只执行一次-----------");
                    return
                        //这个才是中间件的代码,如果之前没有其他中间件拦截的话,每次请求都会进来
                        async httpContext =>
                        {
                            logger.LogInformation("--中间件开始-----------");
                            if (httpContext.Request.Path.StartsWithSegments("/first"))
                            {
                                logger.LogInformation("--22222-----------");
                                await httpContext.Response.WriteAsync("first");
                            }
                            else
                            {
                                logger.LogInformation("--33333-----------");
                                await next(httpContext);
                            }
                        };
                });


            app.UseHttpsRedirection();//https 重定向中间件,强制客户端使用ssl协议。

            /*使用这个中间件 会将wwwroot文件夹中的内容对外可见(对外伺服)。如果不使用这个中间件,客户端就访问不了wwwroot中的静态文件,如JS,CSS,图片等静态文件。*/
            app.UseStaticFiles(); 
        
       app.UseStaticFiles(requestPath:"/StaticFiles"); //添加其他对外伺服文件夹
       
       //或者这样写
       app.UseStaticFiles(new StaticFileOptions{
          RequestPath="/Staticfiles",
          FileProvider=new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "StaticFiles"))
        }); app.UseRouting();
//路由中间件。会检查在应用中已经注册的端点。 //app.UseWelcomePage();//配置 欢迎页 中间件。配置后,会改变 请求路由的endpoint app.UseWelcomePage(new WelcomePageOptions { Path = "/1234" //当请求路径的endpoint 是"/1234"时,会执行这个中间件,并且会在这里短路返回。 }); app.UseEndpoints(endpoints => //注册端点,端点就是进来的http请求的url的结尾那部分。这部分由端点中间件处理。 { logger.LogInformation("ttttttttttt"); endpoints.MapGet("/", async context =>// 以/结尾的url,映射到下面的表达式中。 { throw new Exception("抛出异常啦");//会被捕获。 var helloWorld = configuration["Hello"]; //由于 IHelloService 并没有被 运行时默认注册,所以需要在ConfigureServices 进行手动注册。让.netcore知道传递的是哪个具体的服务(实现类)。 //否则不会将实现了IHelloService接口的服务传递进来。会报异常,说不能解析 IHelloService类型的服务 helloService var helloWorld1 = helloService.GetMsg(); //configuration asp.netcore 运行时自动默认注册进来,不需要手动注册。 //下一个反编译.net reflactor 来了解一下configuration的配置原理 //以后面的加载的为准。 await context.Response.WriteAsync(helloWorld + "----" + helloWorld1); }); //MVC的路由端点,路由模板,路由表的形式 //endpoints.MapControllerRoute( // name:"default", // pattern:"{controller=Home}/{action=Index}/{id?}" // ); //使用这种方式,可以在controller或action上添加路由,不需要添加路由表。 // endpoints.MapControllers(); }); } #endregion }

类 HelloService 和接口 IHelloService 

 public class HelloService : IHelloService
    {
        public string GetMsg()
        {
            return "HelloWorld not rejected by runtime";
        }
    }

    public interface IHelloService
    {
        string GetMsg();
    }

 

类: FyyAspnetcore

public class FyyAspnetcore
    {
        public string Name { get; set; }

        public int Age { get; set; }
    }

appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "FyyAspnetcore": {
    "Name": "Fengyinyong",
    "Age": 30
  },
"Hello":"hello hehehehehe" }
使用这个中间件,会将wwwroot文件夹的内容对外伺服,即对外可见。
原文地址:https://www.cnblogs.com/Fengyinyong/p/13090412.html