当前位置: 首页 > news >正文

上海网站建设设计公司/全网营销代理加盟

上海网站建设设计公司,全网营销代理加盟,网站外部链接做多少合适呢,网站后台管理系统的主要功能这些天一直在学习MVC的源码,深入学习后,发现自己不懂的真的是越来越多,为什么会有上一篇博客呢?在学习DefaultControllerFactory提供控制器的过程中,先是被路由中的MS_DirectRouteMatches这个Toeken值困惑,…

这些天一直在学习MVC的源码,深入学习后,发现自己不懂的真的是越来越多,为什么会有上一篇博客呢?在学习DefaultControllerFactory提供控制器的过程中,先是被路由中的MS_DirectRouteMatches这个Toeken值困惑,我知道他表示一个特性路由,但我想它是哪里来的呢?于是就有了上一篇博文,但是这两天就是和路由干上了,我知道还有一个区域路由的注册工作,还是Application_Start的的第一行代码,于是乎就有了这一篇博文。

AreaRegistration.RegisterAllAreas()

 我们新建一个名称为Admin的Area,VS生成下面的代码。

public class AdminAreaRegistration : AreaRegistration 
{public override string AreaName {get {return "Admin";}}public override void RegisterArea(AreaRegistrationContext context) {context.MapRoute("Admin_default","Admin/{controller}/{action}/{id}",new { action = "Index", id = UrlParameter.Optional });}
}

我们先来看AreaRegistration这个抽象类,实际上,它只有一个核心功能,就是RegisterAllAreas,获取所有继承它的子类类型,然后创建它,在为他创建一个AreaRegistrationContext,在调用它的RegisterArea方法。

public abstract class AreaRegistration
{private const string TypeCacheName = "MVC-AreaRegistrationTypeCache.xml";public abstract string AreaName { get; }internal static void RegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state){List<Type> areaRegistrationTypes = TypeCacheUtil.GetFilteredTypesFromAssemblies(TypeCacheName, IsAreaRegistrationType, buildManager);foreach (Type areaRegistrationType in areaRegistrationTypes){AreaRegistration registration = (AreaRegistration)Activator.CreateInstance(areaRegistrationType);registration.CreateContextAndRegister(routes, state);}}internal void CreateContextAndRegister(RouteCollection routes, object state){AreaRegistrationContext context = new AreaRegistrationContext(AreaName, routes, state);string thisNamespace = GetType().Namespace;if (thisNamespace != null){context.Namespaces.Add(thisNamespace + ".*");}RegisterArea(context);}public abstract void RegisterArea(AreaRegistrationContext context);
}

为什么要有AreaRegistrationContext这个类型呢?假如没有它,AreaRegistration子类创建完成时,就可以直接注册了,我们的AdminAreaRegistration的RegisterArea方法完全可以通过RouteCollection再重载一个MapRoute方法用于Area路由的注册。像下面这个样子。

public override void RegisterArea(RouteCollection routes) 
{routes.MapRoute("Admin_default","Admin/{controller}/{action}/{id}",new { action = "Index", id = UrlParameter.Optional });
}

 这样不是很好么?跟随着源码,详细瞧一瞧这个AreaRegistrationContext

AreaRegistrationContext

 这个类本质上只有一个属性,那就是命名空间。

public class AreaRegistrationContext
{private readonly HashSet<string> _namespaces = new HashSet<string>(StringComparer.OrdinalIgnoreCase);public AreaRegistrationContext(string areaName, RouteCollection routes, object state){ }public string AreaName { get; private set; }public ICollection<string> Namespaces{get { return _namespaces; }}public RouteCollection Routes { get; private set; }public object State { get; private set; }public Route MapRoute(string name, string url, object defaults, object constraints, string[] namespaces){ }
}

 我们回到核心的RegisterAllAreas方法中。

private static bool IsAreaRegistrationType(Type type)
{returntypeof(AreaRegistration).IsAssignableFrom(type) &&type.GetConstructor(Type.EmptyTypes) != null;
}
internal static void RegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state)
{List<Type> areaRegistrationTypes = TypeCacheUtil.GetFilteredTypesFromAssemblies(TypeCacheName, IsAreaRegistrationType, buildManager);foreach (Type areaRegistrationType in areaRegistrationTypes){AreaRegistration registration = (AreaRegistration)Activator.CreateInstance(areaRegistrationType);registration.CreateContextAndRegister(routes, state);}
}

通过TypeCacheUtil.GetFilteredTypesFromAssemblies获取出来的类型必须符合IsAreaRegistrationType委托,(AreaRegistration).IsAssignableFrom(type)不难理解,必须是AreaRegistration的子类,那type.GetConstructor(Type.EmptyTypes)呢?其实一开始我也不明白它是什么意思,后来通过Console写了个小程序测试了下。

class TA
{TA(){}
}
class TB
{TB(){}TB(int i){}
}
class TC
{}
class Program
{static void Main(string[] args){Type ta = typeof(TA);var tac = ta.GetConstructor(Type.EmptyTypes);Type tb = typeof(TB);var tbc = tb.GetConstructor(Type.EmptyTypes);Type tc = typeof(TC);var tcc = tc.GetConstructor(Type.EmptyTypes);Console.WriteLine("类TA :" + (tac != null));Console.WriteLine("类TB :" + (tbc != null));Console.WriteLine("类TC :" + (tcc != null));}
}
View Code

 输出:

类TA :False

类TB :False

类TC :True

请按任意键继续. . .

我们可以明白了,也就是我们的AdminAreaRegistration不能有构造器(Visual Studio生成的确实没有构造器)。但是这里为什么要这样约定呢?确实想不通,我们先继续回到刚刚的TypeCacheUtil.GetFilteredTypesFromAssemblies方法。首先,会尝试从缓存中获取类型,与往常不同的是,这里缓存的格式是xml文件,缓存的原因应该很容易理解,频繁反射会造成性能的影响,改良反射的方式有多种,这里我们学到了一种,缓存。关于TypeCacheSerializer如何工作和ReadTypesFromCache具体是如何实现的这里就不去看了,主要就是一些关于Stream和XmlDocument这两个类的操作。但是有必要提一下IBuildManager这个接口。在MVC中的实现者是BuildManagerWrapper,内部实际使用的是BuildManager(位于System.Web.Compilation),关于它的详细资料少之又少,只知道主要负责站点的动态编译和程序集的管理。我们知道可以通过AppDomain来获取应用程序相关的程序集,但这里为什么用BuilderManager呢?想必必有什么不同!

private static IEnumerable<Type> FilterTypesInAssemblies(IBuildManager buildManager, Predicate<Type> predicate)
{// Go through all assemblies referenced by the application and search for types matching a predicateIEnumerable<Type> typesSoFar = Type.EmptyTypes;ICollection assemblies = buildManager.GetReferencedAssemblies();foreach (Assembly assembly in assemblies){Type[] typesInAsm;try{typesInAsm = assembly.GetTypes();}catch (ReflectionTypeLoadException ex){typesInAsm = ex.Types;}typesSoFar = typesSoFar.Concat(typesInAsm);}return typesSoFar.Where(type => TypeIsPublicClass(type) && predicate(type));
}

我们看到这里用它获取所有的应用程序集。在foreach前打一个断点。借助即时窗口我们可以和AppDomain获取的程序集进行一个比较。

string[] Arr1 = assemblies.Cast().Select(a=>a.FullName).ToArray();

已计算表达式,表达式没有值

string[] Arr2 = AppDomain.CurrentDomain.GetAssemblies().Select(a=>a.FullName).ToArray();

已计算表达式,表达式没有值

Arr1.Length

36

Arr2.Length

42

string[] Arr3 = Arr2.Except(Arr1).ToArray();

已计算表达式,表达式没有值

Arr3

{string[6]}

    [0]: "System.Runtime.Caching, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

    [1]: "Microsoft.Build.Utilities.v4.0, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

    [2]: "Microsoft.JScript, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

    [3]: "Microsoft.VisualStudio.Web.PageInspector.Runtime, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

    [4]: "Microsoft.VisualStudio.Web.PageInspector.Tracing, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

    [5]: "Microsoft.VisualStudio.Debugger.Runtime, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

这里列出的几个命名空间我也不熟悉,但是大致可以了解,使用AppDomain返回的程序集是当前AppDomain下所有程序中显示使用过的类型所在的程序集(如果你对AppDomain有了解,希望不要被我误解),而BuildManager返回的是和程序运行环境甚至配置(调试)相关的程序集,我们可以这么理解,BuildManager提供更强大的功能,可以负责站点的动态编译和程序集的管理。关于AreaRegistration类型的缓存我们基本已经了解,拿到所有的AreaRegistration类型后,我们针对每一个进行一次路由配置工作。

internal static void RegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state)
{List<Type> areaRegistrationTypes = TypeCacheUtil.GetFilteredTypesFromAssemblies(TypeCacheName, IsAreaRegistrationType, buildManager);foreach (Type areaRegistrationType in areaRegistrationTypes){AreaRegistration registration = (AreaRegistration)Activator.CreateInstance(areaRegistrationType);registration.CreateContextAndRegister(routes, state);}
}

具体的

internal void CreateContextAndRegister(RouteCollection routes, object state)
{AreaRegistrationContext context = new AreaRegistrationContext(AreaName, routes, state);string thisNamespace = GetType().Namespace;if (thisNamespace != null){context.Namespaces.Add(thisNamespace + ".*");}RegisterArea(context);
}

我们来思考一下,这个thisNamespace会是什么值呢?由于这里的GetType目标是AdminAreaRegistration,(在我这里)所以是Mvc_Web.Areas.Admin,然后会被添加到这里的AreaRegistrationContext的Namespace属性中,然后调用子类重写的RegisterArea方法,最终添加到RouteCollection中,我们看最后调用的MapRoute方法。

public Route MapRoute(string name, string url, object defaults, object constraints, string[] namespaces)
{if (namespaces == null && Namespaces != null){namespaces = Namespaces.ToArray();}Route route = Routes.MapRoute(name, url, defaults, constraints, namespaces);route.DataTokens[RouteDataTokenKeys.Area] = AreaName;bool useNamespaceFallback = (namespaces == null || namespaces.Length == 0);route.DataTokens[RouteDataTokenKeys.UseNamespaceFallback] = useNamespaceFallback;return route;
}

最重要的是倒数第二行和倒数第三行,他和控制器的匹配有关,其实根据UseNamespaceFallback这个也很容易理解,如果我们的AdminAreaRegistration没有命名空间,那就允许它退回(到其他地方找)。

小结

路由这块终于结束了,任重道远啊,鼓励一下自己,加油!!!

 

转载于:https://www.cnblogs.com/cheesebar/p/6676137.html

http://www.lbrq.cn/news/774973.html

相关文章:

  • 购买高仿手表网站/青岛seo网络推广
  • 今天国际最新消息/关键词优化公司网站
  • 福鼎市城市建设监察大队网站/杭州网站优化体验
  • 久雅科技软件开发外包/新网站seo
  • 江阴做网站哪家好/乌海网站seo
  • 上饶网站制作/市场调研分析报告
  • 微信赌博链接网站建设/百度网页版进入
  • 信贷 网站模板 下载/南京seo报价
  • 辽宁大连网站建设/宁波seo基础入门
  • 陕西省住房和城乡建设部网站/赚钱软件
  • 上海网络维护薪水一般多少/杭州网站推广优化
  • 做项目网站/seo网站排名优化案例
  • 大连甘井子区/搜索引擎优化的具体操作
  • 在対网站做可能的来自内部和外部的攻击/微信seo排名优化软件
  • 义乌营销型网站建设/seo关键词排名优化品牌
  • 湖南专业建站按效果付贿/巨量引擎广告投放平台登录入口
  • 做的网站第二年续费多钱/佛山网站建设
  • 东莞网站建设 牛魔网/seo优化教程
  • 请问婚庆网站建设该怎么做呢/一键注册所有网站
  • 营销网站策划/网络营销课程介绍
  • idea 做网站登录/网上开店如何推广自己的网店
  • 公司做网站怎么推广/百度教育app
  • 有没有什么专门做兼职的网站/新冠疫情最新情况
  • 做调查赚钱网站有哪些/关键词有几种类型
  • 重庆网站建设aiyom/百度风云榜游戏
  • 时时彩做假网站怎么做/seo是广告投放吗
  • 云南网站建设优化/系统开发
  • 怎么做企业官方网站/千锋教育培训机构地址
  • 怎么添加字体到电脑wordpress/萧山区seo关键词排名
  • 内部优惠券网站建站/深圳搜索引擎优化seo
  • 【Altium designer】快速建立原理图工程的步骤
  • 荣耀手机无法连接win11电脑,错误消息:“无法在此设备上加载驱动程序 (hn_usbccgpfilter.sys)。”解决方案
  • P2865 [USACO06NOV] Roadblocks G
  • 腾讯云EdgeOne KV存储在游戏资源发布中的技术实践与架构解析
  • Speaking T2 - Dining Hall to CloseDuring Spring Break
  • 不同于传统的简并模分离圆极化天线,基于耦合谐振器的圆极化天线的原理是什么?