浅谈MVC中路由

引言

  学习ASP.NET MVC 路由这一关是肯定必不可少的。这一节,我们就来简单介绍下MVC中的路由机制。简单的路由机制相信大家都已了解,这一节主要介绍路由中很少使用的部分。

使用静态URL片段

  在一个路由中,并不是所有的URL片段都要求是动态的,也可以创建具有静态片段的模式。例如以下的路由:

1 routes.MapRoute("StaticRoute", "X{controller}/{action}",
2                             new { controller = "Home", action = "Index" },
3                             new string[] { "MyFirstMvcProject.Controllers" });

  我们看到这条路由定义了第一个片段以字母X打头,controller的值是X字母以后的部分,第二个片段Action定义了默认值Index。这条路由将匹配任何X字母开头,controller值是取自第一个片段除字母X以外的部分。

  一个有趣的例子:

  设想下这样的场景,如果您的网站已经发布好久了,用户与网站之间已经形成了某种契约。例如。用户对于这个地址已经非常熟悉http://www.asp.net-example.com/Learn/Index。那么很显然控制器是Learn。如果现在您需要对程序进行重构,那么我们最好保留用户已经熟悉的链接地址。假设重构以后,新的控制器是Home。那么我们可以通过一条保留旧有URL地址的路由来实现这个功能。

1 routes.MapRoute("StaticRoute", "Learn/{action}",
2                             new { controller = "Home", action = "Index" },
3                             new string[] { "MyFirstMvcProject.Controllers" });

  上面的路由,我们输入Learn/Index时,路由机制会自动匹配新的控制器Home。这样一方面没有打断网站与已有用户之间形成的契约,同时又对程序功能做了一个较好的迁移。我们在浏览器中运行如下:

  我们看到,我们输入/Learn/Index。路由找到的是HomeController。

定义可变长路由

  我们通过定义可变长度的路由来匹配任意长度的URL。我们通过设置一个*catchall片段变量可以定义对可变片段数量的支持。请看下面的路由

1 routes.MapRoute(
2                 name: "Default",
3                 url: "{controller}/{action}/{id}/{*catchall}",
4                 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
5                 namespaces: new[] { "MyFirstMvcProject.Controllers" }
6             );

  我们来看下面的例子:

   从这个例子我们看出,我们输入的URL是Home/Index/Id/Do/Operation。我们通过{*catchall}片段变量来获取URL中的片段。我们看到catchall获取的是Do/Operation。说明任意长度的片段变量我们都可以获取到。只是在后续处理时,我们需要自行处理诸如Do/Opeartion这样的片段变量。

 按命名空间来区分控制器执行顺序

  从上面一个例子我们看到我们在路由里面设置了namespaces属性的值。如果我们不设置呢?看看会发生上面。请看下面的例子。

  我们看到,我们的项目中存在两个HomeController控制器,浏览器路由机制解析出控制器名称是Home后,两个名称是Home的控制器,MVC框架不知道选择哪一个。这种情况下,我们需要设置下路由器的namespaces属性。这样MVC就会优先从这个命名空间下去寻找控制器。

定义自定义约束

  MVC框架默认给我们提供了根据正则表达式和HTTP方法来约束路由。如果这些方法还是无法满足要求的话,我们可以通过实现IRouteConstraint接口来自定义路由约束。我们首先来看下IRouteConstraint的情况。

 1         // 摘要: 
 2         //     确定 URL 参数是否包含此约束的有效值。
 3         //
 4         // 参数: 
 5         //   httpContext:
 6         //     一个对象,封装有关 HTTP 请求的信息。
 7         //
 8         //   route:
 9         //     此约束所属的对象。
10         //
11         //   parameterName:
12         //     正在检查的参数的名称。
13         //
14         //   values:
15         //     一个包含 URL 的参数的对象。
16         //
17         //   routeDirection:
18         //     一个对象,指示在处理传入请求或生成 URL 时,是否正在执行约束检查。
19         //
20         // 返回结果: 
21         //     如果 URL 参数包含有效值,则为 true;否则为 false。
22         bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);    

  我们看到,这个接口就一个方法Match。MVC路由在匹配路由时会调用这个Match方法看请求的URL与当前路由是否匹配。下面我们还是通过一个例子来看一下把。请看以下例子:

 1 public class UserAgentConstraint : IRouteConstraint
 2     {
 3         private string requestUserAgent;
 4 
 5         public UserAgentConstraint(string userAgent)
 6         {
 7             this.requestUserAgent = userAgent;
 8         }
 9 
10         public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
11         {
12             bool result = (httpContext.Request.UserAgent != null && httpContext.Request.UserAgent.Contains(this.requestUserAgent));
13             return result;
14         }
15     }

  我们写一条全新的路由来测试下,看看效果。如下:

1 routes.MapRoute("chromeRoute", "{controller}/{action}",
2                             new { controller = "Home", action = "Index" },
3                             new { customConstraint = new UserAgentConstraint("Chrome") });

  这条路由使用了我们自定义的约束路由机制,我们看到我们传递了Chrome给自定义的路由匹配器。这样火狐浏览器和IE应该没法进行浏览,谷歌是可以的。打开浏览器试一下。

  我们使用火狐浏览器来访问/Home/Index。会出现404的问题。

   而我们使用谷歌浏览器访问时,是可以正常进行访问的。

对磁盘文件进行路由

  我们知道对于所有的请求并不是都是针对控制器和动作的。也有很多是对静态文件的访问。例如图像,样式文件,JS代码文件等。默认情况下,路由系统在评估应用程序的路由之前,会考察一个URL是否匹配一个磁盘文件。如果匹配,该文件会用来对该请求进行服务。应用程序定义的路由就不会被使用。

  我们可以通过设置routes.RouteExistingFiles = true来对MVC的默认机制进行修改。通过设置为true,意味着对已存在文件也进行路由。为了演示例子,我们还需要配置应用程序服务器,告诉IIS Express以便在请求到达MVC路由系统之前,不要拦截对磁盘文件的请求。请看下面的配置。

1 <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />

  找到这一配置节点,将preCondition设置为""即可。

  这时候我们在浏览器中输入Content/CustomerJS.js会看的下面这一幕。

  我们看到,我们启用了对磁盘文件进行路由,这样MVC路由系统会设法找到名称为Content的控制器,这显然不是我们想要的。我们可以通过设置默认值来修复这个问题。

1 routes.MapRoute("StaticRoute", "Content/CustomerJS.js",
2                             new { controller = "Home", action = "Index" },
3                             new string[] { "MyFirstMvcProject.Controllers" });

绕过路由系统

  通过使用routes.IgnoreRoute("Content/{filename}.js")我们可以对Content文件夹下的JS文件不进行路由,这样我们上面例子的时候,就会展示JavaScript代码了。

posted @ 2016-01-06 19:48  dreamGong  阅读(766)  评论(0编辑  收藏  举报