MVC杂记<->---路由
在学习MVC的过程中,记录一些基础但很必要的东西。
ASP.NET路由
学习MVC很多同学都喜欢使用默认的路由配置,而不关心怎么去利用它实现一些复杂的或者自定义的配置,下面结合MSDN一起学习一下
1.MVC路由有什么用处?
答:路由被用于匹配有客户端发送过来的HTTP请求,返回适当的网址给浏览器。
2.路由定义的网址和非路由定义的网址有什么区别?
答:在不使用路由的 ASP.NET 应用程序中,对 URL 的传入请求通常映射到处理该请求的物理文件,如 .aspx 文件。 例如,对 http://server/application/Products.aspx?id=4 的请求映射到名为 Products.aspx 的文件,该文件包含代码和标记用于呈现对浏览器的响应。 网页使用查询字符串值 id=4 来确定要显示的内容类型。
在 ASP.NET 路由中,可以定义 URL 模式,这些模式映射到请求处理程序文件但是不必在 URL 中包含这些文件的名称。 另外,可以在 URL 模式中包含占位符,以便无需查询字符串,即可将变量数据传递到请求处理程序。
例如,在请求 http://server/application/Products/show/beverages 时,路由分析器可以将值 Products、show 和 beverages 传递给页处理程序。 在此示例中,如果路由是使用 URL 模式 server/application/{area}/{action}/{category} 定义的,则页处理程序将收到一个字典集合,在该集合中,与键 area 关联的值为 Products,键 action 的值为 show,键 category 的值为 beverages。 在不由 URL 路由管理的请求中,/Products/show/beverages 片断将被解释为应用程序中一个文件的路径。
好了暂时先简单的说以上两个问题,或许有的同学还是很迷糊,那么我们再进一步的理一下.
我们可以把类似这样的过程简单的看成是请求和响应的过程,那么asp.net路由在这个中间环节怎么处理的哪?
当收到请求时,会将由路由找到适当的UrlRoutingModule 对象来处理,然后传送到Handler HTTP 处理程序。如果Handler HTTP是由MvcHandler HTTP 处理的,那么就进入了MVC的执行生命周期,程序通过向 URL 中的控制器值添加后缀“Controller”以确定将处理请求的控制器的类型名称,来确定要调用的控制器。 URL 中的操作值确定要调用的操作方法。
例如,包含 URL 路径 /Products 的 URL 映射到名为 ProductsController 的控制器。 action 参数中的值是调用的操作方法的名称。 包含 URL 路径 /Products/show 的 URL 将导致调用 ProductsController 类的 Show 方法。
在MVC应用程序中无论是页面的跳转以及链接的显示都是要参考全局处理程序中路由的定义,以使我们能够动态的输出网址。
我们找到Global.ascx文件打开,找到其中的定义的默认路由来初步认识一下它的定义:
1 public class MvcApplication : System.Web.HttpApplication 2 { 3 public static void RegisterGlobalFilters(GlobalFilterCollection filters) 4 { 5 filters.Add(new HandleErrorAttribute()); 6 } 7 8 public static void RegisterRoutes(RouteCollection routes) 9 { 10 routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 11 12 routes.MapRoute( 13 "Default", // 路由名称 14 "{controller}/{action}/{id}", // 带有参数的 URL 15 new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值 16 ); 17 18 } 19 20 protected void Application_Start() 21 { 22 AreaRegistration.RegisterAllAreas(); 23 24 // 默认情况下对 Entity Framework 使用 LocalDB 25 Database.DefaultConnectionFactory = new SqlConnectionFactory(@"Data Source=(localdb)\v11.0; Integrated Security=True; MultipleActiveResultSets=True"); 26 27 RegisterGlobalFilters(GlobalFilters.Filters); 28 RegisterRoutes(RouteTable.Routes); 29 } 30 }
我们知道所有ASP.NETMVC应用程序执行入口是HttpApplication的Application_Start(),所有的Asp.netMVC Routing都在这里定义,来看这一句子:
RegisterRoutes(RouteTable.Routes); 那么又带我转向了RegisterRoutes这个函数的定义处:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");// {resource}代表一个名为resource的RouteValue表达式,只是一个变量名的占位符,是用来放置用不到的变量。{*pathInfo}用于匹配所有完整的路由信息中除去{resource}.axd部分剩余的部分,当然是这个*的作用,如果没有,则不能匹配完全,来举个例子asd.axd/a/c/v ,如果是{*pathInfo}那么就会全部匹配asd.axd/a/c/v ,如果是{pathInfo}则只会匹配到asd.axd/a。之所以在途中标注是占位符,这些占位符的名字其实起什么都可以。
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值
定义路由时可以为参数分配一个默认值。 如果 URL 没有包括该参数的值,则会使用默认值。 通过将字典对象分配给 Route 类的 Defaults 属性,可以设置路由的默认值
于 MVC 应用程序,通过 RouteCollectionExtensions.MapRoute 方法的重载(例如 MapRoute(RouteCollection, String, String, Object, Object))可以指定默认值。
有时您需要处理包含可变数量的 URL 段的 URL 请求。 定义路由时,可以指定 URL 是否具有比模式中更多的段,是否将额外的段视为最后一个段的一部分。 若要以此方式处理额外的段,可以用星号 (*) 标记最后一个参数。 该参数称为“可用于放置各种信息的”参数。 具有全部捕捉参数的路由也将与那些不包含最后一个参数的任意值的 URL 相匹配。 下面的示例演示一个与未知数量的段匹配的路由模式。
query/{queryname}/{*queryvalues}
ASP.NET 路由处理 URL 请求时,在示例中演示的路由定义得到下表列出的结果。
向路由添加约束
除了按照 URL 中的参数数量将 URL 请求匹配到路由定义中,还可以指定参数中的值满足特定约束。 如果一个 URL 包含路由的约束以外的值,则该路由不用于处理请求。 添加约束以确保 URL 参数包含将在应用程序中起作用的值。约束是通过使用正则表达式或使用实现 IRouteConstraint 接口的对象来定义的。 将路由定义添加到 Routes 集合时,同时也通过创建一个包含验证测试的 RouteValueDictionary 对象添加了约束。 字典中的关键字标识约束适用的参数。 字典中的值可以是表示正则表达式的字符串,也可以是实现 IRouteConstraint 接口的对象。提供字符串后,路由将视字符串为正则表达式,并通过调用 Regex 类的 IsMatch 方法检查参数值是否有效。 总是将正则表达式视为不区分大小写。提供 IRouteConstraint 对象后,ASP.NET 路由将通过调用 IRouteConstraint 对象的 Match 方法检查参数值是否有效。 Match 方法返回一个布尔值,该值指示参数值是否有效。
下面的示例演示如何使用 MapPageRoute 方法创建具有约束的路由,该约束限制可在 locale 和 year 参数中包括的值。 (在 MVC 应用程序中,使用 MapRoute 方法。)
public static void RegisterRoutes(RouteCollection routes) { routes.MapPageRoute("", "Category/{action}/{categoryName}", "~/categoriespage.aspx", true, new RouteValueDictionary {{"categoryName", "food"}, {"action", "show"}}, new RouteValueDictionary {{"locale", "[a-z]{2}-[a-z]{2}"},{"year", @"\d{4}"}} ); }
路由处理 URL 请求时,在上一示例中演示的路由定义生成下表列出的结果。
默认情况下,路由不处理映射到 Web 服务器上现有物理文件的请求。
例如,如果 Products/Beverages/Coffee.aspx 上存在物理文件,则路由不处理对 http://server/application/Products/Beverages/Coffee.aspx 的请求。 即使匹配一个定义的模式(例如 {controller}/{action}/{id}),路由也不处理该请求。
如果希望路由处理所有请求(包括指向文件的请求),可以通过将 RouteCollection 对象的 RouteExistingFiles 属性设置为 true 来重写默认行为。 将该值设置为 true 后,与定义的模式匹配的所有请求都将由路由处理。
为 URL 模式显式禁用路由
还可以指定路由不应处理某些 URL 请求。 通过定义路由并指定应使用 StopRoutingHandler 类来处理该模式,来阻止路由处理某些特定请求。 当 StopRoutingHandler 对象处理请求时,StopRoutingHandler 对象会阻止以任何其他方式将该请求处理为路由。而是会将该请求处理为 ASP.NET 页、Web 服务或其他 ASP.NET 终结点。 可以使用 RouteCollection.Ignore 方法(对于 MVC 应用程序,为 RouteCollectionExtensions.IgnoreRoute)创建使用 StopRoutingHandler 类的路由。 下面的示例演示如何阻止路由处理 WebResource.axd 文件的请求。
public static void RegisterRoutes(RouteCollection routes) { routes.Ignore("{resource}.axd/{*pathInfo}"); }