网站做记录访客,wordpress 粘贴,h5轻设计平台,中山建站前言
在 上一篇 文章中#xff0c;我们学习了 ASP.NET Core MVC 的路由模块#xff0c;那么在本篇文章中#xff0c;主要是对 ASP.NET Core MVC 启动流程的一个学习。
ASP.NET Core 是新一代的 ASP.NET 应用程序#xff0c;它是跨平台的#xff0c;并且不依赖于 IIS我们学习了 ASP.NET Core MVC 的路由模块那么在本篇文章中主要是对 ASP.NET Core MVC 启动流程的一个学习。
ASP.NET Core 是新一代的 ASP.NET 应用程序它是跨平台的并且不依赖于 IIS新的 MVC Core 设计加入了依赖注入和模块化的 Http 处理管道这篇文章我们一起通过源码看一下它的启动过程每一步都很重要。
我们知道 MVC Core 是作为一个中间件程序注册到 ASP.NET Core 管道流程中的我先来回顾一下在以前基于 IIS 的传统 ASP.NET 程序。 传统的 ASP.NET 应用程序由可执行文件 InetMgr.exe IIS 宿主进程创建然后调用受托管的应用程序入口接着调用 HttpApplication.Application_Start() 进一步初始化通常情况下我们的初始化代码都写在 Application_StartGlobal.asax 中。
我们今天的主题是MVC 框架所以针对 ASP.NET Core Host 和 Server 的初始化流程就不详细讲解了由兴趣的同学可以翻看一下我的这篇文章。
ASP.NET Core 源码地址https://github.com/aspnet/mvc
Getting Started
ASP.NET Core MVC 源码程序主要包含几部分组成:
Mvc.Core 源码的核心实现包含认证过滤模型绑定路由等等...Mvc.RazorRazor视图的拓展实现模板引擎等核心实现在Rozor那个项目。Mvc.TagHelperRazor中 TagHelper的主要实现。Mvc.ViewFeaturesRazor中视图组件的渲染等。
从 Startup 说起 ASP.NET Core MVC 程序在启动之后会经过一系列流程然后到达 Microsoft.AspNetCore.Mvc包里的扩展程序 IMvcBuilder AddMvc(this IServiceCollection services) 中然后我们从 ConfigureServices 这个分支说起吧。
在 Startup 启动的时候会在 ConfigureServices 中注册 AddMvc 的 DI 服务那么MVC也是在这个时候注入到DI容器中的在MVC中所有的注入都是使用 TryAddXXX 的形式也就是如果容器中已经有相关服务的话将不会添加新注册的服务所以如果你有一些服务需要进行重写的话需要在 builder.AddMvc() 之前注册到DI中。 我们先看一下 AddMvc 的返回值 IMvcBuilder , IMvcBuilder 是一个针对 IServiceCollection 包装的一个接口除了IServiceCollection之外还有一个 ApplicationPartManager 。那么它是干嘛的呢 从命名来看 ApplicationPartManager 是用来管理 ApplicationPart 的那么其实除了里面 ApplicationPart 之外还有 IApplicationFeatureProvider。
public interface IMvcBuilder{IServiceCollection Services { get; }ApplicationPartManager PartManager { get; }
}
ApplicationPart
它是 MVC Core 中引用的一个抽象的概念它允许你暴露一些特性或者一些已知的资源比如一些元数据信息发布的资源磁盘的文件等。 你可以在应用程序启动的时候进行 ApplicationPart 的配置它是作为 IMvcBuilder 扩展的一部分。 目前 MVC 框架针对 ApplicationPart 的默认实现只有 AssemblyPart当然你可以根据需要进行扩展。
ApplicationPartManager
private static void AddDefaultFrameworkParts(ApplicationPartManager partManager){ var mvcTagHelpersAssembly typeof(InputTagHelper).GetTypeInfo().Assembly; if(!partManager.ApplicationParts.OfTypeAssemblyPart().Any(p p.Assembly mvcTagHelpersAssembly)){partManager.ApplicationParts.Add(new AssemblyPart(mvcTagHelpersAssembly));} var mvcRazorAssembly typeof(UrlResolutionTagHelper).GetTypeInfo().Assembly; if(!partManager.ApplicationParts.OfTypeAssemblyPart().Any(p p.Assembly mvcRazorAssembly)){partManager.ApplicationParts.Add(new AssemblyPart(mvcRazorAssembly));}
}
提供了从 IApplicationFeatureProvider 列表初始化 ApplicationPart 的功能例如 FeatureProviders 可以是 ControllerFeatureProvider 它可以通过从 ApplicationPart 列表中的暴露出来的类型来找到哪些是 Controller并且把这些 Controller 添加到 ControllerFeature 中那么在应用程序中这些被保存的 Controller 就将被视为控制器。 其实就是在 MVC 框架启动的时候首先会把 Assembly 程序集转换为 ApplicationPart 添加到 ApplicationPartManager 对象列表中才能执行后续的任务因为要从这些程序集中查找 Controller那么从这个特性我们可以延伸到 利用此功能我们可以从 Web 层剥离 Controller 到其他程序集中。 MVC 加载程序集主要是依靠 DefaultAssemblyPartDiscoveryProvider 这个类提供的功能它是一个静态类位于 Microsoft.AspNetCore.Mvc.Internal 命名空间有需要的同学可以直接使用。
下面是 AddMvc 的内部函数列表它将每一个模块相关的服务封装成了一个 AddXXX 的拓展函数。 我们依次来看一下这些注册到 Services 中 AddXXX 内部都又注册了哪些东西。
AddMvcCore
根据命名我们可以看到它是MVC的核心服务下面是一张图罗列出了 MvcCore 内部注册的一些注册的接口我们可以看到有非常的多。 这个图注册的服务比较多我就不一一说明了有几个关键的服务还是要说一下的。
Action相关
先是 Action 相关的一些服务可以说他们承载了 Mvc Core 中的核心
IActionDescriptorCollectionProvider ActionDescriptorCollection 的提供程序在内部他会对 Action 进行整理然后我们可以在他的属性 ActionDescriptors 读取到相关信息。
ActionDescriptor这个可能大家比较熟悉它封装了Action上下文的很多信息也就是Action的描述符。
ApplicationModel MVC 应用程序的一个实体包含了 Controller 信息Filters信息属性信息等框架根据 ApplicationModel 存储的这些信息来构建(Build) ControllerActionDescriptor 列表。
ControllerActionDescriptor 一个继承自 ActionDescriptor的类新增了一些关于 ControllerName ActionName MethodInfo 等属性。
IActionSelector我们知道当一个路由到我们MVC系统的时候有可能这个路由会匹配到多个Action与其相符合那么如何选着最合适的路由处理程序呢 这个接口主要封装了相关逻辑。
还有 IControllerActivator ,IControllerActivator ,IActionInvokerFactory 我们将在下一篇中介绍。
然后是一些 Infrastructure 的一些服务主要是一些Request 和 Response 流的处理还有 xxxResult 的一些执行程序。
路由相关
MvcRouteHandler, MvcAttributeRouteHandler 这两个我们留到下一篇介绍。
模型绑定验证相关
IModelMetadataProvider从方法类型的元数据中获取信息。IModelBinderFactory模型绑定工厂。IObjectModelValidator模型验证。
关于模型绑定和验证后面我应该会单独有一篇博客介绍细节。
AddViews Views 注入的服务主要包括视图引擎、Html Helper 相关、Json Helper、View Components、CookieTempData、Antiforgery 等。
AddRazorViewEngine
在 AddRazorViewEngine 中又一次执行了 builder.AddViews() 不知道这个是 Bug 还是故意这样的 我猜测有可能是一些地方单独使用视图引擎做一些操作而 AddRazorViewEngine 又依赖于 AddViews 中提供的一些服务所以又重新执行了 AddView()。 经过 github 的 issue 印证这并不是 bug而是设计如此。开发团队在实现这一块的功能的时候AddXXX 的 设计策略就是会自动添加依赖的服务因为这样比较更加友好这种形式对于添加什么服务也更加的明确。 当然他们也讲到将很多的碎片服务再进行碎片的细分是非常复杂的有时候会有点不切实际所以此处不得不如此。 接下来又向 ApplicationPartMangager 里面的 FeatureProviders 添加了 TagHelperFeatureProviderMetadataReferenceFeatureProviderViewsFeatureProvider 的实例。 AddRazorPages
处理Razor Pages 中的一些业务操作在 AddRazorPages 中又一次调用了 AddRazorViewEngine() 而 AddRazorViewEngine 里面又调用了 AddView() 又此可见这些组件都是环环相扣的他们都有自己的机制来确保服务的健全。 AddCacheTagHelper
添加 MVC Cache Tag Helper 服务。 在这个注册的服务中有两个关于缓存的服务一个是 IDistributedCache 另外一个是 IMemoryCache当你主动注册一个IDistributedCache的时候将会使用你注册的IDistributedCache。
AddDataAnnotations
注册了以下两个服务我就不画图了。
MvcDataAnnotationsMvcOptionsSetupIValidationAttributeAdapterProvider
处理 Mvc Model 中数据注解相关业务第一个 MvcDataAnnotationsMvcOptionsSetup 将会在 MvcOptions 的 ModelMetadataDetailsProviders 属性中添加 DataAnnotationsMetadataProvider 和 DataAnnotationsModelValidatorProvider
MvcDataAnnotationsMvcOptionsSetup 实现了 IConfigureOptionsMvcOptions, 下面是它的 Configure 方法。
public void Configure(MvcOptions options){ if (options null){ throw new ArgumentNullException(nameof(options));}options.ModelMetadataDetailsProviders.Add(new DataAnnotationsMetadataProvider(_dataAnnotationLocalizationOptions,_stringLocalizerFactory));options.ModelValidatorProviders.Add(new DataAnnotationsModelValidatorProvider(_validationAttributeAdapterProvider,_dataAnnotationLocalizationOptions,_stringLocalizerFactory));
}
AddJsonFormatterServices
MvcJsonMvcOptionsSetupJsonPatchOperationsArrayProviderJsonResultExecutor
关于MVC 输入 Json 格式化的配置项还有 JsonResultExecutor。 以及 JsonPatch 的相关操作。
有些同学可能对 JsonPatch 不太了解那么 JsonPatch 是什么东西呢 JSON Patch 在 IETF 中规范是 RFC 6902。 JSON Patch 是一个用来描述 JSON 文档变化的格式它本身也是 JSON 文档。它可以用于避免在只有一个节点更改时发送整个文档。当与HTTP PATCH方法组合使用时它允许以符合标准的方式对HTTP API进行部分更新。例如
源文件
{baz: qux,foo: bar}
Patch
[{ op: replace, path: /baz, value: boo },{ op: add, path: /hello, value: [world] },{ op: remove, path: /foo]
结果
{baz: boo,hello: [world]
}
那么 ASP.NET Core 中微软对 RFC 6902 协议的实现位于 Microsoft.AspNetCore.JsonPatch 这个 NuGet 包里面。
MVC 框架针对于 Json Patch 提供了一扩展方法 JsonPatchExtensions需要的同学自行使用。
AddCors
IApplicationModelProvider , CorsApplicationModelProviderCorsAuthorizationFilter
下面是 CorsApplicationModelProvider 执行的时候的代码就是向 ControllerModel 中添加 Filter
public void OnProvidersExecuting(ApplicationModelProviderContext context){IEnableCorsAttribute enableCors;IDisableCorsAttribute disableCors; foreach (var controllerModel in context.Result.Controllers){enableCors controllerModel.Attributes.OfTypeIEnableCorsAttribute() .FirstOrDefault(); if (enableCors ! null){controllerModel.Filters.Add(new CorsAuthorizationFilterFactory(enableCors.PolicyName));}disableCors controllerModel.Attributes.OfTypeIDisableCorsAttribute() .FirstOrDefault(); if (disableCors ! null){controllerModel.Filters.Add(new DisableCorsAuthorizationFilter());} foreach (var actionModel in controllerModel.Actions){enableCors actionModel.Attributes.OfTypeIEnableCorsAttribute().FirstOrDefault(); if (enableCors ! null){actionModel.Filters.Add(new CorsAuthorizationFilterFactory(enableCors.PolicyName));}disableCors actionModel.Attributes.OfTypeIDisableCorsAttribute().FirstOrDefault(); if (disableCors ! null){actionModel.Filters.Add(new DisableCorsAuthorizationFilter());}}}
}
其中 CorsAuthorizationFilterFactory 的实例会创建 CorsAuthorizationFilter 。 有关 Cors 的更多示例可以看这里。
UseMvc
UseMvc 的主要过程是Router中间件的初始化和启动过程关于Router中间件可以看一下我的上一篇文章执行流程如下
1、构建 middlewarePipelineBuilder它是一个新的 ApplicationBuilder 实例。
2、在UseMvc中主要是应用 Router 中间件进行路由拦截。
3、构建 RouterBuilder , 添加或配置 IRouteBuilder。
4、使用IRouteBuilder 注册 Router 中间件。
总结
本篇文章主要是根据源码分析了 MVC 中间件在启动的过程中都注册了哪些服务以及这些服务在MVC构建的过程中都起到了什么作用 那么他是怎么和Router中间件进行配合的呢我们下一篇来分析 Controller Action 的激活和 MVC 的执行流程。 相关文章
ASP.NET Core MVC 源码学习Routing 路由
原文地址http://www.cnblogs.com/savorboard/p/aspnetcore-mvc-startup.html.NET社区新闻深度好文微信中搜索dotNET跨平台或扫描二维码关注