扒一扒asp.net core mvc控制器的寻找流程
不太会排版,大家将就看吧.
asp.net core mvc和asp.net mvc中都有一个比较有意思的而又被大家容易忽略的功能,控制器可以写在非Web程序集中,比如Web程序集:"MyWeb",引用程序集"B.bll",你可以将所有的控制器写在"B.bll"程序集里面.mvc框架仍然可以寻找到这个控制器.
仔细想一想,mvc框架启动的时候寻找过程:1.找到所有包含控制器的程序集;2.反射找到所有控制器类型;3.反射找到所有的action;4.缓存这些controller与action.
那么有意思的就是第一步"找到所有包含控制器的程序集",一开始我认为是扫描当前应用程序域已加载的程序集,然后反射判断存不存在控制器类型.单如果一个程序有上千个程序集,那么反射无疑是一种灾难,mvc的启动也没这么慢啊,怀着好奇的心,这里就扒一扒官方的实现原理(asp.net mvc源码没去看,但原理估计差不多,这里就扒asp.net core mvc).
这里建议大家先了解下 asp.net core mvc的启动流程:http://www.cnblogs.com/savorboard/p/aspnetcore-mvc-startup.html.
action的匹配:http://www.cnblogs.com/savorboard/p/aspnetcore-mvc-routing-action.html
这里引用杨晓东博客中的图片:
1.AddMvcCore,mvc核心启动代码:
- public static IMvcCoreBuilder AddMvcCore(this IServiceCollection services)
- {
- if (services == null)
- {
- throw new ArgumentNullException(nameof(services));
- }
- //获取ApplicationPartManager管理类,该类保存了ApplicationPart集合,而ApplicationPart最重要的子类AssemblyPart记录了程序集信息,另外PopulateFeature用于填充各种功能
- var partManager = GetApplicationPartManager(services);
- services.TryAddSingleton(partManager);
- ConfigureDefaultFeatureProviders(partManager);
- ConfigureDefaultServices(services);
- AddMvcCoreServices(services);
- var builder = new MvcCoreBuilder(services, partManager);
- return builder;
- }
ApplicationPartManager:
- /// <summary>
- /// Manages the parts and features of an MVC application.
- /// </summary>
- public class ApplicationPartManager
- {
- /// <summary>
- /// Gets the list of <see cref="IApplicationFeatureProvider"/>s.
- /// </summary>
- public IList<IApplicationFeatureProvider> FeatureProviders { get; } =
- new List<IApplicationFeatureProvider>();
- /// <summary>
- /// Gets the list of <see cref="ApplicationPart"/>s.
- /// </summary>
- public IList<ApplicationPart> ApplicationParts { get; } =
- new List<ApplicationPart>();
- /// <summary>
- /// Populates the given <paramref name="feature"/> using the list of
- /// <see cref="IApplicationFeatureProvider{TFeature}"/>s configured on the
- /// <see cref="ApplicationPartManager"/>.
- /// </summary>
- /// <typeparam name="TFeature">The type of the feature.</typeparam>
- /// <param name="feature">The feature instance to populate.</param>
- public void PopulateFeature<TFeature>(TFeature feature)
- {
- if (feature == null)
- {
- throw new ArgumentNullException(nameof(feature));
- }
- foreach (var provider in FeatureProviders.OfType<IApplicationFeatureProvider<TFeature>>())
- {
- provider.PopulateFeature(ApplicationParts, feature);
- }
- }
- }
- private static ApplicationPartManager GetApplicationPartManager(IServiceCollection services)
- {
- var manager = GetServiceFromCollection<ApplicationPartManager>(services);
- if (manager == null)
- {
- manager = new ApplicationPartManager();
- var environment = GetServiceFromCollection<IHostingEnvironment>(services);
- if (string.IsNullOrEmpty(environment?.ApplicationName))
- {
- return manager;
- }
- //使用默认的程序集发现提供器查找程序集,这个类就是查找的核心类
- var parts = DefaultAssemblyPartDiscoveryProvider.DiscoverAssemblyParts(environment.ApplicationName);
- foreach (var part in parts)
- {
//将找到的程序集添加到集合中- manager.ApplicationParts.Add(part);
- }
- }
- return manager;
- }
2.DefaultAssemblyPartDiscoveryProvider:
- public static IEnumerable<ApplicationPart> DiscoverAssemblyParts(string entryPointAssemblyName)
- {
//使用应用程序名称加载应用程序的入口程序集- var entryAssembly = Assembly.Load(new AssemblyName(entryPointAssemblyName));
- var context = DependencyContext.Load(entryAssembly);
//找到候选的程序集,这里就是"可能"包含了控制器的程序集- return GetCandidateAssemblies(entryAssembly, context).Select(p => new AssemblyPart(p));
- }
DefaultAssemblyPartDiscoveryProvider代码我就不全贴了(点击查看完整源码),
这里使用了一个DependencyContext依赖上下文,注意这个依赖上下文不是依赖注入的那个上下文,这个是指程序集引用关系的依赖上下文.
实现原理看起来其实有点low,就是递归计算并判断程序集是否有引用mvc程序集,如果有引用就作为候选程序集.
这里看核心的一个计算方法:
- private DependencyClassification ComputeClassification(string dependency)
- {
- if (!_runtimeDependencies.ContainsKey(dependency))
- {
- // Library does not have runtime dependency. Since we can't infer
- // anything about it's references, we'll assume it does not have a reference to Mvc.
- return DependencyClassification.DoesNotReferenceMvc;
- }
- var candidateEntry = _runtimeDependencies[dependency];
- if (candidateEntry.Classification != DependencyClassification.Unknown)
- {
- return candidateEntry.Classification;
- }
- else
- {
- var classification = DependencyClassification.DoesNotReferenceMvc;
- foreach (var candidateDependency in candidateEntry.Library.Dependencies)
- {
- var dependencyClassification = ComputeClassification(candidateDependency.Name);
- if (dependencyClassification == DependencyClassification.ReferencesMvc ||
- dependencyClassification == DependencyClassification.MvcReference)
- {
- classification = DependencyClassification.ReferencesMvc;
- break;
- }
- }
- candidateEntry.Classification = classification;
- return classification;
- }
- }
拿到所有候选程序集(就是可能包含控制器的程序集)后,就是调用ApplicationPartManager的PopulateFeature将控制器类型缓存起来.至于后面的action什么的就不再扒了,有兴趣的可以看源代码.
从这个过程可以发现DependencyContext这个类,以及Microsoft.Extensions.DependencyModel这个库,那么我们可以利用这个东西也可以玩出很多花样来.
哦 再补充一个点,我们可以外挂式的加载程序集:
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddMvc()
- .AddApplicationPart(Assembly.LoadFrom(@"C:\demo\demo.dll"));
- }
那么从这个点,你又想到了什么?我想到了.net core mvc插件化的思路.
扒一扒asp.net core mvc控制器的寻找流程的更多相关文章
- ASP.NET Core 入门教程 4、ASP.NET Core MVC控制器入门
一.前言 1.本教程主要内容 ASP.NET Core MVC控制器简介 ASP.NET Core MVC控制器操作简介 ASP.NET Core MVC控制器操作简介返回类型简介 ASP.NET C ...
- ASP.NET Core 入门笔记5,ASP.NET Core MVC控制器入门
摘抄自https://www.cnblogs.com/ken-io/p/aspnet-core-tutorial-mvc-controller-action.html 一.前言 1.本教程主要内容 A ...
- ASP.NET Core MVC 控制器创建与依赖注入
本文翻译自<Controller activation and dependency injection in ASP.NET Core MVC>,由于水平有限,故无法保证翻译完全准确,欢 ...
- asp.net core mvc剖析:启动流程
asp.net core mvc是微软开源的跨平台的mvc框架,首先它跟原有的MVC相比,最大的不同就是跨平台,然后又增加了一些非常实用的新功能,比如taghelper,viewcomponent,D ...
- Asp.Net Core MVC控制器和视图之间传值
一.Core MVC中控制器和视图之间传值方式和Asp.Net中非常类似 1.弱类型数据:ViewData,ViewBag 2.强类型数据:@model 二.代码 实例 1.ViewData pub ...
- asp.net core MVC 控制器,接收参数,数据绑定
1.参数 HttpRequest HttpRequest 是用户请求对象 QueryString Form Cookie Session Header 实例: public IActionResult ...
- Pro ASP.NET Core MVC 第6版 第二章(前半章)
目录 第二章 第一个MVC 应用程序 学习一个软件开发框架的最好方法是跳进他的内部并使用它.在本章,你将用ASP.NET Core MVC创建一个简单的数据登录应用.我将它一步一步地展示,以便你能看清 ...
- Pro ASP.NET Core MVC 第6版 第一章
目录 第一章 ASP.NET Core MVC 的前世今生 ASP.NET Core MVC 是一个微软公司开发的Web应用程序开发框架,它结合了MVC架构的高效性和简洁性,敏捷开发的思想和技术和.N ...
- ASP.NET Core MVC 之视图(Views)
ASP.NET Core MVC 控制器可以使用视图返回格式化的结果. 1.什么是视图 在 MVC 中,视图封装了用户与应用交互呈现细节.视图是具有生成要发送到客户端内容的,包含嵌入代码的HTML模板 ...
随机推荐
- flask的文件上传和下载
http://flask.pocoo.org/docs/1.0/api/ http://docs.jinkan.org/docs/flask/api.html?highlight=download h ...
- php之文件类型解析漏洞防御与攻击
php在处理文件上传时,经常可以用到下面几种方式来判断文件的类型 1.通过文件名后缀,不安全,非常容易欺骗2.通过mime判断,部分类型的文件通过修改文件后缀名,也可以欺骗服务器3.通过头字节判断文件 ...
- [Python爬虫] 之十七:Selenium +phantomjs 利用 pyquery抓取梅花网数据
一.介绍 本例子用Selenium +phantomjs爬取梅花网(http://www.meihua.info/a/list/today)的资讯信息,输入给定关键字抓取资讯信息. 给定关键字:数字: ...
- subscription group permisson
- iOS开发中经常使用的Xcode插件
1.全能搜索家CodePilot 2.0 你要找的是文件?是目录?是代码?Never Mind,CMD+SHIFT+X调出CodePilot,输入不论什么你想到搜的东西吧! 想搜appFinishLa ...
- knowledgeroot 配置
首先下载 KnowledgeRoot 的安装包,就是一个压缩文件,解压缩后放到 WebRoot 下面 在浏览器中打开网站,自动提示进行安装,安装的过程很简单,安装结束后即可以使用. 安装包创建的数据库 ...
- B5:责任链模式 Chain Of Responsibility
使多个对象都有机会处理处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着该链处理请求,直到有一个对象能够处理它为止. 相当于switch/case,在客户端指定了每一链 ...
- 微信小程序bindtap和catchtap区别
bindtap可以产生冒泡事件 catchtap只自身触发事件,不会传递到父视图 文章来源:刘俊涛的博客 地址:http://www.cnblogs.com/lovebing 欢迎关注 ...
- Grow heap (frag case) to 6.437MB for 1114126-byte allocation
本篇文章是对Grow heap (frag case) 堆内存过大的问题进行了详细的分析介绍,需要的朋友参考下 对于Android开发者来说虽然使用了可以自动管理内存的Java语言,但是对于内存管理不 ...
- iOS开发-发送邮件(E-mail)方法整理合集(共3种)
前言:在IOS开发中,有时候我们会需要用到邮件发送的功能.比如,接收用户反馈和程序崩溃通知等等.其实这个功能是很常用的,因为我目前就有发送邮件的开发需求,所以顺便整理下IOS发送邮件的方法. IOS原 ...