• 以路由控制URL


          至此为止,我们一直在使用ASP.NET MVC新项目随带的默认路由配置。现在我们将深入探讨路由系统,并学习如何创建应用程序的自定义路由,以确保URL既是用户友好又是搜索引擎可访问的。

          路由的全部内容都是关于URL以及如何将URL作为应用程序的外部输入的。当使用其他开发工具,如PHP、Web Form或是经典的ASP时,URL通常对应于磁盘上的物理文件。一个http://example.com/Products.aspx这样的URL会导致执行负责处理该请求的名为Products.aspx的文件。

          通过使用URL路由,ASP.NET MVC解除了URL与物理文件的耦合。路由提供了一种把无扩展名的URL映射到控制器动作的方式,让开发人员对URL方案有完全的控制。

          在本章中,我们将介绍路由概念及其与MVC应用程序的关系,还将简要介绍它们如何用于ASP.NET Web Form项目。我们将考察如何设计应用程序的URL方案,然后将这些概念运用于创建一个示例应用程序的路由。最后看看如何测试路由,以确保它们按预期工作。

    一、介绍URL路由

        与将URL绑定到磁盘上的物理文件不同,ASP.NET MVC引入的URL路由的底层结构能够将URL映射到控制器动作,而无须在服务器上有物理文件作为URL的目标。在本节中,我们将考察新建MVC项目随带的默认路由的结构,以及这些路由是如何与控制器和动作的概念相关联的。    

    1.默认路由

        当创建一个新的ASP.NET MVC应用程序时,默认的项目模板会在Global.asax文件中调用一个名称为RegisterRoutes的方法。该方法负责为应用程序配置路由,并定义了最初两条路由——一条忽略路由和一条遵循{controller}/{action}/{id}模式的默认路由,如下所示。

          路由是通过调用MapRoute方法而定义的,该方法有个过载。在这个例子中,默认路由是通过调用三个参数的过载来配置的。第一个参数是路由名("Default")。第二个参数是用来匹配URL的URL模式。本例中,URL模式被定义为具有三个片段——控制器、动作和ID。第三个参数是一个匿名类型,它为这些片段定义了默认值。

          如果用户访问http://example.com/users/edit/5这样的URL,这将匹配默认路由,因为它有三个片段,如图所示。

          在这个例子中,字符串users映射到controller参数,edit映射到actio,而5映射到id。由于这个URL显然与路由相匹配,MVC框架会尝试查找名称为UsersController的类、调用Edit方法,并为其id参数传递5。如果找不到控制器或动作,框架会产生一个404错误。

          添加到路由定义中的默认参数意味着URL不必精确地匹配三片段URL模式。如果指定了默认控制器Home以及默认动作Index,当控制器片段省略时,路由将默认控制器为HomeController。同样,如果动作片段未指定,则路由会默认寻找Index动作。Id参数的默认值UrlParameter.Optional,意指不论是否指定第三个片段,路由都可以被匹配。下表给出了几个能匹配默认路由的例子。

    URL 路由参数 被选中的动作方法
    http://example.com/Users/Edit/5 Controller=User, Action=Edit, id=5 UsersController.Edit(5)
    http://example.com/Users/Edit Controller=User, Action=Edit UsersController.Edit()
    http://example.com/Users Controller=User, Action=Index UsersController.Index()
    http://example.com Controller=User, Action=Index HomeController.Index()

          在IgnoreRoute方法中,模式{resource}.axd/{*pathInfo}确保文件扩展名为.axd的任何URL不会被路由引擎所处理,这样才能确保任何自定义HTTP处理程序(其扩展名为.axd)以正确方式呗处理,而不会被路由引擎拦截。

    2.入站与出站路由

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

          出站路由(Outbound Routing):通过一组给定的路由数据(通常是控制器和动作)生成相应的URL。

         上图所示的入站路由描述了一个控制器动作的URL调用。HTTP请求进入ASP.NET管道,并通过ASP.NET MVC应用程序注册的路由进行发送。每个路由都有处理请求的机会,而匹配路由随后会指定被使用的控制器和动作。

    二、设计URL模式(schema)

    1.建立简单、整洁的URL

                        传统URL:http://example.com/eventmanagement/events_by_month.aspx?year=2011&month=4

          使用路由系统的URL:http://example.com/events/2011/04

          这种URL带来的好处是,其中的日期有了一种明确的层次格式。

    2.建立可破解的URL

          在设计URL方案时,考虑最终用户为了改变所显示的数据要如何操纵或“破解”URL是有价值的。例如,也许可以合理地假设,从以下URL移去参数“04”,可能表示2011年发生的全部事件:

          http://example.com/events/2011/04

          同样的逻辑可以形成下表所示的更全面的路由列表。

    URL 描述
    http://example.com/events 显示全部事件
    http://example.com/events/<year> 显示某年事件
    http://example.com/events/<year>/<month> 显示某月事件
    http://example.com/events/<year>/<month>/<day> 显示某日事件

          让URL模式具有这种灵活性是很棒的,但这可能会导致应用程序中具有大量潜在的URL。在建立应用程序视图时,你总是要改出相应的导航。记住,可能在各个页面上不必对每个可能的URL组合都包含一个链接。在用户试图破解URL并使其生效时,让用户有一些惊喜的发现反而是件好事。

          如果不希望用户破解,可考虑使用连接字符来替代斜线,如/events/2008-04-01。

    3.使用URL参数区分请求

          让我们对此路由加以扩展,并允许按类别列出事件。从用户的观点来看,最有用的URL可能像这样:

    http://example.com/events/aspnet-usergroup-meeting

          但现在有问题了!我们已经有了一个与/events/<something>形式匹配的路由,用来列出特定年、月、日的事件,那么现在如何用/events/<something>也匹配类别?第二个路由片段现在意味着完全不同的含义,这与现有的路由不协调了。如果把这种URL交给路由系统,它应该把这种参数可能作类别还是日期?
          幸运的是,ASP.NET MVC的路由系统允许我们运用条件,使用正则表达式来确保路由只与某个模式的参数相匹配就够了。这意味着我们可以只用一条路由,就能让/events/2011-01-01形式的请求传递给按日期显示事件的动作,而让/events/asp-net-mvc-in-action形式的请求传递给按类别显示事件的动作。

    4.尽可能避免暴露数据库ID

           一个用于托管开发人员事件的网站可能会定义这样的URL:

    http://example.com/events/87

          87是从数据库获得的每一个对象都有一个主键形式的唯一标识符,但是除了数据库管理员之外,数字87对任何人都毫无意义。因此,应该尽可能避免在URL中使用数据库生成的ID,尽量让它们有意义、可读、易于理解。

    http://example.com/events/houstonTechFest2010

    5.考虑添加多余信息

          如果必须在URL中使用数据库ID,可考虑添加除了使URL可读外没什么目的的附加信息。

    http://example.com/events/houstonTechFest2010/session-87
    http://example.com/events/houstonTechFest2010/session-87/an-introduction-to-mvc

    --------------------------------------------------------------------

    搜索引擎优化(SEO)

          当涉及网站的搜索引擎优化方面时,有必要提一提设计良好的URL的价值,在URL中放置一个相关的关键字提升搜索引擎排序。设计要点如下:

    • 为控制器和动作使用描述性的、简单的、普遍使用的单词。力求尽可能相关并使用可能用于所建页面的关键词。
    • 当在路由中包含文本参数时,用连接字符替换所有的空格符。
    • 去掉字符串参数中不重要的标点和不必要的文本。
    • 在URL可能的地方包含附加的、有意义的信息,如标题和描述等。

    ----------------------------------------------------------------------

    三、在ASP.NET MVC中实现路由

          默认项目模板创建了两个默认路由,但你可以不接受这两个默认路由的限制,添加自己的路由,以实现完全自定义的URL模式。以下将对此加以演示,以一个简单的在线商店为例,实现几个路由。我们将考察如何创建简单、静态的路由,以及创建更复杂的使用参数的路由和全匹配路由。

    1.在线商店的URL模式(重要)

    路由号 URL 描述
    1 http://example.com/ 首页,重定向到分类列表
    2 http://example.com/privacy 显示包含网站私有策略的静态页面
    3 http://example.com/products/<productcode> 显示相应产品代码的产品详情页面
    4 http://example.com/products/<productcode>/buy 将相应产品添加到购物篮
    5 http://example.com/basket 显示当前用户的购物篮
    6 http://example.com/checkout 启动当前用户的结算过程

          注意:路由4中的URL不是设计给用户看的,它通过表单递交进行链接,在动作处理完成后会立即进行重定向,因而这种URL不会在地址栏中出现。

    2.添加自定义静态路由

          路由1是由默认路由处理的。

          路由2,是一个纯静态路由,将http://example.com/privacy映射到HomeController的Privacy动作。

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

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

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

          当有少量偏离一般规则的URL时,静态路由是有用的。如果路由包含与页面显示的数据相关的信息,就需要动态路由了。

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

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

          两个占位符将匹配URL中用斜线分隔的片段,productCode参数是必需的,但action是可选的。如果action未指定,该路由会默认指向CatalogController上的Show动作,并传递productCode参数。详细代码如下。

    public class CatalogController : Controller
        {
            private ProductRepository _productRepository = new ProductRepository();
    
            public ActionResult Show(string productCode)
            {
                var product = _productRepository.GetByCode(productCode);
    
                if (product == null)
                {
                    return new NotFoundResult();
                }
                return View(product);
            }
    
        }

         实现一个执行时能生成HTTP 404的自定义动作结果:

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

          NotFoundResult通过集成ActionResult,在其中提供了必须实现的ExecuteResult方法。该方法将响应状态码设置为404,然后渲染一个名为NotFound的视图,该视图位于Views/Shared目录。

          注意:HttpNotFoundResult动作,也将响应转台码设置为404,但它未提供显示自定义错误页面的机制,因此总是会给最终用户显现一个空屏。

          最后,我们可以添加模式中的路由5和路由6。

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

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

          MapRoute方法的第四个参数包含了路由约束。约束参数是一个匿名类型形式的字典,可以用于指定如何约束特定的路由参数。在本例中,我们使用了一个正则表达式来指明,仅当片段字符串为“basket”或“checkout”时,才匹配action参数。这种约束能够适当地阻止把未知动作传递给控制器。

    4.全匹路由

          我们现在已经添加了静态和动态路由,以便为网站的不同URL提供内容。但假设有一个与所有路由都不匹配的请求,会发生什么?结果会抛出一个异常,这是实际应用程序中不希望发生的事情。为了对此加以处理,我们可以使用与ASP.NET的错误处理基础架构结合在一起的全匹配路由。

          我们将添加一个全匹配路由,用它匹配尚未被其他路由匹配的任何URL,显示HTTP404的错误消息,它应该是最后一条被定义的路由。

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

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

    public class ErrorController: Controller
    {
        public ActionResult NotFound()
        {
            return new NotFoundResult();
        }
    }

          现在,可以删去默认的{controller}/{action}/{id}路由,因为我们已经完全定制了路由,以匹配我们的URL模式。或者,你也许会选择保留它,以作为访问其他控制器的一种默认方式。

    四、使用路由系统生成URL

        每当网站中需要一个URL时,我们都要求框架给出,而不是采用硬编码。我们需要制定一种控制器、动作以及参数的组合,剩下的由ActionLink方法完成。ActionLink是MVC框架中HtmlHelper类上的一个扩展方法,它会生成一个插入了正确URL的完整的HTML<a>元素,该URL与传递进来的对象参数所指定的路由相匹配。以下是调用ActionLink的一个例子:

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

           第一个是超链接的显示文本;第二个和第三个指定了要被链接到的动作和控制器;第四个采用了一个匿名类型形式的字典,以指定任意的附加路由参数;最后一个是仍以匿名类型形式指定的任意的附加HTML属性。

          使用前面定义的路由,这个例子会生成一个链接,指向CatalogController上的Show动作,并带有为productCode指定的附加参数。以下是其输出:

    <a href="/products/mvc-in-action">MVC3 in Action</a>

          类似地,如果使用HtmlHelper的BeginForm方法来建立表单标签,它会为你生成URL。有时,能够将路由部分未指定的参数传递给动作时有用的:

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

          如果该参数与路由中的某个部分匹配,它将成为URL的一部分。否则,它将被附加到查询字符串。比如,以下是上述代码生成的链接:

    <a href="/products/mvc-in-action?currency=USD">MVC3 in Action</a>

           在使用ActionLink时,被选中的路由是路由集合中所定义的第一个匹配路由。大多数情况下,这是足够的,但如果你希望请求一条特定的路由,可以使用RouteLink,它接受一个标识被请求路由的参数,像这样:

    @Html.RouteLink ( "MVC3 in Action", "Show", "Catalog", 
    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,但没有任何包围标签。

  • 相关阅读:
    数据库的读读事务也会产生死锁
    数据库中的two phase locking
    排序合并连接(sort merge join)的原理
    SQL Server2016 原生支持JSON
    公司内部培训SQL Server传统索引结构PPT分享
    postgresql的ALTER经常使用操作
    POJ 1458 Common Subsequence(最长公共子序列LCS)
    Docker 1.3 公布
    spring bean之间的关系:继承;依赖
    hdu 1215 七夕节
  • 原文地址:https://www.cnblogs.com/meetyy/p/4134615.html
Copyright © 2020-2023  润新知