带你读开源—ASP.NET_MVC(七)
我们继续谈细节。
我们注意到ASP.NET MVC项目都包含一个Global.asax文件,这个文件代码很少,只包括三个方法,即RegisterGlobalFilters、RegisterRoutes、Application_Start。
我们看RegisterRoutes方法的定义(代码段1)。
代码段1中的routes.MapRoute语句是路由映射的具体实现,我们在MVC源码中看其定义(代码段2)。
代码段2中route用一个MvcRouteHandler来实例化,即封装了MVC路由处理机制。我们完全可以自定义一个IRouteHandler的实现,例如代码段3:
代码段3中的MyHandler定义见代码段4。
我们现在把代码段1中的routes.MapRoute这句代码,更换为代码段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字符串。

前面我们谈控制器时,没有提到控制器是如何实例化的,下面我们进入这个话题。MVC框架中的controller由控制器工厂进行实例化(代码段6),而系统预置的控制器工厂是DefaultControllerFactory,它实现了IControllerFactory接口。
我们看看DefaultControllerFactory的具体实现(代码段7),这段代码中最核心的语句是【Type controllerType = GetControllerType(requestContext, controllerName);[1] IController controller = GetControllerInstance(requestContext, controllerType); [2]】,这两句的功能是:首先根据路由传递过来的Controller名称得到控制器的类型;再根据控制器类型,创建IController的具体实例。
我们跟踪进入语句[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框架搜索控制器的顺序。
这三条注释所作用的语句中都用到了GetControllerTypeWithinNamespaces方法,其实现见代码段9。
我们注意到ASP.NET MVC项目都包含一个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 special routing 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:
public class MyRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new MyHandler();
}
}代码段 3
代码段3中的MyHandler定义见代码段4。
public class 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", new Route("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字符串。

图 1
前面我们谈控制器时,没有提到控制器是如何实例化的,下面我们进入这个话题。MVC框架中的controller由控制器工厂进行实例化(代码段6),而系统预置的控制器工厂是DefaultControllerFactory,它实现了IControllerFactory接口。
// Instantiate the controller and call 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 IController CreateController(RequestContext requestContext, string controllerName)
{
if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
}
if (String.IsNullOrEmpty(controllerName) && !requestContext.RouteData.HasDirectRouteMatch())
{
throw new ArgumentException(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 Type GetControllerType(RequestContext requestContext, string controllerName)
{
if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
}
if (String.IsNullOrEmpty(controllerName) &&
(requestContext.RouteData == null || !requestContext.RouteData.HasDirectRouteMatch()))
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
}
RouteData routeData = requestContext.RouteData;
if (routeData != null && routeData.HasDirectRouteMatch())
{
return GetControllerTypeFromDirectRoute(routeData);
}
// first search in the current route's namespace collection
object routeNamespacesObj;
Type match;
if (routeData.DataTokens.TryGetValue(RouteDataTokenKeys.Namespaces, out routeNamespacesObj))
{
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 UseNamespaceFallback key might not exist, in which case its value is implicitly "true"
if (match != null || false.Equals(routeData.DataTokens[RouteDataTokenKeys.UseNamespaceFallback]))
{
// got a match or the route requested we stop looking
return match;
}
}
}
// then search in the application's default namespace collection
if (ControllerBuilder.DefaultNamespaces.Count > 0)
{
HashSet<string> namespaceDefaults = new HashSet<string>(ControllerBuilder.DefaultNamespaces, StringComparer.OrdinalIgnoreCase);
match = GetControllerTypeWithinNamespaces(routeData.Route, controllerName, namespaceDefaults);
if (match != null)
{
return match;
}
}
// if all else fails, search every namespace
return GetControllerTypeWithinNamespaces(routeData.Route, controllerName, null /* namespaces */);
}代码段 8
这三条注释所作用的语句中都用到了GetControllerTypeWithinNamespaces方法,其实现见代码段9。
private Type GetControllerTypeWithinNamespaces(RouteBase route, string controllerName, HashSet<string> namespaces)
{
// Once the master list of controllers 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
throw CreateAmbiguousControllerException(route, controllerName, matchingTypes);
}
}代码段 9
...全文
相关推荐
经典的基于ASP.NET MVC框架的开源博客系统
一个国人写的开源blog系统,使用ASP.NET MVC框架开发. 具有以下优点: 1,代码精练,优雅,。 2,使用了大量的设计模式 3,采用N层架构设计,分层非常合理。 4,支持强大的扶肤功能 5,大量使用了.net Framework 3.5的新特性 是学习ASP.NET MVC 以及N层架构开发,.net 新特性的最佳途径。
基于asp.net mvc的开源网站管理系统
基于asp.net mvc的开源网站管理系统 包含了jquery,bootstrap,ueditor......等众多开源项目实例
微软开源ASP.NET MVC项目
唯一的微软开源MVC项目,好东西不多说了。
开源:ASP.NET MVC+EF6+Bootstrap开发框架
特别实用,好用,最全的.NET开源框架,牛逼框架,好框架。框架使用场景:OA、ERP、BPM、CRM、WMS、TMS、MIS等业务管理系统及后台系统。祝各位早日登上人生巅峰!
ASP.NET MVC 4和ASP.NET MVC5[附源码]合集
ASP.NET MVC 4和ASP.NET MVC5[附源码]合集,有心的人可以对比看下,MVC4 和MVC5的差异,以及里面的架构 变化


