004_URL 路由

在视图中生成输出URL

   使用路由系统来生成输出URL,能够确保URL方案动态地产生URL。

   在视图中生成输出URL的最简单做法是在视图中调用Html.ActionLink辅助器方法,如:

<div>@Html.ActionLink("This is an outgoing URL", "CustomVariable")</div>

         注意,ActionLink方法生成的HTML是基于当前路由配置的。如果路由方案是下面这样,

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute("MyRoute", "{controller}/{action}/{id}",
                new { controller = "Home", action = "Index", id = UrlParameter.Optional });
        }

   则将得到这样的:HTML:<a href=”/Home/CustomVarible”>This is an outgoing URL</a>

   但是,如果将路由方案改为下面这种方式:

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute("NewRoute", "App/Do{action}",
                new { controller = "Home" });
            routes.MapRoute("MyRoute", "{controller}/{action}/{id}",
                new { controller = "Home", action = "Index", id = UrlParameter.Optional });
        }

   则将会得到:<a href=”/App/DoCustomVarible”>This is an outgoing URL</a>

   因此,可以看出使用路由系统生成输出URL的方式可以方便的实现自动对路由配置的更改进行响应。这也方便了维护——通过修改路由方案,在视图中的输出链接会自动地反映出这种修改。

知识点:

         路由系统是按照路由被添加的顺序来处理路由的,路由会被添加到传递给RegisterRoutes方法的RuteCollection对象中。每一条路由再被检测是否是一个匹配时,都需要满足三个条件:

  • URL模式中定义的每一个片段变量都必须有一个可用的值。为了找到每个片段变量的值,路由系统首先查看已经提供的值(采用匿名类型的属性),然后查看当前请求的变量值,最后查看该路由中定义的默认值。
  • 在给片段变量提供的值中,应当没有违背这条路由所定义的只默认变量的值。只默认变量是为其提供了默认值,但未在URL模式中出现的变量。如在匹配这条路由(routes.MapRoute("MyRoute", "{controller}/{action}",new { myVar = "True" });)时就要小心,不要给myVar(只默认变量:为其提供了默认值“true”,但未在URL模式中出现——如果未在URL模式中为其提供值)提供值,或要确保所提供的值与这个默认值是匹配的。
  • 所有片段变量的值均必须满足路由约束。一定注意,路由系统不会试图查找最佳匹配路由,它只会找出最先匹配者,然后用这条路由来生成URL,任何后续的路由都会被忽略。所以,应该首先定义最具体的路由。

为各个片段参数所选择参数值将在其中被替换,即在Html.ActionLink给片段提供的值,会替换掉生成URL中的相关默认值——这些默认值是在路由配置中设定的。同时,将忽略尾部的默认值序列。如果明确地提供一些参数,但它们与片段参数或默认参数不符,那么方法将把这些参数以“名字/值”对的查询字符串形式进行追加。

以其他控制器为目标

   ActionLink方法默认以当前控制器为目标创建输出URL,如果需要创建一个以不同控制器为目标的输出URL,则可以使用它的一个重载版本,它允许指定控制器名称。需要注意的是,路由系统不会对动作方法和控制器的值进行检验,不要指定不存在的目标。

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>ActionName</title>
</head>
<body>
    <div>The controller is:@ViewBag.Controller</div>
    <div>The action is:@ViewBag.Action</div>
    <div>@Html.ActionLink("This is an outgoing URL", "CustomVariable")</div>
    <div>
        <!--通过指定控制器来实现一个以不同控制器为目标的输出 URL -->
        @Html.ActionLink("This targets another controller", "Index", "Admin")
    </div>
</body>
</html>

   上述加粗部分使用了ActionLink的一个重载版本,其指定了目标控制器及动作,当视图渲染时,最终会生成以下HTML结果:<a href=”/Admin”>This targets another controller</a>。由于Index为默认动作方法,因此,可以省略默认的动作片段,这也是路由系统所允许的。

传递额外的值

   可以使用一个匿名类型为一些片段变量传值,在这个匿名类型中一其属性表示片段。如下代码所示:

    <div>
        <!--使用匿名类型给片段变量提供值-->
        @Html.ActionLink("This is an outgoing URL", "CustomVariable", new { id = "Hello" })
    </div>

         上面这段代码将会产生这样的HTML:

<a href="/App/DoCustomVariable?id=Hello">This is an outgoing URL</a>

   根据前面的路由模式设置,为id提供的值被作为查询字符串添加到了URL,其原因是为了实现与路由设置的URL模式相匹配。前面的路由设置如下:

routes.MapRoute("NewRoute", "App/Do{action}",new { controller ="Home" });

         因此,如果路由设置中只有一个与之匹配的路由,那将会得到不同的结果——复制给id属性的值被作为URL片段包括在URL中。即如果只有一条这样的与之匹配的路由:

routes.MapRoute("MyRoute", "{controller}/{action}/{id}",
                new { controller = "Home", action = "Index", id = UrlParameter.Optional });

   HTML结果:<a href="/App/CustomVariable/Hello">This is an outgoing URL</a>

         变化之处已用粗体标出。

知识点:

片段变量的重用

   在为一条路由URL模式中的每一个片段变量查找值的过程中,路由系统将考查当前请求的值,就如前面谈到输出URL时所说的,路由系统为了找到每个片段变量的值,会首先查看已经提供的值(采用匿名类型的属性),然后查看当前请求的变量值,最后查看该路由定义的默认值。

   假设只有一条路由,如下:

routes.MapRoute("MyRoute", "{controller}/{action}/{color}/{page}");

   现在假设一个用户的当前URL为/Catalog/List/Purple/123,并渲染一个这样的链接:

@Html.Action(“Click me”,”List”,”Catalog”,new {page=789},null)

   虽然,未提供color片段变量的值,同时也未定义默认值,但路由系统将会根据已经的定义的路由进行匹配,并生成这样的HTML:

<a href=”/Catalog/List/Purple/789”>Click me</a>

   原因是,路由系统查找了当前请求的变量值——它重用了输入URL的片段变量值,color的值最终被赋成了Purple。

   需要注意的是,在开发的过程中不要依赖路由系统的这种行为,因为,路由系统将只对某些片段变量使用重用值,这些片段变量在URL模式中的出现早于提供给Html.ActionLink方法的参数。如果下面这样的链接将不会被匹配:

@Html.Action(“Click me”,”List”,”Catalog”,new {color=”Aqua”},null)

   这里未提供值的片段page在URL模式中的出现晚于已提供值的color片段,因此不能使用重用值,于是这条路由将不被匹配。

   因此,这里强烈建议不要依赖与路由系统的这种行为,并应为URL模式中的所有片段变量都提供值。

指定HTML标签属性

         通过提供一个匿名类型,可以为元素设置标签属性,该匿名类型的属性与所需要的标签属性相对应。如下面示例中对id标签属性的设置,并为其所在的a元素赋值了一个CSS的class:

    <div>
        <!--生成一个带有标签属性的锚点元素。class 之前使用@字符作为前缀,这是一条 C# 语言特性,它让用户能够用保留关键字作为 class 成员的名字(即以 class 作为该匿名类型的一个成员)-->
        @Html.ActionLink("This is an outgoing URL", "Index", "Home", null, new { id = "myAchorID", @class = "myCSSClass" })
    </div>

   上述这段语句将被渲染成这样的HTML:

<a class=”myCSSClass” href=”/” id=”myAnchorID”>This is an outgoing URL</a>

生成链接中的全限定URL

   前面介绍的生成的链接都是相对URL,但我们还可以使用ActionLink辅助器方法生成全限定的URL。如:

    <div>
        <!--生成权限定 URL -->
        @Html.ActionLink("This is an outgoing URL", "Index", "Home", "https", "myserver.mydomain.com", " myFragmentName", new { id = "myId" }
                          , new { id = "myAchorID", @class = "myCSSClass" })
    </div>

         最终会生成这样的HTML:

<a class=”myCSSClass” href=”https://myserver.mydomain.com/Home/Index/MyId#myFragmentName” id=”myAnchorID”>This is an outgoing URL</a>

         建议:在实际项目中尽可能使用相对URL,权限定URL会形成对应用程序的基础架构方式产生依赖性。

生成URL(而不是链接)

   使用Html.ActionLink辅助器方法可以生成完整的HTML的<a>元素,但如果需要,还可以使用Url.Action方法只生成URL,而不产生HTML元素。如下代码所示:

    <div>
        This is a URL:
        @Url.Action("Index", "Home", new { id = "MyId" })
    </div>

         除了只生成URL外,它与Html.ActionLink方法的工作方式相同。

在动作方法中生成输出URL

有时我们需要在动作方法中输出URL,如果仅需生成URL,可以采取与在视图中同样的辅助器方法,如下:

        /// <summary>
        /// 在动作方法中生成输出 URL
        /// </summary>
        /// <returns></returns>
        public ViewResult MyActionMethod()
        {
            string myActionUrl = Url.Action("Index", new { id = "MyID" });
            string myRouteUrl = Url.RouteUrl(new { controller = "Home", action = "Index" });

            // ... 用此 URL 做些事情...
            return View();
        }

         对于上面这段代码,myActionUrl 的值将是“/Home/Index/MyID”,而myRouteUrl 将为“/”。

         通常,需要将客户端浏览器重定向到另一个URL。使用RedirectToAction方法可以重定向到另一个动作,该方法指示MVC框架把一条重定向指令发布给一个URL,由这个URL调用指定的动作。如:

        /// <summary>
        /// 重定向到另一个动作
        /// </summary>
        /// <returns></returns>
        public RedirectToRouteResult MyActionMethod()
        {
            return RedirectToAction ("Index");
        }

         该方法的一些重载版本可以给生成的URL中片段变量指定控制器和值。

         如果需要用一个URL发送一个重定向,而这个URL只是根据对象的属性生成,则还可以使用RedirectToRoute方法,如:

        /// <summary>
        /// 重定向到根据匿名类型中的属性生成的URL
        /// </summary>
        /// <returns></returns>
        public RedirectToRouteResult MyActionMethod()
        {
            return RedirectToRoute(new { controller = "Home", action = "Home", id = "MyID" });
        }

根据指定路由生成URL

         下面介绍一下如何通过指定的路由生成URL或链接,当然在实际的项目中根据指定路由生成URL是不可取的,主要是因为在视图或动作方法中使用指定的路由名生成URL,等同于在建立视图或动作方法与路由自己的依赖性,而这与MVC思想是不一致的。好了,这里咱们只需要通过这种方式来理解这一过程的实现原理:

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute("MyRoute", "{controller}/{action}");
            routes.MapRoute("MyOtherRoute", "App/{action}", new { controller = "Home" });

        }

         上面为两条路由指定了名称——MyRoute和MyOtherRoute。对路由命名的原因主要有两个:

  • 作为路由目的的一种说明
  • 便于选择特点的路由,用以生成输出URL

   由于前面路由配置已给定了路由顺序,所以,当使用下面的Html.ActionLink方法生成的链接将总是由MyRoute生成,如:@Html.ActionLink(“Click me”,”Index”,”Customer”)

   得到的结果:<a href=”/Customer/Index”>Click me</a>

可以用Html.RouteLink方法(该方法可以指定路由生成链接)覆盖这种默认路由匹配行为,这种方法需要指定一条路由(如下面粗体的“MyOtherRoute”,而斜体的粗体字“Customer”被重写了),如:

@Html.RouteLink(“Click me”,”MyOtherRoute”,”Index”,”Customer”)

         结果:

<a length=”8” href=”/App/Index?Length=5”>Click me</a>

         说明:就像开头说明的这种以指定路由生成URL不是明智之举,但是如果我们需要明确路由的意图时最好还是改用注释来提示。

原文地址:https://www.cnblogs.com/KeSaga/p/5550128.html