《ASP.NET MVC 4 实战》学习笔记 9:路由(上)

本书第8章《安全性》相对偏理论,偶感觉比较枯燥故略过,应该不会影响后面的学习。。。好吧,是我想偷懒。。。

一、URL路由介绍:

1.默认路由:

当创建一个新的MVC 5应用程序时,默认的项目模板会在RouteConfig.cs文件中创建默认路由,并在Global.asax注册路由:

    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");//忽略路由

            routes.MapRoute(
                name: "Default",//路由名
                url: "{controller}/{action}/{id}",//参数式URL
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }//参数默认值
            );
        }
    }
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }

2.入站路由与出站路由:

入站路由(Inbound Routing):将URL映射到控制器或动作及任何附加参数;

出站路由(Outbound Routing):通过控制器、动作及任意附加参数构造与URL方案匹配的URL。

二、设计URL方案:
  设计URL方案的一般性原则:

  • 建立简单、整洁的URL;
  • 建立可破解的URL;
  • 用URL参数区分请求;
  • 尽可能避免暴露数据库ID;
  • 考虑添加多余信息。

三、实现路由:

1.在线商店URL方案:

2.添加自定义静态路由:
  路由1和2是纯静态路由:

            routes.MapRoute("home", "", new { controller = "Home", action = "Index" });
            routes.MapRoute("privacy_policy", "privacy", new { controller = "Home", action = "Privacy" });

注意:添加到路由表中的路由次序决定了查找匹配时的路由搜索顺序。这意味着源代码中列出的路由应当从带有最具体条件的最高优先级降到最低优先级或全匹配路由。

3.添加自定义的动态路由:

  路由3和4是用两个路由参数实现的:

            routes.MapRoute("product", "products/{productCode}/{action}",
                            new { controller = "Catalog", action = "Show" });

上面路由中productCode参数是必需的但action是可选的,因为后面的匿名类型中为action提供了默认值“Show”。

   路由5和6:

            routes.MapRoute("catalog", "{action}",
                            new { controller = "Catalog" },
                            new { action = @"basket|checkout" });

这些路由几乎是静态路由,只不过它们是用一个参数和一个路由约束来实现的,以保持较少的路由数目。这么做的原因有两个:1)每个请求都必须扫描路由表进行匹配,所以大的路由集合会影响到性能;2)路由越多路由优先级问题出现的风险也越高。

4.全匹配路由:

我们将添加一个全匹配路由用来匹配尚未被其他路由匹配的任何URL,这一路由的目的是显示HTTP的404错误消息。全局的全匹配路由能够匹配任意URL,因为它应该是最后一条被定义的路由:

            routes.MapRoute("404-catch-all", "{*catchall}", new { Controller = "Error", Action = "NotFound" });

值catchall为全匹配路由要拾取的值提供了一个名称。与规则路由参数不同,全匹配参数会捕获包括正斜线在内的整个URL部分。在上述示例中,该路由会被映射到ErrorController的NotFound动作:

namespace RoutingSample.Controllers
{
    public class ErrorController : Controller
    {
        public ActionResult NotFound()
        {
            return new NotFoundResult();
        }
    }
}

其中NotFoundResult为能生成404的自定义动作结果:

namespace RoutingSample
{
    public class NotFoundResult : ActionResult
    {
        public override void ExecuteResult(ControllerContext context)
        {
            context.HttpContext.Response.StatusCode = 404;
            new ViewResult() { ViewName = "NotFound" }.ExecuteResult(context);
        }
    }
}

四、使用路由系统生成URL:

每当网站需要一个URL时,框架根据路由规则自动生成这个URL而不是使用一个固定的URL字符串(硬编码)。我们需要指定一种控制器、动作以及参数的组合,剩下的由ActionLink方法完成。ActionLink是MVC框架中HtmlHelper类上的一个扩展方法,它会生成一个完整的HTML<a>元素,如:

@Html.ActionLink("MVC4实战","Show","Catalog",new{productCode="mvc-in-action"},null)

生成:

<a href="/products/mvc-in-action">MVC4实战</a>

有时我们需要将一些附加参数传递给动作,如:

@Html.ActionLink("MVC4实战","Show","Catalog",new{productCode="mvc-in-action",currency="USD"},null)

本例中传递了currency参数。如果该参数与路由中的某个部分匹配它将称为URL的一部分,否则它将被附加到查询字符串。上述代码生成的链接为:

<a href="/products/mvc-in-action?currency=USD">MVC4实战</a>

如果你希望请求一条特定的路由,可以使用RouteLink,它接受一个标识被请求路由的参数,如:

@Html.RouteLink("MVC4实战","product",new{productCode="mvc-in-action"},null)

这个代码将查找一个带有product名称的路由,而不是指定的控制器和动作。

如果你需要获得一个URL,但不是为了链接或表单(这通常发生在编写Ajax代码并需要设置一个请求URL时)。UrlHelper类能够直接生成URL,由ActionLink方法或其他方法使用,如:

@Url.Action("Show","Catalog",new{productCode="mvc-in-action"})

这个代码返回“/products/mvc-in-action”,但是没有任何包围标签(即一个单纯的URL)。

五、ASP.NET Web Form的路由:

 前述的在线商店示例假设有一个最初用ASP.NET Web Form写成的遗留页面ProductByCategory.aspx,它列出按产品类别进行分组的产品:

namespace RoutingSample
{
    public partial class ProductsByCategory : Page
    {
        private readonly ProductRepository _productRepository = new ProductRepository();

        protected void Page_Load(object sender, EventArgs e)
        {
            string category=Request.QueryString["category"]; 
            var productsByCategory = _productRepository.GetProductsByCategory(category);

            _groupedProductsRepeater.DataSource = productsByCategory;
            _groupedProductsRepeater.DataBind();
        }
    }
}
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ProductsByCategory.aspx.cs" Inherits="RoutingSample.ProductsByCategory" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Products by Category</title>
        <link rel="Stylesheet" href="~/Content/Site.css" type="text/css" />
    </head>
    <body>
        <form id="form1" runat="server">
            <ul>
                <asp:Repeater runat="server" ID="_groupedProductsRepeater">
                    <ItemTemplate>
                        <li>
                            <strong><%# Eval("Category") %></strong>
                            <ul>
                                <asp:Repeater runat="server" DataSource=‘<%# Eval("Products") %>‘>
                                    <ItemTemplate>
                                        <li>
                                            <%# Eval("Name") %>
                                        </li>
                                    </ItemTemplate>
                                </asp:Repeater>
                            </ul>
                        </li>
                    </ItemTemplate>
                </asp:Repeater>
            </ul>
        </form>
    </body>
</html>

1.添加用于Web Form页面的路由:

            routes.MapPageRoute(
                "ProductsByCategory",
                "products/ByCategory/{category}",
                "~/ProductsByCategory.aspx",
                checkPhysicalUrlAccess: true,
                defaults: new RouteValueDictionary(new { category = "All" }));

2.修改Web Form以使用RouteData:

        protected void Page_Load(object sender, EventArgs e)
        {
            //string category=Request.QueryString["category"];
            string category = (string)RouteData.Values["category"];//通过路由数据提取值
            var productsByCategory = _productRepository.GetProductsByCategory(category);

            _groupedProductsRepeater.DataSource = productsByCategory;
            _groupedProductsRepeater.DataBind();
        }

3.通过Web Form页面生成URL:

我们可以利用Web Form页面的路由基础架构来生成指向其他路由的链接,包括映射到控制器动作的链接。修改页面:

                                <asp:Repeater runat="server" DataSource=‘<%# Eval("Products") %>‘>
                                    <ItemTemplate>
                                        <li>
                                            <asp:HyperLink runat="server" 
                                                NavigateUrl=‘<%# GetRouteUrl(new { controller="Catalog",action="Show",productCode=Eval("Code")})%>‘ 
                                                Text=‘<%# Eval("Name") %>‘ />
                                        </li>
                                    </ItemTemplate>
                                </asp:Repeater>

在循环标记中调用GetRouteUrl方法,将它的值绑定到asp:Hyperlink的NavigateUrl属性。该方法接受一个匿名类型,在其中指定想要链接到的控制器与动作以及参数。

源码下载 密码:onoy

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。