剖析ASP.NET Core MVC(Part 1)- AddMvcCore(译)
2021-06-18 06:05
标签:个人 基础 ict 有趣 服务集 对象存储 assembly 不包含 .net 原文:https://www.stevejgordon.co.uk/asp-net-core-mvc-anatomy-addmvccore 欢迎阅读新系列的第一部分,我将剖析MVC源代码,给大家展示隐藏在表面之下的工作机制。此系列将分析MVC的内部,如果觉得枯燥,可以停止阅读。但就我个人而言,也是经过反复阅读、调试甚至抓狂,直到最后理解ASP.NET MVC源代码(或者自认为理解),从中获益匪浅。通过了解框架的运作机制,我们可以更好的使用它们,更容易解决遇到的问题。 我会尽力给大家解释对源码的理解,我不能保证自己的理解和解释是100%正确,但我会竭尽所能。要知道简洁清晰的把一段代码解释清楚是很困难的,我将通过小块代码展示MVC源代码,并附源文件链接,方便大家追踪。阅读之后如果仍不理解,我建议你花些时间读读源代码,必要时亲自动手调试一下。我希望此系列会引起像我一样喜欢刨根问底的人的兴趣。 本文我将剖析AddMvcCore到底为我们做了什么,同时关注几个像 ApplicationPartManager这样的类。本文使用的project.json基于rel/1.1.2源代码,通过运行MVC Sandbox 项目进行调试。 由于版本在不断更新,一些类和方法可能会改变,尤其是内部。请始终参考GitHub上的最新代码。对于MvcSandbox ConfigureServices我已作更新: AddMvcCore是IServiceCollection的扩展方法。通常把一组关联的服务注册到服务集合(services collection)时都使用扩展方法这种模式。在构建MVC应用时,有两个扩展方法用来注册MVC服务(MVC Services),AddMvcCore是其中之一。相对AddMvc方法,AddMvcCore提供较少的服务子集。一些不需要使用MVC所有特性的简单程序,就可以使用AddMvcCore。比如在构建REST APIs,就不需要Razor相关组件,我一般使用AddMvcCore。你也可以在AddMvcCore之后手动添加额外的服务,或者直接使用功能更多的AddMvc。AddMvcCore的实现: AddMvcCore做的第一件事就是通过GetApplicationPartManager静态方法获得ApplicationPartManager,把IServiceCollection作为参数传递给GetApplicationPartManager。 本方法首先检查当前已注册的服务中是否有ApplicationPartManager,通常情况是没有的,但极少情况你可能在调用AddMvcCore之前注册了其它服务。ApplicationPartManager如果不存在则创建一个新的。 接下来的代码是计算ApplicationPartManager的ApplicationParts属性值。首先从服务集合(services collection)中获得IHostingEnvironment。如果能够获IHostingEnvironment实例,则通过它获得程序名或封装名(application/assem bly name),然后传递给静态方法DefaultAssemblyPartDiscoveryProvider,DiscoverAssemblyParts方法将返回IEnumerable。 DiscoverAssemblyParts 首先通过封装名(assembly name)获得封装对象(Assembly Object)和DependencyContex。本例封装名为“MvcSandbox”。然后将这些值传递给GetCandidateAssemblies方法,GetCandidateAssemblies再调用GetCandidateLibraries方法。 解释一下GetCandidateLibraries做了什么: 它返回一个在 更明确一些,获得的程序集列表包含了我们的解决方案中引用的所有MVC程序集。 ReferenceAssemblies是一个定义在DefaultAssemblyPartDiscoveryProvider类中静态HashSet GetCandidateLibraries使用CandidateResolver类定位并返回“候选人”。CandidateResolver 通过运行时对象(RuntimeLibrary objects)和ReferenceAssemblies构造。每个运行时对象依次迭代并添加到一个字典中,添加过程中检查依赖名(dependency name)是否唯一,如果不唯一则抛出异常。 每个依赖对象(既RuntimeLibrary)都作为新的依赖对象存储到字典中。这些对象包含一个DependencyClassification属性,用来筛选需要的libraries (candidates)。DependencyClassification是一个枚举类型: 创建Dependency的时候,如果与ReferenceAssemblies HashSet匹配,则标记为MvcReference,其余标记为Unknown。 当CandidateResolver.GetCandidates方法被调用时,结合ComputeClassification方法,遍历整个依赖对象树。每个依赖对象都将检查他的所有子项,直到匹配Candidate或者MvcReference,同时标记父依赖项为Candidate类型。遍历结束将返回包含identified candidates的IEnumerable DiscoverAssemblyParts将返回的candidates转换为新的AssemblyPart。此对象是对程序集的简单封装,只包含了如名称、类型等主要封装属性。后续我可能单独撰文分析此类。 最后,通过GetApplicationPartManager,AssemblyParts被加入到ApplicationPartManager。 返回的ApplicationPartManager实例通过AddMvcCore扩展方法加入到services collection。 接下来AddMvcCore把ApplicationPartManager作为参数调用静态ConfigureDefaultFeatureProviders方法,为ApplicationPartManager的FeatureProviders添加ControllerFeatureProvider。 ControllerFeatureProvider将被用在ApplicationPar的实例中发现controllers。我将在后续的博文中介绍ControllerFeatureProvider。现在我们继续研究AddMovCore的最后一步。(ApplicationPartManager此时已更新) 首先调用私有方法ConfigureDefaultServices,通过Microsoft.AspNetCore.Routing提供的AddRouting扩展方法开启routing功能。它提供启用routing功能所需的必要服务和配置。本文不对此作详细描述。 AddMvcCore接下来调用另一个私有方法AddMvcCoreServices,该方法负责注册MVC核心服务,包括框架可选项,action 的发现、选择和调用,controller工厂,模型绑定和认证。 最后AddMvcCore通过services collection和ApplicationPartManager,构造一个新的MvcCoreBuilder对象。此类被叫做: 允许细粒度的配置MVC基础服务(Allows fine grained configuration of essential MVC services.) AddMvcCore扩展方法返回MvcCoreBuilder,MvcCoreBuilder包含IserviceCollection和ApplicationPartManager属性。MvcCoreBuilder和其扩展方法用在AddMvcCore初始化之后做一些额外的配置。实际上,AddMvc方法中首先调用的是AddMvcCore,然后使用MvcCoreBuilder配置额外的服务。 要把上述所有问题都解释清楚不是件容易的事,所以简单总结一下。本文我们分析的是MVC底层代码,主要实现了把MVCs需要的服务添加到IserviceCollection中。通过追踪ApplicationPartManager的创建过程,我们了解了MVC如何一步步创建内部应用模型(ApplicationModel)。虽然我们并没有看到很多实际的功能,但通过对startup的跟踪分析我们发现了许多有趣的东西,这为后续分析奠定了基础。 剖析ASP.NET Core MVC(Part 1)- AddMvcCore(译) 标签:个人 基础 ict 有趣 服务集 对象存储 assembly 不包含 .net 原文地址:http://www.cnblogs.com/lookerblue/p/7262907.html
发布于:2017年3月
环境:ASP.NET Core 1.1AddMvcCore
注:MvcSandbox为ASP.Net Core MVC源码中的示列项目。
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore();
}
public static IMvcCoreBuilder AddMvcCore(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
var partManager = GetApplicationPartManager(services);
services.TryAddSingleton(partManager);
ConfigureDefaultFeatureProviders(partManager);
ConfigureDefaultServices(services);
AddMvcCoreServices(services);
var builder = new MvcCoreBuilder(services, partManager);
return builder;
}
GetApplicationPartManager的实现:private static ApplicationPartManager GetApplicationPartManager(IServiceCollection services)
{
var manager = GetServiceFromCollection(services);
if (manager == null)
{
manager = new ApplicationPartManager();
var environment = GetServiceFromCollection
public static IEnumerable DiscoverAssemblyParts(string entryPointAssemblyName)
{
var entryAssembly = Assembly.Load(new AssemblyName(entryPointAssemblyName));
var context = DependencyContext.Load(Assembly.Load(new AssemblyName(entryPointAssemblyName)));
return GetCandidateAssemblies(entryAssembly, context).Select(p => new AssemblyPart(p));
}
internal static IEnumerable GetCandidateAssemblies(Assembly entryAssembly, DependencyContext dependencyContext)
{
if (dependencyContext == null)
{
// Use the entry assembly as the sole candidate.
return new[] { entryAssembly };
}
return GetCandidateLibraries(dependencyContext)
.SelectMany(library => library.GetDefaultAssemblyNames(dependencyContext))
.Select(Assembly.Load);
}
internal static IEnumerable
internal static HashSetstring> ReferenceAssemblies { get; } = new HashSetstring>(StringComparer.OrdinalIgnoreCase)
{
"Microsoft.AspNetCore.Mvc",
"Microsoft.AspNetCore.Mvc.Abstractions",
"Microsoft.AspNetCore.Mvc.ApiExplorer",
"Microsoft.AspNetCore.Mvc.Core",
"Microsoft.AspNetCore.Mvc.Cors",
"Microsoft.AspNetCore.Mvc.DataAnnotations",
"Microsoft.AspNetCore.Mvc.Formatters.Json",
"Microsoft.AspNetCore.Mvc.Formatters.Xml",
"Microsoft.AspNetCore.Mvc.Localization",
"Microsoft.AspNetCore.Mvc.Razor",
"Microsoft.AspNetCore.Mvc.Razor.Host",
"Microsoft.AspNetCore.Mvc.TagHelpers",
"Microsoft.AspNetCore.Mvc.ViewFeatures"
};
public CandidateResolver(IReadOnlyList
private enum DependencyClassification
{
Unknown = 0,
Candidate = 1,
NotCandidate = 2,
MvcReference = 3
}
private Dependency CreateDependency(RuntimeLibrary library, ISetstring> referenceAssemblies)
{
var classification = DependencyClassification.Unknown;
if (referenceAssemblies.Contains(library.Name))
{
classification = DependencyClassification.MvcReference;
}
return new Dependency(library, classification);
}
public IEnumerable
var parts = DefaultAssemblyPartDiscoveryProvider.DiscoverAssemblyParts(environment.ApplicationName);
foreach (var part in parts)
{
manager.ApplicationParts.Add(part);
}
}
return manager;
private static void ConfigureDefaultFeatureProviders(ApplicationPartManager manager)
{
if (!manager.FeatureProviders.OfType
小结
文章标题:剖析ASP.NET Core MVC(Part 1)- AddMvcCore(译)
文章链接:http://soscw.com/essay/95364.html