Asp.net mvc 当使用多态性时,控制器如何选择正确的操作?

Asp.net mvc 当使用多态性时,控制器如何选择正确的操作?,asp.net-mvc,Asp.net Mvc,我刚刚意识到我已经用了很多年的东西不应该起作用!考虑以下行为的多态性: public ActionResult MyAction() { ... } [AcceptVerbs(HttpVerbs.Post)] public ActionResult MyAction(String input) { ... } 很明显,当我们使用GET时,只有前一个仍然是有效候选,因为属性过滤掉了后一个。因此,这是明确的,每个人都很高兴。但是,如果我们使用POST跳转到代码中会怎么样 乍一看,人们倾向于认为,

我刚刚意识到我已经用了很多年的东西不应该起作用!考虑以下行为的多态性:

public ActionResult MyAction() { ... }

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult MyAction(String input) { ... }
很明显,当我们使用GET时,只有前一个仍然是有效候选,因为属性过滤掉了后一个。因此,这是明确的,每个人都很高兴。但是,如果我们使用POST跳转到代码中会怎么样

乍一看,人们倾向于认为,由于第一种方法是一种更一般的操作,因此后者更合理,可以说,在这种特殊情况下用于涵盖特殊功能。但这是人类的逻辑。不过,我怀疑服务器是否有这样的理由

我在一个项目中查过路线图和其他文件,但据我所知,其中涉及到一些黑魔法

所以我的问题是:框架如何知道选择什么


接下来的一个问题是,MVC的版本是否有所不同。

我建议阅读Phil Haack的,它应该能回答您的问题。引用一些重要部分:

ActionSelectionAttribute 一旦我们确定了控制器类中与当前操作名称匹配的所有方法,我们需要通过查看应用于列表中的方法的ActionSelectionAttribute的所有实例来进一步缩减列表

此属性是属性的抽象基类,这些属性提供了对操作方法可以响应的请求的细粒度控制。此方法的API非常简单,只包含一个方法

然后再往下一点:

最后,我们应该在列表中留下一个方法,然后调用程序调用该方法。如果有多个方法可以处理当前请求,调用程序将抛出一个异常,指示问题所在。如果没有方法可以处理该请求,调用程序将调用控制器上的HandleUnknownAction

ASP.NET MVC框架包括此基本属性的一个实现,即AcceptVerbsAttribute


这篇文章接着解释了这个过程如何与AcceptVerbsAttribute一起工作,并展示了一个与您类似的示例。

我建议阅读Phil Haack的,它应该能回答您的问题。引用一些重要部分:

ActionSelectionAttribute 一旦我们确定了控制器类中与当前操作名称匹配的所有方法,我们需要通过查看应用于列表中的方法的ActionSelectionAttribute的所有实例来进一步缩减列表

此属性是属性的抽象基类,这些属性提供了对操作方法可以响应的请求的细粒度控制。此方法的API非常简单,只包含一个方法

然后再往下一点:

最后,我们应该在列表中留下一个方法,然后调用程序调用该方法。如果有多个方法可以处理当前请求,调用程序将抛出一个异常,指示问题所在。如果没有方法可以处理该请求,调用程序将调用控制器上的HandleUnknownAction

ASP.NET MVC框架包括此基本属性的一个实现,即AcceptVerbsAttribute


本文接着解释了这个过程如何与AcceptVerbsAttribute一起工作,并展示了一个与您类似的示例。

该框架确实会像您这样考虑:选择后一个操作是因为它被认为更具体。我并没有检查每一个版本,但我认为自从HttpPostAttribute引入以来,这种行为并没有改变

然而,随着时间的推移,我已经多次下载了ASP.NET MVC源代码,我可以看到实现确实有所改变。在某一点上,ActionMethodSelector的RunSelectionFilters方法中源代码的相关部分如下所示:

//如果匹配动作方法具有选择属性,请考虑更多。 //特定于没有选择属性的匹配操作方法 返回MatchesWithSelectionAttribute。计数>0 ? 与SelectionAttribute匹配 :不带可选属性的匹配; 不过,这不是当前的实现。在中,实现有点复杂,但行为是相同的,参见RunSelectionFilters中的注释。。。ActionMethodSelectorBase.cs的名称:

//具有有效选择属性的方法将覆盖所有其他方法。
该框架确实像您所做的那样进行了推理:选择后一个操作是因为它被认为更具体。我并没有检查每一个版本,但我认为自从HttpPostAttribute引入以来,这种行为并没有改变

然而,随着时间的推移,我已经多次下载了ASP.NET MVC源代码,我可以看到实现确实有所改变。有一次,ActionMethodSelector的RunSelectionFilters方法中的源代码的相关部分出现了错误 这样做:

//如果匹配动作方法具有选择属性,请考虑更多。 //特定于没有选择属性的匹配操作方法 返回MatchesWithSelectionAttribute。计数>0 ? 与SelectionAttribute匹配 :不带可选属性的匹配; 不过,这不是当前的实现。在中,实现有点复杂,但行为是相同的,参见RunSelectionFilters中的注释。。。ActionMethodSelectorBase.cs的名称:

//具有有效选择属性的方法将覆盖所有其他方法。
首先,谢谢你的链接。我读过你提到的那篇文章,虽然写得很好,但它并没有真正回答我的问题,可能是因为我错过了它。事实上,他提到,如果在筛选候选对象后留下了多个方法,那么会抛出一个异常,因为这些属性不真实。然后,他给出了一个关于两种变形方法的属性的例子,这是一种非常明确的方式,我主张,但它没有解决我关于感觉像是正确的选择无属性的情况的问题。我错过了什么?我现在明白你的意思了,但他是对的,如果剩下两个动作,它会抛出一个异常:System.Reflection.AmbiguousMatchException。在你发表评论后,我第二次读了这篇文章,你是对的,他没有回答你的问题。但是,标记有ActionMethodSelectorAttributes的操作将优先于任何未装饰的操作。该属性只是一个过滤器,因此未修饰的方法将同时接受GET和POST,但不会在使用ActionMethodSelectorAttributes修饰的方法之前被选中,该方法可以处理当前请求。@KonradViltersten事实上,不要相信我的话,你可以看到相关代码。+1啊,原来是这样的。那一个正好是我好奇的地方。MVC中有很多自动化的东西,人们在做一些异常聪明或愚蠢的事情之前是不会意识到这一点的——这两者之间的界线就是头发很好。在过去的几天里,我手头有了更多的时间,我开始尝试不同的方法,而不是遵循古老的、已被证实的方法——只是为了测试极限。谢谢@我同意你的看法。如果有什么不同的话,最困难的部分通常是找到所涉及的正确类型的名称。一旦你做到了这一点,其他一切都很容易理解。很高兴它能帮上忙。首先,谢谢你的链接。我读过你提到的那篇文章,虽然写得很好,但它并没有真正回答我的问题,可能是因为我错过了它。事实上,他提到,如果在筛选候选对象后留下了多个方法,那么会抛出一个异常,因为这些属性不真实。然后,他给出了一个关于两种变形方法的属性的例子,这是一种非常明确的方式,我主张,但它没有解决我关于感觉像是正确的选择无属性的情况的问题。我错过了什么?我现在明白你的意思了,但他是对的,如果剩下两个动作,它会抛出一个异常:System.Reflection.AmbiguousMatchException。在你发表评论后,我第二次读了这篇文章,你是对的,他没有回答你的问题。但是,标记有ActionMethodSelectorAttributes的操作将优先于任何未装饰的操作。该属性只是一个过滤器,因此未修饰的方法将同时接受GET和POST,但不会在使用ActionMethodSelectorAttributes修饰的方法之前被选中,该方法可以处理当前请求。@KonradViltersten事实上,不要相信我的话,你可以看到相关代码。+1啊,原来是这样的。那一个正好是我好奇的地方。MVC中有很多自动化的东西,人们在做一些异常聪明或愚蠢的事情之前是不会意识到这一点的——这两者之间的界线就是头发很好。在过去的几天里,我手头有了更多的时间,我开始尝试不同的方法,而不是遵循古老的、已被证实的方法——只是为了测试极限。谢谢@我同意你的看法。如果有什么不同的话,最困难的部分通常是找到所涉及的正确类型的名称。一旦你做到了这一点,其他一切都很容易理解。不管怎样,很高兴它起了作用。
public abstract class ActionSelectionAttribute : Attribute
{
  public abstract bool IsValidForRequest(ControllerContext controllerContext,
      MethodInfo methodInfo);
}