六、调试路由:
1.安装Route Debugger:
在NuGet包管理器控制台输入:
install-package routedebugger
2.使用Route Debugger:
一旦安装了Route Debugger对RouteDebugger.dll的引用便被添加到项目中,web.config也会添加一条新的应用程序设置:
<add key="RouteDebugger:Enabled" value="true" />
注:在部署应用程序之前要确保禁用了Route Debugger,即将RouteDebugger:Enabled设为false。
启动调试,进入ProductsByCategory页面,可以看到:
“Route Debugger”部分显示了与当前请求匹配的路由参数;“Data Tokens”部分显示了与该路由关联在一起的任意自定义数据标记;“All Routes”部分通过在“Matches CurrentRequest”列显示True表示哪些路由可能潜在地与当前请求匹配,该列为True的第一条路由是被选来处理当前请求的路由。
我们修改“ProductsByCategory”路由为:
routes.MapPageRoute( "ProductsByCategory", "products/ByCategory/{category}", "~/ProductsByCategory.aspx", checkPhysicalUrlAccess: true, defaults: new RouteValueDictionary(new { category = "All" })); routes.MapRoute("404-catch-all", "{*catchall}", new { Controller = "Error", Action = "NotFound" });
然后访问/Products/ByCategory,会报错:
从图中我们可以看到有好几条与/Products/ByCategory地址匹配的路由,但匹配的第一条路由是“products”,用户被带到产品信息页而不是ProductsByCategory页。
3.使用路由约束:
上例中为了不让任何输入都与“products”路由的“productCode”片段匹配,我们可以用一个正则表达式来限制什么内容能与这一参数匹配:
routes.MapRoute("product", "products/{productCode}/{action}", new { controller = "Catalog", action = "Show" }, new { productCode="(?!ByCategory).*"});
此例我们使用正则表达式排除了字符串ByCategory。我们也可以使用自定义约束来代替正则表达式:
namespace RoutingSample { public class NotEqualConstraint : IRouteConstraint { private string _input; public NotEqualConstraint(string input) { _input = input; } public bool Match(HttpContextBase httpContext, //HTTP上下文的引用 Route route, //约束的路由 string parameterName, //被约束的路由参数名 RouteValueDictionary values, //当前路由值集合 RouteDirection routeDirection //指明该路由是用来匹配输入请求还是用于生成URL ) { object matchingValue; if (values.TryGetValue(parameterName, out matchingValue)) { if (_input.Equals((string)matchingValue, StringComparison.OrdinalIgnoreCase)) { return false; } } return true; } } }
routes.MapRoute("product", "products/{productCode}/{action}", new { controller = "Catalog", action = "Show" }, new {productCode=new NotEqualConstraint("ByCategory")});
七、测试路由行为:[我又晕了。。。]
1.测试入站路由:
1)测试路由的硬方式:
首先引入NUnit:
install-package nunit -version 2.6.3
添加测试:
namespace RoutingSample.Tests { [TestFixture] public class NotUsingTestHelper { [Test] public void root_matches_home_controller_index_action() { const string url = "~/"; // 建立模仿请求 var request = MockRepository.GenerateStub<HttpRequestBase>(); request.Stub(x => x.AppRelativeCurrentExecutionFilePath) .Return(url).Repeat.Any(); request.Stub(x => x.PathInfo) .Return(string.Empty).Repeat.Any(); var context = MockRepository .GenerateStub<HttpContextBase>(); context.Stub(x => x.Request) .Return(request).Repeat.Any(); // 注册路由 RouteTable.Routes.Clear(); RouteConfig.RegisterRoutes(RouteTable.Routes); var routeData = RouteTable.Routes.GetRouteData(context);// 获取用于请求的路由 Assert.That(routeData.Values["controller"], Is.EqualTo("Home"));// 断言控制器正确 Assert.That(routeData.Values["action"], Is.EqualTo("Index")); //断言动作正确 } } }
2)使用MvcContrib的路由测试扩展:
首先安装MvcContrib.TestHelper程序集:
install-package mvccontrib.mvc3.testhelper-ci
添加测试:
[TestFixtureSetUp] public void FixtureSetup() { RouteTable.Routes.Clear(); RouteConfig.RegisterRoutes(RouteTable.Routes); } [Test] public void root_maps_to_home_index() { "~/".ShouldMapTo<HomeController>(x => x.Index());// 断言URL映射到动作 }
3)测试示例路由:
namespace RoutingSample.Tests { [TestFixture] public class UsingTestHelper { [TestFixtureSetUp] public void FixtureSetup() { RouteTable.Routes.Clear(); RouteConfig.RegisterRoutes(RouteTable.Routes); } [Test] public void root_maps_to_home_index() { "~/".ShouldMapTo<HomeController>(x => x.Index());// 断言URL映射到动作 } [Test] public void privacy_should_map_to_home_privacy() { "~/privacy".ShouldMapTo<HomeController>(x => x.Privacy()); } [Test] public void products_should_map_to_catalog_index() { "~/products".ShouldMapTo<CatalogController>(x => x.Index()); } [Test] public void product_code_url() { "~/products/product-1".ShouldMapTo<CatalogController>(x => x.Show("product-1")); } [Test] public void product_buy_url() { "~/products/product-1/buy".ShouldMapTo<CatalogController>(x => x.Buy("product-1")); } [Test] public void basket_should_map_to_catalog_basket() { "~/basket".ShouldMapTo<CatalogController>(x => x.Basket()); } [Test] public void checkout_should_map_to_catalog_checkout() { "~/checkout".ShouldMapTo<CatalogController>(x => x.CheckOut()); } [Test] public void _404_should_map_to_error_notfound() { "~/404".ShouldMapTo<ErrorController>(x => x.NotFound()); } [Test] public void ProductsByCategory_MapsToWebFormPage() { "~/Products/ByCategory".ShouldMapToPage("~/ProductsByCategory.aspx"); } } }
2.测试出站路由:
namespace RoutingSample.Tests { [TestFixture] public class OutboundUrlTests { [TestFixtureSetUp] public void FixtureSetup() { RouteTable.Routes.Clear(); RouteConfig.RegisterRoutes(RouteTable.Routes); } [Test] public void Generate_home_url() { OutBoundUrl.Of<HomeController>(x => x.Index()) .ShouldMapToUrl("/"); } [Test] public void Generates_products_url() { OutBoundUrl.Of<CatalogController>(x => x.Show("my-product-code")) .ShouldMapToUrl("/products/my-product-code"); } } }
源码下载 密码:mh5o