• 浅谈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代码了。

  • 相关阅读:
    数学+高精度 ZOJ 2313 Chinese Girls' Amusement
    最短路(Bellman_Ford) POJ 1860 Currency Exchange
    贪心 Gym 100502E Opening Ceremony
    概率 Gym 100502D Dice Game
    判断 Gym 100502K Train Passengers
    BFS POJ 3278 Catch That Cow
    DFS POJ 2362 Square
    DFS ZOJ 1002/HDOJ 1045 Fire Net
    组合数学(全排列)+DFS CSU 1563 Lexicography
    stack UVA 442 Matrix Chain Multiplication
  • 原文地址:https://www.cnblogs.com/dreamGong/p/5106732.html
Copyright © 2020-2023  润新知