生成传出URL时选择了意外的路由考虑如下路由:routes.MapRoute("route1","{controller}/{month}-{year}/{action}/{用户}");routes.MapRoute("route2","{controller}/{month}-{year}/{action}");以下测试:测试1[TestMethod]publicvoidTest1(){RouteCollectionroutes=newRouteCollection();MvcApplication.RegisterRoutes(路线);RequestContextcontext=newRequestContext(CreateHttpContext(),newRouteData());DateTime现在=DateTime.Now;字符串结果;上下文.RouteData。Values.Add("控制器","主页");context.RouteData.Values.Add("action","Index");context.RouteData.Values.Add("用户","user1");结果=UrlHelper.GenerateUrl(null,"Index",null,newRouteValueDictionary(new{month=now.Month,year=now.Year}),routes,context,true);//OK,结果==/Home/10-2012/Index/user1Assert.AreEqual(string.Format("/Home/{0}-{1}/Index/user1",now.Month,now.Year),结果);}Test2[TestMethod]publicvoidTest2(){RouteCollectionroutes=new路线集合();MvcApplication.RegisterRoutes(路线);RequestContextcontext=newRequestContext(CreateHttpContext(),newRouteData());DateTime现在=DateTime.Now;字符串结果;context.RouteData.Values.Add("controller","Home");context.RouteData.Values.Add("action","Index");context.RouteData.Values.Add("用户","user1");context.RouteData.Values.Add("month",now.Month+1);context.RouteData.Values.Add("year",now.Year);结果=UrlHelper.GenerateUrl(null,"Index",null,newRouteValueDictionary(new{month=now.Month,year=now.Year}),routes,context,true);//错误因为result==/Home/10-2012/IndexAssert.AreEqual(string.Format("/Home/{0}-{1}/Index/user1",now.Month,now.Year),result);这个测试模拟了当我在请求上下文中已经有路由值并尝试使用UrlHelper生成传出URL的情况。问题是(在测试2中给出的),如果我有来自预期路线(此处为route1)并尝试通过routeValues参数替换其中一些路段,所需路线将被省略,并使用下一条合适的路线。所以,测试1工作正常,因为请求上下文已经有路由1的5个段中的3个的值,并且通过routeValues参数传递了两个缺失段(即年和月)的值。测试2具有请求上下文中所有5个段的值。我想通过routeValues将其中一些(即月和年)替换为其他值。但是route1好像不太合适,就用route2。为什么?我的路线有什么问题?在这种情况下,我是否希望手动清除请求上下文?编辑[TestMethod]publicvoidTest3(){RouteCollectionroutes=newRouteCollection();MvcApplication.RegisterRoutes(路线);RequestContextcontext=newRequestContext(CreateHttpContext(),newRouteData());DateTime现在=DateTime.Now;字符串结果;context.RouteData.Values.Add("controller","Home");context.RouteData.Values.Add("action","Index");context.RouteData.Values.Add("月",now.Month.ToString());context.RouteData.Values.Add("年",now.Year.ToString());结果=UrlHelper.GenerateUrl(null,"Index",null,newRouteValueDictionary(new{month=now.Month+1,year=now.Year+1}),routes,context,true);断言。AreEqual(string.Format("/Home/{0}-{1}/Index",now.Month+1,now.Year+1),result);这个测试让事情变得更加混乱。我在这里测试route2。有用!我在请求上下文中有所有4个段的值,通过routeValues传递其他值,结果传出URL就可以了。所以,问题出在route1上。我错过了什么?编辑来自SandersonS.FreemanA.-ProASP.NETMVC3Framework第3版:路由系统按照将路由添加到传递给RegisterRoutes方法的RouteCollection对象的顺序处理路由。检查每个路由是否匹配,这需要满足三个条件:必须为URL模式中定义的每个段变量提供一个值。为了找到每个段变量的值,路由系统首先查看我们提供的值(使用匿名类型的属性),然后查看当前请求的变量值,最后查看路由中定义的默认值。我们为段变量提供的值都不会与路径中定义的仅默认变量不一致。我在这些路由中没有默认值所有段变量的值必须满足路由约束。我在这些路由中没有约束,因此,根据我在匿名类型中指定值的第一条规则,我没有默认值。当前请求的变量值——我想这是来自请求上下文的值。这些针对route2的推理在适用于route1时有什么问题?编辑实际上一切都不是来自单元测试,而是来自真正的mvc应用程序。在那里,我使用UrlHelper.Action方法(String,Object)生成传出URL。由于此方法用于布局视图(大多数视图的父级),我已将其包含在我的扩展助手方法中(以从视图中排除额外的逻辑),此扩展方法从请求中提取操作名称上下文,传递为给它一个参数。我知道我可以通过请求上下文提取所有当前路由值并替换那些年和月(或者我可以创建一个匿名路由值集合,包含上下文中的所有值),但我认为这是多余的,因为mvc自动考虑到请求上下文中包含的值。所以,我只是提取了动作名称,因为没有UrlHelper.Action重载没有动作名称(或者我什至喜欢“不指定”动作名称),并通过匿名路由值对象添加了新的月份和年份。这是一个扩展方法:publicstaticMvcHtmlStringGetPeriodLink(thisHtmlHelperhtml,RequestContextcontext,DateTimedate){UrlHelperurlHelper=newUrlHelper(context);返回MvcHtmlString.Create(urlHelper.Action((string)context.RouteData.Values["action"],new{year=date.Year,month=date.Month}));正如我在上面的测试中所描述的,它适用于较短的路径(当请求上下文仅包含控制器、年月和操作时),但较长的路径失败(当请求上下文包含控制器、年和月、操作和用户)。我发布了一个解决方法,让路由按照我需要的方式工作。虽然我确实想知道为什么我必须在这种情况下采取任何变通办法,但这两条路线之间的主要区别在于是什么阻止了route2以route2的方式工作。编辑另一条评论。至于请求上下文中的值是字符串类型,我决定尝试将它们作为字符串设置到上下文中,以确保没有类型混淆(intvsstring)。我不明白,这方面发生了什么变化,但一些路线开始正确生成。但不是所有……这没有什么意义。我在一个真实的应用程序中更改了它,而不是在测试中,因为测试在上下文中有整数,而不是字符串。好吧,我找到了使用route1的条件——只有当上下文中的月和年的值等于匿名对象中给定的值时才使用它。如果它们不同(在对int和string的测试中),请使用route2。但为什么?这证实了我在实际应用程序中的意思:我在上下文中有strings,但通过匿名对象提供int,这在某种程度上混淆了mvc,并且它无法使用route1。我将匿名对象中的整数更改为字符串s,并且上下文中的月份和年份等于匿名对象中的URL,开始正确生成;而其他人则没有。所以我看到一个规则:匿名对象的属性应该是string类型,以匹配请求上下文中路由值的类型。但这条规则似乎并不是强制性的,因为在Test3中,我更改了类型(你现在可能会看到),它仍然可以正常工作。MVC设法正确转换类型。最后,我找到了所有这些行为的解释。请看下面的答案。这是我用来让它工作的快速修复:publicstaticMvcHtmlStringGetPeriodLink(thisHtmlHelperhtml,RequestContextcontext,DateTimedate){context.RouteData.Values["month"]=date.Month;context.RouteData.Values["year"]=date.Year;返回MvcHtmlString.Create(urlHelper.Action((string)context.RouteData.Values["action"]));}我只是从context.RouteData.Values中获取删除月份和年份条目。我只是替换了请求上下文中的月份和年份条目。如果您将它们从上下文中移除(就像我之前所做的那样),它们将无法用于之后调用的辅助方法。这种方法使我的扩展方法根据测试1中描述的场景工作(参见问题)。FINALYPerusingSandersonS.,FreemanA.-ProASP.NETMVC3Framework(3rdEdition)我至少找到了所有这些的解释:ASP.NETMVC第2部分详细信息第11章URL,路由和区域生成传出URLs在UnderstandingSegmentVariableReuse部分:路由系统将仅重用URL模式中较早出现的段变量的值,而不是提供给Html.ActionLink方法的任何参数。我的月-年段在控制器之后立即得到满足,我确定了月份和年份值,所有尾随段(action,user)都没有被重用。在我的例子中,没有在我的匿名对象中指定它们,它们似乎不可用于路由。因此无法匹配route1。书中甚至有一句警告:处理这种行为的最好方法就是防止它发生。我们强烈建议您不要依赖此行为,并为URL模式中的所有段变量提供值。依赖这种行为不仅会使您的代码难以阅读,而且您最终会对用户发出请求的顺序做出假设,这最终会在您的应用程序进入维护阶段时困扰您。好吧,它咬了我)))值得记住丢失的100个代表(我将在这里再次重复)规则:路由系统将只重用早于分段变量的URL模式中的值,而不是任何提供的参数。一条带有默认用户的路由就足够了吗?即routes.MapRoute("route1","{controller}/{month}-{year}/{action}/{user}",new{user=""});否则你必须允许更具体的用户路由,以便在创建URL时首先不匹配route2。UPDATE:我建议离开你的助手,直接使用Url.Action,这里有两个测试你的场景:很有用,需要多了解C#学习教程,希望大家多多关注——[TestFixture]publicclassRouteRegistrarBespokeTests{私有UrlHelper_urlHelper;[设置]publicvoidSetUp(){varroutes=newRouteCollection();路线。清除();varrouteData=newRouteData();RegisterRoutesTo(路线);varrequestContext=newRequestContext(HttpMocks.HttpContext(),routeData);_urlHelper=newUrlHelper(requestContext,routes);[测试]publicvoidShould_be_able_to_map_out_sample(withuser_)varnow=DateTime.Now;varresult=_urlHelper.Action("Index","Sample",new{year=now.Year,month=now.Month});Assert.AreEqual(string.Format("/Sample/{0}-{1}/Index",now.Month,now.Year),result);}[测试]publicvoidShould_be_able_to_map_sample_with_user(){varnow=DateTime.Now;varresult=_urlHelper.Action("Index","Sample",new{user="user1",year=now.Year,month=now.Month});断言AreEqual(string.Format("/Sample/{0}-{1}/Index/{2}",now.Month,now.Year,"user1"),result);}privatestaticvoidRegisterRoutesTo(RouteCollectionroutes){routes.MapRoute("route1","{controller}/{month}-{year}/{action}/{user}");routes.MapRoute("route2","{controller}/{month}-{year}/{action}");}}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如有转载请注明出处:
