带你读开源—ASP.NET_MVC(七)
2016-09-09 20:47
267 查看
我们继续谈细节。
我们注意到ASP.NETMVC项目都包含一个Global.asax文件,这个文件代码很少,只包括三个方法,即RegisterGlobalFilters、RegisterRoutes、Application_Start。
我们看RegisterRoutes方法的定义(代码段1)。
代码段 1
代码段1中的routes.MapRoute语句是路由映射的具体实现,我们在MVC源码中看其定义(代码段2)。
代码段 2
代码段2中route用一个MvcRouteHandler来实例化,即封装了MVC路由处理机制。我们完全可以自定义一个IRouteHandler的实现,例如代码段3:
代码段 3
代码段3中的MyHandler定义见代码段4。
代码段 4
我们现在把代码段1中的routes.MapRoute这句代码,更换为代码段5。
代码段 5
好了,现在我们按下F5进行调试,在浏览器地址栏输入http://localhost:48580/My,回车,看见图1了没?浏览器显示我们在代码段4中希望输出的“HELLO”。这里我们自己定义了一个新的路由规则,即当我们访问http://localhost:48580/My的时候,就会调用我们自定义的MyRouteHandler,成就感有木有?有木有?当然,我们自定义的这条路由规则URL只是静态匹配,它非常简单,以至于简单到不能再简单,以至于毫无用途,但我们毕竟通过这个例子,明白了MVC路由系统的大概端倪。当然,代码段5中的静态URL(My)也可以更换成动态URL,比如“{My}/{Love}”,这样当我们访问http://localhost:48580/hello/kitty时,就会调用我们自定义的路由。可见,ASP.NET的路由系统把花括号“{}”中的内容看作一个变量(或者占位符),之间用斜杠“/”分割,并以此来匹配浏览器输入的URL字符串。
![](http://img.bbs.csdn.net/upload/201609/01/1472716347_969959.png)
图 1
前面我们谈控制器时,没有提到控制器是如何实例化的,下面我们进入这个话题。MVC框架中的controller由控制器工厂进行实例化(代码段6),而系统预置的控制器工厂是DefaultControllerFactory,它实现了IControllerFactory接口。
代码段 6
我们看看DefaultControllerFactory的具体实现(代码段7),这段代码中最核心的语句是【Type controllerType =GetControllerType(requestContext, controllerName);[1] IController controller = GetControllerInstance(requestContext,controllerType); [2]】,这两句的功能是:首先根据路由传递过来的Controller名称得到控制器的类型;再根据控制器类型,创建IController的具体实例。
代码段 7
我们跟踪进入语句[1]的具体定义(代码段8),可以看到其中有三句很扎眼的注释【// first search in the current route's namespace collection】、【// then search in the application's default namespace collection】、【// if all else fails, search every namespace】,这些注释清楚的告诉我们MVC框架搜索控制器的顺序。
代码段 8
这三条注释所作用的语句中都用到了GetControllerTypeWithinNamespaces方法,其实现见代码段9。
代码段 9
我们注意到ASP.NETMVC项目都包含一个Global.asax文件,这个文件代码很少,只包括三个方法,即RegisterGlobalFilters、RegisterRoutes、Application_Start。
我们看RegisterRoutes方法的定义(代码段1)。
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id =UrlParameter.Optional } // Parameter defaults ); }
代码段 1
代码段1中的routes.MapRoute语句是路由映射的具体实现,我们在MVC源码中看其定义(代码段2)。
[SuppressMessage("Microsoft.Design","CA1054:UriParametersShouldNotBeStrings", MessageId = "2#",Justification = "This is not a regular URL as it may contain specialrouting characters.")] public static Route MapRoute(this RouteCollection routes, string name,string url, object defaults, object constraints, string[] namespaces) { if (routes == null) { throw new ArgumentNullException("routes"); } if (url == null) { throw new ArgumentNullException("url"); } Route route = new Route(url, new MvcRouteHandler()) { Defaults = CreateRouteValueDictionaryUncached(defaults), Constraints = CreateRouteValueDictionaryUncached(constraints), DataTokens = new RouteValueDictionary() }; ConstraintValidation.Validate(route); if ((namespaces != null) && (namespaces.Length > 0)) { route.DataTokens[RouteDataTokenKeys.Namespaces] = namespaces; } routes.Add(name, route); return route; }
代码段 2
代码段2中route用一个MvcRouteHandler来实例化,即封装了MVC路由处理机制。我们完全可以自定义一个IRouteHandler的实现,例如代码段3:
publicclass MyRouteHandler : IRouteHandler { public IHttpHandler GetHttpHandler(RequestContext requestContext) { return new MyHandler(); } }
代码段 3
代码段3中的MyHandler定义见代码段4。
publicclass MyHandler : IHttpHandler { public bool IsReusable { get { return false; } } public void ProcessRequest(HttpContext context) { context.Response.Write("HELLO"); } }
代码段 4
我们现在把代码段1中的routes.MapRoute这句代码,更换为代码段5。
routes.Add("MyRoute", newRoute("My", new MyRouteHandler()));
代码段 5
好了,现在我们按下F5进行调试,在浏览器地址栏输入http://localhost:48580/My,回车,看见图1了没?浏览器显示我们在代码段4中希望输出的“HELLO”。这里我们自己定义了一个新的路由规则,即当我们访问http://localhost:48580/My的时候,就会调用我们自定义的MyRouteHandler,成就感有木有?有木有?当然,我们自定义的这条路由规则URL只是静态匹配,它非常简单,以至于简单到不能再简单,以至于毫无用途,但我们毕竟通过这个例子,明白了MVC路由系统的大概端倪。当然,代码段5中的静态URL(My)也可以更换成动态URL,比如“{My}/{Love}”,这样当我们访问http://localhost:48580/hello/kitty时,就会调用我们自定义的路由。可见,ASP.NET的路由系统把花括号“{}”中的内容看作一个变量(或者占位符),之间用斜杠“/”分割,并以此来匹配浏览器输入的URL字符串。
![](http://img.bbs.csdn.net/upload/201609/01/1472716347_969959.png)
图 1
前面我们谈控制器时,没有提到控制器是如何实例化的,下面我们进入这个话题。MVC框架中的controller由控制器工厂进行实例化(代码段6),而系统预置的控制器工厂是DefaultControllerFactory,它实现了IControllerFactory接口。
// Instantiate the controller andcall Execute factory =ControllerBuilder.GetControllerFactory(); controller = factory.CreateController(RequestContext,controllerName);
代码段 6
我们看看DefaultControllerFactory的具体实现(代码段7),这段代码中最核心的语句是【Type controllerType =GetControllerType(requestContext, controllerName);[1] IController controller = GetControllerInstance(requestContext,controllerType); [2]】,这两句的功能是:首先根据路由传递过来的Controller名称得到控制器的类型;再根据控制器类型,创建IController的具体实例。
public virtual IControllerCreateController(RequestContext requestContext, string controllerName) { if (requestContext == null) { throw newArgumentNullException("requestContext"); } if(String.IsNullOrEmpty(controllerName) &&!requestContext.RouteData.HasDirectRouteMatch()) { throw newArgumentException(MvcResources.Common_NullOrEmpty, "controllerName"); } Type controllerType =GetControllerType(requestContext, controllerName); IController controller =GetControllerInstance(requestContext, controllerType); return controller; }
代码段 7
我们跟踪进入语句[1]的具体定义(代码段8),可以看到其中有三句很扎眼的注释【// first search in the current route's namespace collection】、【// then search in the application's default namespace collection】、【// if all else fails, search every namespace】,这些注释清楚的告诉我们MVC框架搜索控制器的顺序。
protected internal virtual TypeGetControllerType(RequestContext requestContext, string controllerName) { if (requestContext == null) { throw newArgumentNullException("requestContext"); } if(String.IsNullOrEmpty(controllerName) && (requestContext.RouteData ==null || !requestContext.RouteData.HasDirectRouteMatch())) { throw newArgumentException(MvcResources.Common_NullOrEmpty, "controllerName"); } RouteData routeData =requestContext.RouteData; if (routeData != null &&routeData.HasDirectRouteMatch()) { returnGetControllerTypeFromDirectRoute(routeData); } // first search in the currentroute's namespace collection object routeNamespacesObj; Type match; if(routeData.DataTokens.TryGetValue(RouteDataTokenKeys.Namespaces, outrouteNamespacesObj)) { IEnumerable<string>routeNamespaces = routeNamespacesObj as IEnumerable<string>; if (routeNamespaces != null&& routeNamespaces.Any()) { HashSet<string>namespaceHash = new HashSet<string>(routeNamespaces,StringComparer.OrdinalIgnoreCase); match =GetControllerTypeWithinNamespaces(routeData.Route, controllerName,namespaceHash); // the UseNamespaceFallbackkey might not exist, in which case its value is implicitly "true" if (match != null ||false.Equals(routeData.DataTokens[RouteDataTokenKeys.UseNamespaceFallback])) { // got a match or theroute requested we stop looking return match; } } } // then search in the application'sdefault namespace collection if(ControllerBuilder.DefaultNamespaces.Count > 0) { HashSet<string> namespaceDefaults = newHashSet<string>(ControllerBuilder.DefaultNamespaces,StringComparer.OrdinalIgnoreCase); match =GetControllerTypeWithinNamespaces(routeData.Route, controllerName,namespaceDefaults); if (match != null) { return match; } } // if all else fails, search everynamespace returnGetControllerTypeWithinNamespaces(routeData.Route, controllerName, null /* namespaces*/); }
代码段 8
这三条注释所作用的语句中都用到了GetControllerTypeWithinNamespaces方法,其实现见代码段9。
private TypeGetControllerTypeWithinNamespaces(RouteBase route, string controllerName,HashSet<string> namespaces) { // Once the master list ofcontrollers has been created we can quickly index into it ControllerTypeCache.EnsureInitialized(BuildManager); ICollection<Type>matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName,namespaces); switch (matchingTypes.Count) { case 0: // no matching types return null; case 1: // single matching type return matchingTypes.First(); default: // multiple matching types throwCreateAmbiguousControllerException(route, controllerName, matchingTypes); } }
代码段 9
相关文章推荐
- ASP.NET MVC 开源项目 收集
- 开源 ASP.NET MVC 1.0 项目
- 一起谈.NET技术,ASP.NET MVC 3 Beta新特性以及.Net开源的趋势----最新译文
- [ASP.NET MVC 3 系列] ASP.NET MVC 3 Beta新特性以及.Net开源的趋势----最新译文
- 推荐一款asp.net-MVC开源框架,完全开源免费使用
- asp.net mvc相关开源项目推荐
- asp.net mvc相关开源项目推荐
- Asp.net MVC 2.0 + Unity 2.0(IoC) + EF4.0 实例:RoRoWoBlog 开源项目框架代码
- 【转载】使用Json比用string返回数据更友好,也更面向对象一些 |Asp.net MVC 2.0 + Unity 2.0(IoC) + EF4.0 实例:RoRoWoBlog 开源项目框架代码
- 开源 Asp.net mvc 用户中心开发计划
- asp.net mvc 1.0 开源
- 看一下基于ASP.NET MVC的开源社区项目Orchard
- asp.net mvc相关开源项目
- vici 开源asp.net mvc支持asp.net2.0II6.0下部署 实例下载地址
- ASP.NET MVC学习资料 新增几个开源项目
- ASP.NET MVC 2的代码以MS-PL协议开源发布
- [转]asp.net mvc相关开源项目推荐
- ASP.NET MVC 开源项目Kigg解读(1)
- (转)看了一些ASP.NET MVC开源项目后的一些想法,关于ASP.NET MVC+Repository+Service架构的一些思考
- 我要学ASP.NET MVC 3.0(十九): MVC 3.0 实例之使用开源控件实现表格排序和分页