【问题标题】:Why can't Asp.net MVC distinguish between two actions when they have different parameters?为什么 Asp.net MVC 不能区分具有不同参数的两个动作?
【发布时间】:2011-09-22 16:55:26
【问题描述】:

我试图在我的 Asp.net MVC 应用程序中使用两种不同的帐户注册方法,一种供一般用户注册,另一种供使用特定注册令牌注册的用户使用。因此,我的AccountController 中有以下方法签名:

public virtual ActionResult Register () {...}

public virtual ActionResult Register (Guid registrationToken) {...}

但是,当我转到 http://localhost/Account/Register 时,我得到一个异常,即当前请求在这两个操作之间不明确。我的印象是,如果没有传入registrationToken GET 参数,它将使用无参数Register 操作,否则将使用第二个。

这需要特殊的路由配置吗?

【问题讨论】:

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


    【解决方案1】:

    拥有一个可以为空的参数的方法会更容易吗?这也将自动解决您的问题,因为它不再模棱两可了:

    public virtual ActionResult Register (Guid? registrationToken)
    {
        if(registrationToken.HasValue)
        {
             // this is specific user
        }         
        else
        {
             // this is general user
        }
    }
    

    【讨论】:

    • 是的,这是一个解决方案,但我希望有一个由 MVC 自动化的解决方案。我只是认为 MVC 可以通过参数区分动作。
    • @KallDrexx - 问题是,它不区分“无参数”和“参数为空”。此外,它不会区分“参数a 已设置且参数b 为空”和“参数a 已设置且没有参数b”。尽管对于简单的情况看起来很明显,但对于更复杂的情况,这并不容易实现。这将是一个非常复杂且容易出错的决策框架。
    • 我想这样做,或者更改我的第二个操作方法的名称是最好的选择
    • 它似乎没有区别,句号。我同意在这种情况下很难区分,但即使参数完全不同,比如一个整数和另一个自定义对象列表,asp.net mvc3 仍然会引发模棱两可的异常。对于需要它的情况(例如, Save(Item item) vs Save(IEnumerable items) ),archil 给出了如何更彻底地处理这个问题的基本原因和答案
    【解决方案2】:

    mvc 控制器的默认基类,Controller 使用ActionInvoker 选择要调用的操作。首先,动作被选中,默认情况下来自 RouteData["action"] 值,然后对所选动作的参数进行所有模型绑定和验证。这就是为什么当调用者看到两个具有相同名称和相同选择属性的操作时,它会触发错误,因为它无法区分两者。

    但是有管理动作选择逻辑的内置方法,即使用从ActionMethodSelector class 派生的属性。首先,您创建从它派生的类,其中包含用于调用操作的逻辑。你的情况

    它将使用无参数 如果没有,请注册操作 registrationToken GET 参数传递 in,否则将使用第二个。

     public class RegistrationActionTokenAttribute : ActionMethodSelectorAttribute
        {
            public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
            {
                if (controllerContext.HttpContext.Request.QueryString.AllKeys.Contains("registrationToken"))
                {
                    return true;
                }
                return false;
            }
        }
    

    如果查询字符串包含参数“registrationToken”,我实现了第二个操作应标记为有效以供选择的演示逻辑。剩下的就是用这个属性装饰你的第二个方法

    [RegistrationActionToken]    
    public virtual ActionResult Register (Guid registrationToken) {...}
    

    错误消失了。此外,控制器现在根据查询字符串参数选择正确的操作

    【讨论】:

    • 理论上我喜欢这个解决方案,我不知道你能做到这一点,但我担心这会成为维护的噩梦。如果有人更改了registrationToken 的名称并且不修改属性,则会出现可能不容易进行单元测试的错误。
    • 这是控制动作选择的内置方式。通常,您可以使用属性构造函数传递参数名称,以使属性更明显地依赖于动作的参数
    • 最好将其设置为通过属性参数接受查询字符串。
    【解决方案3】:

    第二种方法需要 Post 吗?在任何用于接受表单提交的方法上方添加 [HttpPost] 通常是有益的。

    它也可以解决你的问题。

    【讨论】:

    • 不,这两种方法都是为了向用户提供注册表单。后者用于更专业的形式,而前者用于一般形式。
    • 在这种情况下,我不明白你为什么要给他们取相同的名字。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-04
    • 2014-04-07
    相关资源
    最近更新 更多