为啥 Asp.net MVC 不能区分具有不同参数的两个动作?

Posted

技术标签:

【中文标题】为啥 Asp.net MVC 不能区分具有不同参数的两个动作?【英文标题】: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 操作,否则将使用第二个。

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

【问题讨论】:

【参考方案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] 通常是有益的。

它也可以解决你的问题。

【讨论】:

不,这两种方法都是为了向用户提供注册表单。后者用于更专业的形式,而前者用于一般形式。 在这种情况下,我不明白你为什么要给他们取相同的名字。

以上是关于为啥 Asp.net MVC 不能区分具有不同参数的两个动作?的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET-MVC5 - 为啥 Bootstrap v4 主题不能正确显示组件?

具有捆绑和缩小功能的 ASP.NET MVC 4 应用程序,为啥在调试模式下启用缩小?

为啥 Asp.net MVC4 不能使用 SQL Server Session 状态存储的 cookieless

在 ASP.NET MVC 中,为啥我不能从“MyCustomView”继承而不指定完整的类型名称? [复制]

在 ASP.NET MVC 中强制区分大小写路由

将json发送到控制器时,ASP.NET mvc 4控制器参数始终为空,为啥?