MVC3 中的路由






4.65/5 (16投票s)
MVC 中路由的简要介绍。
引言
很多人都在问我 MVC 中的路由是如何工作的,所以这篇文章将为大家简要介绍一下。
路由系统可以分为两个部分
- RouteData:这个机制用于检查传入的 URL,然后决定请求需要发送到哪个控制器和操作。
- VirtualPath:这个机制负责生成出站 URL。这些 URL 出现在我们视图渲染的 HTML 中,以便用户点击链接时可以调用特定的操作。
在本文中,我们将只关注 RouteData。要学习 MVC3 的基础知识,请阅读以下文章 点击此处。
让我们开始创建一个路由项目
使用 Internet 模板创建一个新的 MVC 应用程序,命名为 Routing。因为我们选择了这个模板,所以它会包含一些预先编写好的路由。
由于路由定义在 Global.asax 中,打开该文件,您会看到以下代码行
namespace Routing
{
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
}
我们可以看到 Application_Start
方法负责调用 RegisterRoutes
方法,该方法定义了路由规则。当应用程序启动时,ASP.NET 平台会调用这个 Application_Start
方法。
注意: 幸运的是,MVC 允许我们定义每个路由需要遵循的 URL 模式,而不是手动输入所有单独的 URL。如果路由的模式匹配 URL,那么它就会被处理。
让我们来看一个简单的 URL。如果您在不删除当前路由的情况下运行应用程序,然后打开https://:xxxx/Home/About,您会看到以下屏幕
让我们快速讨论一下。 URL 可以分解为段。这些是 URL 的组成部分(不包括主机名和查询字符串),由 / 字符分隔。在示例 URL 中,有两个段
- Home – 这是 URL 的第一个段,指向 Home 控制器。
- About - 这是 URL 的第二个段,指向 About 操作。
URL 模式是 {controller}/{action}
在处理传入的 URL 时,路由系统的任务是将 URL 匹配到模式,然后从 URL 中找出段变量的值。段变量使用花括号({ 和 } 字符)表示。我们的示例有两个名为 controller 和 action 的段变量。
我们说匹配到模式,是因为 MVC 应用程序。
现在让我们快速看看这个路由可以处理的所有情况。
请求 URL | 段变量 |
http://testsite.com/Home/Index | controller = Home, action = Index |
http://testsite.com/Index/Home | controller = Index, action = Home |
http://testsite.com/Home | 不匹配 (段太少) |
http://testsite.com/Home/Index/Soccer | 不匹配 (段太多) |
正如我们所见,在第一种和第二种情况下,URL 模式匹配了正确的段数,并且我们可以到达相应的控制器和操作,而在第三种和第四种情况下,URL 模式不匹配。
这是默认行为,很快我们将学习如何更改默认设置。
创建和注册一个简单的路由
由于我们是从基础开始,暂时删除 RegisterRoutes
方法的内容,我们将逐步学习如何编写路由。
一旦您有了 URL 模式,就可以用它来定义一个路由。
现在让我们创建一个自定义路由来处理上面的例子
public static void RegisterRoutes(RouteCollection routes) { routes.MapRoute("CustomRoute", "{controller}/{action}"); }
在这里,我们创建了一个名为 CustomRoute
的新路由,它将把 URL 段分别处理到指定的控制器和操作。
例如
URL http://testsite.com/Home/Index 将路由到 controller = Home 和 action = Index
定义默认值
上面定义的路由在第一种和第二种情况下都能正常工作,但如果我们需要确保第三种情况也能正常工作呢?为了做到这一点,我们需要为视图定义默认值,如下所示:
public static void RegisterRoutes(RouteCollection routes) {
routes.MapRoute("CustomRoute ", "{controller}/{action}", new { action = "Index" });
}
这个路由告诉我们,如果我们不为 Action 提供任何值,它将默认调用 Index 操作,这意味着 URL http://testsite.com/Home/ 将路由到 controller = Home 和 action = Index,因为没有指定其他操作。同时,URL http://testsite.com/Home/Xyz 将路由到 controller = Home 和 action = Xyz,因为它被明确指定了。
接下来想到的是,如果我们希望在缺少默认控制器时也执行一个默认控制器,是的,我们可以通过以下方式处理:
public static void RegisterRoutes(RouteCollection routes) {
routes.MapRoute("CustomRoute ", "{controller}/{action}", new { controller = "Home", action ="Index" });
}
通过为 controller 和 action 变量都提供默认值,我们创建了一个可以匹配零个、一个或两个段的 URL 的路由。下表概述了其行为
请求 URL | 段变量 |
http://testsite.com/ | controller = Home, action = Demo |
http://testsite.com/Home | controller = Home, action = Demo |
http://testsite.com/Demo/Test | controller = Demo, action = Test |
http://testsite.com/Test/Demo | controller = Test, action = Demo |
http://testsite.com/Test/Demo/List | 不匹配 (段太多) |
静态 URL 段
还可以创建具有静态段的模式。假设您有一个需求,希望在 URL 前加上“Student”一词。
http://testsite.com/Student/Home/Index
public static void RegisterRoutes(RouteCollection routes) {
routes.MapRoute("CustomRoute ", "{controller}/{action}",
new { controller = "Home", action = "Index" });
routes.MapRoute("StaticRoute", " Student /{controller}/{action}",
new { controller = "Home", action = "Index" });
}
此 URL 模式将仅匹配包含三个段的 URL,其中第一个段必须是 Student。另外两个段可以包含任何值,并将用于 controller 和 action 变量。
我们还可以创建包含静态和变量元素的 URL 模式。
public static void RegisterRoutes(RouteCollection routes) {
routes.MapRoute("StaticRoute ", "XYZ{controller}/{action}");
routes.MapRoute("CustomRoute ", "{controller}/{action}",
new { controller = "Home", action = "Index" });
routes.MapRoute("AnotherStaticRoute ", "Public/{controller}/{action}",
new { controller = "Home", action = "Index" });
}
此路由中的模式匹配任何两个段的 URL,其中第一个段以 XYZ 开头。controller 的值取自第一个段,不包括 XYZ。action 值取自第二个段。
例如,以下 URL 将被该路由匹配
http://testsite.com/XYZ/Home/Index
此 URL 将被定向到 Home 控制器的 Index 操作方法。
自定义段变量
MVC 不仅限于将 URL 路由到 controller 和 action 变量。我们还可以自由定义自己的变量,例如
public static void RegisterRoutes(RouteCollection routes) { routes.MapRoute("CustomRoute ", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" }); }
此路由将匹配任何零到三个段的 URL。第三个段的内容将被分配给 id 变量,如果不存在第三个段,则使用默认值。
现在我们首先想到的是如何获取这个值并使用它。
所以,首先我们来谈谈如何获取这个 id 值,可以通过以下两种方式实现
- 我们可以通过
RouteData.Values
属性在操作方法中访问任何段变量,因此 id 可以这样访问:
public ViewResult CustomVariable() {
ViewBag.CustomVariable = RouteData.Values["id"];
return View();
}
public ViewResult CustomVariable(string id) {
ViewBag.CustomVariable = index;
return View();
}
现在,一旦我们获取了 id 值,就可以像这样在视图中显示它:
@{
ViewBag.Title = "CustomVariable";
}
<h2>Variable: @ViewBag.CustomVariable</h2>
定义可选 URL 段
MVC 还允许我们拥有可选的 URL 段,这意味着用户不需要指定一个 URL 段,但即使没有为其指定默认值。
public static void RegisterRoutes(RouteCollection routes) {
routes.MapRoute("CustomRoute", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
无论是否提供了 id 段,此路由都将匹配 URL。
段数 | URL | 映射 |
0 | http://testsite.com/ | controller = Home, action = Demo |
1 | http://testsite.com/Test | controller = Home, action = Demo |
2 | http://testsite.com/Test/Demo | controller = Test, action = Demo |
3 | http://testsite.com/Test/Demo/List | controller = Test, action = Demo, id = list |
4 | http://testsite.com/Test/Demo/List/NameId | 不匹配 (段太多) |
定义可变长度路由
到目前为止,我们已经看到了如何处理任意特定数量的段的路由,但如果我们想处理“n”个段的情况呢?
MVC 也为我们轻松处理这种情况提供了支持。可以通过将其中一个段变量指定为“catchall”来支持可变段,方法是在其前面加上星号 (*)。
public static void RegisterRoutes(RouteCollection routes) { routes.MapRoute("CustomRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }); }
如果您注意到这里,我们扩展了之前示例中的路由,添加了一个 catchall 段变量,我们形象地称之为 catchall。这个路由现在将匹配任何 URL。前三个段用于分别设置 controller、action 和 id 变量的值。如果 URL 包含其他段,它们都将被分配给 catchall 变量。
段数 | URL | 映射 |
0 | http://testsite.com/ | controller = Home, action = Demo |
1 | http://testsite.com/Test | controller = Home, action = Demo |
2 | http://testsite.com/Test/Demo | controller = Test, action = Demo |
3 | http://testsite.com/Test/Demo/List | controller = Test, action = Demo, id = list |
4 | http://testsite.com/Test/Demo/List/NameId/ProfId | controller = Test, action = Demo, id = list, catch = NameId/ ProfId |
此路由中的 URL 模式可以匹配的段数没有上限。