ASP.NET路由,其中​​两个控制器操作具有相同数量的参数

时间:2013-04-23 02:44:45

标签: c# asp.net-mvc asp.net-mvc-routing

我们有这样的路线配置:

  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

在我们的应用中,我们有两个网址

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();
      }
   }

这似乎意味着无论Controller Action的名称如何,两个路由都不能具有相同数量的参数。如果两个控制器操作具有相同名称的参数,则一切正常。我知道我可以开始做非常讨厌的事情来解决这个问题,例如调用所有参数相同的名称或给动作无意义的参数来改变参数的数量,但我真的想知道幕后发生了什么。

如何解决这个问题?

3 个答案:

答案 0 :(得分: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 }
    );
 }

然而。我强烈建议不要采用这种方法,因为您的“默认”路线是联系路线。这意味着(在Razor下)@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 :(得分:2)

明确指定路径中的控制器和/或操作以允许路由选择正确的路径:

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

您还可以为参数添加约束以区分路径,但在您的情况下,两个操作都具有相同的整数参数。

答案 2 :(得分:2)

您是否只是删除自定义路由,只需重复使用{id}参数(将{contactId}和{aboutId}转换为动作代码中的“id”)?

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();
  }

}