不太会排版,大家将就看吧.

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控制器的寻找流程的更多相关文章

  1. ASP.NET Core 入门教程 4、ASP.NET Core MVC控制器入门

    一.前言 1.本教程主要内容 ASP.NET Core MVC控制器简介 ASP.NET Core MVC控制器操作简介 ASP.NET Core MVC控制器操作简介返回类型简介 ASP.NET C ...

  2. ASP.NET Core 入门笔记5,ASP.NET Core MVC控制器入门

    摘抄自https://www.cnblogs.com/ken-io/p/aspnet-core-tutorial-mvc-controller-action.html 一.前言 1.本教程主要内容 A ...

  3. ASP.NET Core MVC 控制器创建与依赖注入

    本文翻译自<Controller activation and dependency injection in ASP.NET Core MVC>,由于水平有限,故无法保证翻译完全准确,欢 ...

  4. asp.net core mvc剖析:启动流程

    asp.net core mvc是微软开源的跨平台的mvc框架,首先它跟原有的MVC相比,最大的不同就是跨平台,然后又增加了一些非常实用的新功能,比如taghelper,viewcomponent,D ...

  5. Asp.Net Core MVC控制器和视图之间传值

    一.Core MVC中控制器和视图之间传值方式和Asp.Net中非常类似 1.弱类型数据:ViewData,ViewBag 2.强类型数据:@model 二.代码 实例  1.ViewData pub ...

  6. asp.net core MVC 控制器,接收参数,数据绑定

    1.参数 HttpRequest HttpRequest 是用户请求对象 QueryString Form Cookie Session Header 实例: public IActionResult ...

  7. Pro ASP.NET Core MVC 第6版 第二章(前半章)

    目录 第二章 第一个MVC 应用程序 学习一个软件开发框架的最好方法是跳进他的内部并使用它.在本章,你将用ASP.NET Core MVC创建一个简单的数据登录应用.我将它一步一步地展示,以便你能看清 ...

  8. Pro ASP.NET Core MVC 第6版 第一章

    目录 第一章 ASP.NET Core MVC 的前世今生 ASP.NET Core MVC 是一个微软公司开发的Web应用程序开发框架,它结合了MVC架构的高效性和简洁性,敏捷开发的思想和技术和.N ...

  9. ASP.NET Core MVC 之视图(Views)

    ASP.NET Core MVC 控制器可以使用视图返回格式化的结果. 1.什么是视图 在 MVC 中,视图封装了用户与应用交互呈现细节.视图是具有生成要发送到客户端内容的,包含嵌入代码的HTML模板 ...

随机推荐

  1. 小二助手(react应用框架)-概述

    时间想学习一个前端框架,原因是这样的,我本身是做游戏的,但是自己对前端web比较感兴趣. 然后我就选择自己学哪个框架,Angular.react.vue 最后选择了react,选择的理由就不说了 那做 ...

  2. python 列表合并

    列表合并主要有以下方法: 1.用list的extend方法,L1.extend(L2),该方法将参数L2的全部元素添加到L1的尾部 结果:[1, 2, 3, 4, 5, 1, 20, 30] 2.用切 ...

  3. Unity3D教程宝典之Web服务器篇:(第三讲)PHP的Hello World

    转载自风宇冲Unity3D教程学院 引言:PHP是比较简单的编程语言,即使没接触过的也可以现学现用.PHP教程文档PHP100视频教程                           Unity接 ...

  4. FBXImport

    using UnityEditor; public class MyEditor : AssetPostprocessor{ public void OnPreprocessModel() { Mod ...

  5. Excel 将换行符替换为空

          Step1:按快捷键Ctrl+H,打开"查找和替换"对话框:     Step2:选择"查找内容"后的文本框,按住Alt键,在数字键盘中输入&quo ...

  6. 利用HTML5 Canvas和Javascript实现的蚁群算法求解TSP问题演示

    HTML5提供了Canvas对象,为画图应用提供了便利. Javascript可执行于浏览器中, 而不须要安装特定的编译器: 基于HTML5和Javascript语言, 可随时编写应用, 为算法測试带 ...

  7. 无线网络RSSI、SSID、BSSID

    获取无线网络,及无线网络的参数之前,我们先了解一下RSSI,SSID和BSSID分别是什么,当然你可以去百度或者维基百科查阅,我这里只是简单的说明一下.RSSI就是无线网络的信号强度,这个是和无线AP ...

  8. sshd服务安装和配置管理

    1.SSHD简介(介绍) SSH协议:安全外壳协议,为Secure Shell的缩写,SSH为建立在应用层和传输层基础上的安全协议. sshd服务使用SSH协议可以用来进行远程控制,或在计算机之间传送 ...

  9. RapidIO协议(1)

    RapidIO协议 1.概述 1.1介绍 RapidIO是基于包交换互联协议,主要作为系统内部接口使用,如:芯片间.板间的通讯,速度能在GB/S数量级.如连接处理器.内存.内存映射的I/O设备.这些设 ...

  10. dos指令 批处理文件

    windows下开发的时候难免写一些脚本,脚本的调用又难以避免的写批处理文件,也就是(.bat)文件!这个文件是什么呢?其实就是以下的这些dos命令.以下是从网上摘抄的,留以记录,待以后需要时查阅.也 ...