龙空技术网

Asp.net Core启动流程讲解(三)

日行四善 172

前言:

如今姐妹们对“aspnet网页打印实例”大体比较看重,同学们都需要剖析一些“aspnet网页打印实例”的相关知识。那么小编也在网络上网罗了一些有关“aspnet网页打印实例””的相关资讯,希望小伙伴们能喜欢,你们一起来学习一下吧!

Startup.cs启动前后,做了什么?以及如何从Startup到Webapi/Mvc流程接管?

Startup

UseStartup配置了Startup初始化

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

实际上Startup类是按照IStartup实现的非硬性约束的扩展

        public static IWebHostBuilder UseStartup(this IWebHostBuilder hostBuilder, Type startupType)        {//省略不重要的代码段            return hostBuilder                .ConfigureServices(services =>                {                    if (typeof(IStartup).GetTypeInfo().IsAssignableFrom(startupType.GetTypeInfo()))                    {                        services.AddSingleton(typeof(IStartup), startupType);                    }                    else                    {                        services.AddSingleton(typeof(IStartup), sp =>                        {                            var hostingEnvironment = sp.GetRequiredService<IHostEnvironment>();                            return new ConventionBasedStartup(StartupLoader.LoadMethods(sp, startupType, hostingEnvironment.EnvironmentName));                        });                    }                });        }

这里是不是豁然开朗?asp.net core其实内部依赖的是IStartup接口,至于Startup只是一个非IStartup硬性约束的实现

	public interface IStartup	{		IServiceProvider ConfigureServices(IServiceCollection services);		void Configure(IApplicationBuilder app);	}

Startup类依旧有一定既定约束

1、需要实现ConfigureServices方法,参数为1,且类型为 IServiceCollection,返回值可为void/IServiceProvider(asp.net core 3.0以上,返回值只能为void)

2、需要实现Configure,参数且为生命周期Singleton/Transient的Ioc容器内服务

3、在ConfigureServices方法内配置DI,Configure内启用 中间件

4、启动顺序由ConfigureServices->Configure

中间件

中间件由IApplicationBuilder扩展

常见的IApplicationBuilder.UseMvc就是中间件,其实就是基于Route的一套扩展,本质上webapi/mvc,都是Route上层的一套扩展组件,这块可以翻阅源码,不具体展开了

IApplicationBuilder.Use

下面一段演示示例

            app.Use(async (context, next) =>            {                Console.WriteLine("Use");                await next.Invoke();            });            app.Use(async (context, next) =>            {                Console.WriteLine("Use1");                await next.Invoke();            });            app.UseMvc();

先打印Use,然后Use1,最后完成执行。

使用Use方法运行一个委托,我们可以在Next调用之前和之后分别执行自定义的代码,从而可以方便的进行日志记录等工作。这段代码中,使用next.Invoke()方法调用下一个中间件,从而将中间件管道连贯起来;如果不调用next.Invoke()方法,则会造成管道短路。

IApplicationBuilder.Use是IApplicationBuilder Run/Map/MapWhe/Middleware的 核心 模块,基于IApplicationBuilder.Use做各种管道的扩展与实现。

IApplicationBuilder.Run

            app.Run(async (context) =>            {                await context.Response.WriteAsync("Hello World!");            });            app.UseMvc();

很简单的示例,在默认api流程前,加了一段输出。段代码中,使用Run方法运行一个委托,这就是最简单的中间件,它拦截了所有请求,返回一段文本作为响应。Run委托终止了管道的运行,因此也叫作中断中间件。

IApplicationBuilder Map/MapWhen

Map创建基于路径匹配的分支、使用MapWhen创建基于条件的分支。

创建一段IApplicationBuilder.Map的示例

            app.Map("/api/test", (_map) =>            {                _map.Run(async (conetxt) =>                {                    await conetxt.Response.WriteAsync("test");                });            });

访问 /api/test 路由地址时,浏览器输出 test 的字符串。

再编写一段IApplicationBuilder.MapWhen 基于条件的分支示例

            app.Map("/api/test", (_map) =>            {                _map.MapWhen((context) =>                {                    return context.Request.Path == "/a";                },(__map) => {                    __map.Run(async (conetxt) =>                    {                        await conetxt.Response.WriteAsync("test a");                    });                });                _map.Run(async (conetxt) =>                {                    await conetxt.Response.WriteAsync("test");                });            });

访问 /api/test 路由时,浏览器默认输出 test 字符串,当访问 /api/test/a 路由时,打印 test a 字符串。

Middleware

自定义一个Middleware

    public class ContentMiddleware    {        private RequestDelegate _nextDelegate;        public ContentMiddleware(RequestDelegate nextDelegate)        {            _nextDelegate = nextDelegate;        }        public async Task Invoke(HttpContext httpContext)        {            if (httpContext.Request.Path.ToString().ToLower() == "/middleware")            {                await httpContext.Response.WriteAsync(                    "Handled by content middleware", Encoding.UTF8);            }            else            {                await _nextDelegate.Invoke(httpContext);            }        }    }

访问路由 /middleware, 输出 "Handled by content middleware",反之则管道继续向下运行。

IMiddleware

UseMiddleware内部,判断类是否继承了IMiddleware,是则通过Ioc获取IMiddlewareFactory,通过IMiddlewareFactory 创建,然后在 IApplicationBuilder.Use 运行。

反之则生成表达式在 IApplicationBuilder.Use 运行。

        public static IApplicationBuilder UseMiddleware(this IApplicationBuilder app, Type middleware, params object[] args)        {            if (typeof(IMiddleware).GetTypeInfo().IsAssignableFrom(middleware.GetTypeInfo()))            {                // IMiddleware doesn't support passing args directly since it's                // activated from the container                if (args.Length > 0)                {                    throw new NotSupportedException(Resources.FormatException_UseMiddlewareExplicitArgumentsNotSupported(typeof(IMiddleware)));                }                return UseMiddlewareInterface(app, middleware);            }            var applicationServices = app.ApplicationServices;            return app.Use(next =>            {                //省略代码段                var factory = Compile<object>(methodInfo, parameters);                return context =>                {                    var serviceProvider = context.RequestServices ?? applicationServices;                    if (serviceProvider == null)                    {                        throw new InvalidOperationException(Resources.FormatException_UseMiddlewareIServiceProviderNotAvailable(nameof(IServiceProvider)));                    }                    return factory(instance, context, serviceProvider);                };            });        }
后记

深挖了一下中间件的相关细节,也查阅了很多作者的分享文章,参考 Asp.Net Core 3.0 源码,重写了一下中间件这块

如果对于内容有交流和学习的

原文地址:

标签: #aspnet网页打印实例 #asp获取javascript返回值