【问题标题】:The current request for action {0} on controller type {1} is ambiguous当前对控制器类型 {1} 的操作 {0} 请求不明确
【发布时间】:2013-07-01 17:12:09
【问题描述】:

我有两个动作,我希望我的路线 /users/users/{id} 不同。但是它给我带来了错误。

是否有可能在不手动创建每个路由的情况下实现这种事情,我将拥有其他遵循类似模式的控制器,并且为所有这些控制器编写自定义路由通常看起来是多余的和坏主意。

错误

当前对控制器类型的操作“索引”请求 'UsersController' 在以下操作方法之间不明确: System.Web.Mvc.ActionResult Index() 类型 Api.Controllers.UsersController System.Web.Mvc.ActionResult Api.Controllers.UsersController 类型上的索引(Int32)

代码

public class UsersController : Controller
{
    public ActionResult Index()
    {
        return null;
    }

    public ActionResult Index(int id)
    {
        return null;
    }
}

【问题讨论】:

  • 当你指定 /users/{id} 时你有 id = UrlParameter.Optional 吗?
  • @AlexeyAza 我设置了默认路由。如果我添加另一条删除id = UrlParameter.Optional 的路线,它不会改变任何东西。
  • @AlexeyAza 他们建议使用单独的操作或在控制器内部检查 id 是否为空。它并没有真正回答我想要实现的目标。也许没有办法解决这个问题。但是他们以某种方式在 WebAPI 中做到了这一点..

标签: c# asp.net-mvc rest asp.net-mvc-4 routes


【解决方案1】:

你需要一个ActionMethodSelector

public class RequiresParameterAttribute : ActionMethodSelectorAttribute {

   readonly string parameterName;

   public RequiresParameterAttribute(string parameterName) {
      this.parameterName = parameterName;
   }

   public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
      return controllerContext.RouteData.Values[parameterName] != null;
   }
}

还有控制器:

public class UsersController : Controller
{
    public ActionResult Index()
    {
        return null;
    }

    [RequiresParameter("id")]
    public ActionResult Index(int id)
    {
        return null;
    }
}

我不确定以上是否可行,但应该会给你一个想法。

【讨论】:

  • 我把代码放在RouteConfig.cs中,效果很好。
【解决方案2】:

你也可以试试这样的:

public class UsersController : Controller
{   
    public ActionResult Index(int? id)
    {
        if(id == null) {
            // case A
        }
        else {
            // case B
        }
    }
}

【讨论】:

  • 这是一个比公认答案简单得多的解决方案。
【解决方案3】:

Max Toro 的回答很有用,尽管我需要指定更多参数。

我将选择器属性更改为:

public class RequiresParameterAttribute : ActionMethodSelectorAttribute
{

    readonly string[] parameterName;

    public RequiresParameterAttribute(string[] parameterName)
    {
        this.parameterName = parameterName;
    }

    public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
    {

        //somehow, in my version of MVC controllerContext.RouteData.Values was not returning querystring parameters at all...
        var queryString = controllerContext.RequestContext.HttpContext.Request.QueryString; 

        foreach (string param in parameterName)
        {
            if (queryString.GetValues(param) == null)
                return false;
        }

        return true;
    }
}

然后就可以这样使用了:

[RequiresParameter(new string[] { "id", "id2", "id3" })]
public ActionResult Index(int id, int id2, int id3)
{
    //....
}

【讨论】:

    【解决方案4】:

    将 [HttpGet] 放在第一个方法中!

    public class UsersController : Controller
    {
        [HttpGet] 
        public ActionResult Index()
        {
            return null;
        }
    
        public ActionResult Index(int id)
        {
            return null;
        }
    }
    

    【讨论】:

    • 当我这样做并尝试使用 GET 将 /Index 上的表单发布到 /Index 时,它永远不会遇到第二个“Index”操作,因为第一个正在捕获它。所以这并不适用于所有情况。
    【解决方案5】:

    我只是删除第一个不带参数的方法,并使整数在路由中既是可选的,又在控制器中成为可为空的 int。然后您可以根据单个操作方法中的整数为空来决定要做什么。

    您可以将动作定义为路由的一部分:

    /{action}/{id}
    

    并使action 为必需,id 为可选...这将允许基于 URL 映射操作。也可以指定{controller}

    【讨论】:

    • 这将是我最后的选择。这似乎是一个糟糕的控制器设计。
    • 您能详细说明您的其他类似路线吗?
    • /projects/projects/{id}
    • 它确实有帮助,但它改变了路由。我希望我的网址像休息一样。
    • 它们可能是静止的...您可以使用不同的方法来获取、POST、PUT 和 DELETE...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多