以路由控制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方案,而后将这些概念运用于建立一个示例应用程序的路由。最后看看如何测试路由,以确保它们按预期工做。session

1、介绍URL路由架构

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

1.默认路由框架

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

      路由是经过调用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应用程序注册的路由进行发送。每一个路由都有处理请求的机会,而匹配路由随后会指定被使用的控制器和动做。

2、设计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可能的地方包含附加的、有意义的信息,如标题和描述等。

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

3、在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模式。或者,你也许会选择保留它,以做为访问其余控制器的一种默认方式。

4、使用路由系统生成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,但没有任何包围标签。

相关文章
相关标签/搜索