2013-04-23 36 views
2

我们有一个路由配置,如下所示:ASP.NET路由在两个控制器动作有相同数量的参数

public static void RegisterRoutes(RouteCollection routes) { 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

    routes.MapRoute(
     name: "About", 
     url: "{controller}/{action}/{aboutId}", 
     defaults: new { controller = "Home", action = "About" } 
    ); 

    routes.MapRoute(
     name: "Contact", 
     url: "{controller}/{action}/{contactId}", 
     defaults: new { controller = "Home", action = "Contact" } 
    ); 

    routes.MapRoute(
     name: "Default", 
     url: "{controller}/{action}/{id}", 
     defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
    ); 
    } 

你会发现,有两条路有一个强制性的额外的参数。路线AboutContact

在我们的应用程序,我们有两个URL

www.myapp.com/Home/About/2工作正常。 但是,当我们浏览我们的浏览器www.myapp.com/Home/Contact/5我们得到可怕的路由例外:

The parameters dictionary contains a null entry for parameter 'contactId' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult Contact(Int32)' in 'RoutingTest.Controllers.HomeController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter. 

如果我们改变路由的序列,使得它看起来像这样:

public static void RegisterRoutes(RouteCollection routes) { 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

    routes.MapRoute(
     name: "Contact", 
     url: "{controller}/{action}/{contactId}", 
     defaults: new { controller = "Home", action = "Contact" } 
    ); 

    routes.MapRoute(
     name: "About", 
     url: "{controller}/{action}/{aboutId}", 
     defaults: new { controller = "Home", action = "About" } 
    ); 

    routes.MapRoute(
     name: "Default", 
     url: "{controller}/{action}/{id}", 
     defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
    ); 
    } 

然后Contact网址作品但About网址没有。

HomeController的是这样的:

public class HomeController : Controller { 
     public ActionResult Index() { 
     ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application."; 

     return View(); 
     } 

     public ActionResult About(int aboutId) { 
     ViewBag.Message = "Your app description page."; 

     return View(); 
     } 

     public ActionResult Contact(int contactId) { 
     ViewBag.Message = "Your contact page."; 

     return View(); 
     } 
    } 

什么这似乎意味着是两个路线不能有相同数量的参数,无论是控制器的名字。如果两个控制器动作具有相同名称的参数,则所有工作都正常。我知道我可以开始做非常黑客的事情来解决这个问题,比如调用所有的参数相同的名字,或者给出无意义的参数来改变参数的数量,但我实际上想知道底下发生了什么。

我该如何解决这个问题?

+0

老实说,我不明白为什么你需要在这种情况下,3条不同的路线。所有你需要做的就是删除非默认路由,并用id替换'aboutId'和'contactId'。一切都应该工作... – Aron 2013-04-23 02:48:08

+0

@Aron:这当然是一个人为的例子来证明这个问题。我们有多个不同参数的控制器动作。将它们命名为同样的东西会严重降低代码的可读性。 – 2013-04-23 03:46:13

回答

5

问题的根(不是双关语)不是路由不能有相同数量的参数。他们能。问题是路由引擎将选择匹配传入请求的第一条路由。你的路由只是默认值不同,而模式匹配 - 他们是完全一样的。因此,在每一种情况下,您都应该击中Contact路线。

它看起来像你试图根据行动有不同的路线。我实际上看不出为什么你需要。

您可以使用以下效果。

public static void RegisterRoutes(RouteCollection routes) { 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

    routes.MapRoute(
     name: "Contact", 
     url: "Home/Contact/{contactId}" 
    ); 

    routes.MapRoute(
     name: "About", 
     url: "Home/About/{aboutId}" 
    ); 

    routes.MapRoute(
     name: "Default", 
     url: "{controller}/{action}/{id}", 
     defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
    ); 
} 

但是,我强烈建议不要这种方法,因为你的“默认”路线是联系路线。这意味着(在剃刀下)@Html.ActionLink()和相关的方法将是错误的。

老实说,它应该只是工作完美,如果你只是使用...

public static void RegisterRoutes(RouteCollection routes) { 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

    routes.MapRoute(
     name: "Default", 
     url: "{controller}/{action}/{id}", 
     defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
    ); 
} 
+1

那么采用第二种解决方案(删除除默认路由之外的所有路由)不起作用,并且以相同的异常结束。为了使其工作,您需要为所有单参数控制器操作提供相同的名称“id”。我在我的问题中提到了这一点,并不认为这是一个可接受的解决方案。 – 2013-04-23 04:05:22

+0

@AranMulholland - 路由基于模式匹配工作。没有其他选择,只能更改路线,以便它们具有不同的模式,或重复使用相同的路线。你需要某种差异性,如果你不愿意这样做,它根本行不通。 – 2013-04-24 05:46:37

+0

@MystereMan但是路由包含参数的名称和默认的控制器动作,这是否意味着默认的控制器动作被忽略?您会认为路由引擎可以确定我打算调用控制器操作,因为请求会命名该控制器和操作。 – 2013-04-24 07:02:48

2

指定控制器和/或行动路线明确允许路由挑选正确的路线:

routes.MapRoute(
    name: "About", 
    url: "{controller}/About/{aboutId}", 
    defaults: new { controller = "Home", action = "About" } 
); 

您还可以添加约束参数路由之间进行区分,但它看起来像你的情况这两个操作具有相同的整数参数。

+0

我强烈建议不要采用这种方法,因为它会搞乱'@ Url.Action'和相关帮助程序的路由。 – Aron 2013-04-23 02:57:35

+0

@Aron - 我不完全确定为什么Url.Action不适合你的非默认路由......除了你的建议之外,链接到相关的文章/问题将会有所帮助。 – 2013-04-23 03:07:02

+0

这完全是经验的。 MVC不认可“默认”作为一些神奇的名字。因此“默认”路线是第一个被注册的路线,在这种情况下是关于路线。默认情况下,'@ Url.Action'将使用的路由是关于路由。因此,当渲染例如'@ Html.ActionLink(“Foo”,“Bar”)''时,你会得到一个链接到'http://www.myapp.com/Foo/About/?action = Bar'。这会让你到正确的地方。只是不是很RESTful。 – Aron 2013-04-23 03:14:42

2

你不能只是删除您的自定义路线,只是重复使用(编号)参数(转{的ContactID}和{} aboutId逼到了“身份证”在你的动作代码)?

public class HomeController : Controller { 
    public ActionResult Index() { 
    ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application."; 

    return View(); 
    } 

    public ActionResult About(int id) { 

    int aboutId = id; 

    ViewBag.Message = "Your app description page."; 

    return View(); 
    } 

    public ActionResult Contact(int id) { 

    int contactId = id; 

    ViewBag.Message = "Your contact page."; 

    return View(); 
    } 

}

相关问题