【问题标题】:MVC3: Use of ActionMethodSelectorAttribute causes HttpPostAttribute to be ignoredMVC3:使用 ActionMethodSelectorAttribute 会导致 HttpPostAttribute 被忽略
【发布时间】:2012-01-06 18:53:56
【问题描述】:

以下属性用于限制对 ajax 请求的操作:

public class AjaxRequestAttribute : ActionMethodSelectorAttribute
{
    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        return controllerContext.HttpContext.Request.IsAjaxRequest();
    }
}

我定义了以下控制器操作方法:

[AjaxRequest]
public ActionResult Login()
{
     ...
}

[HttpPost, AjaxRequest]
public ActionResult Login(LoginModel model, string returnUrl)
{
    ...
}

ajax发帖时出现如下错误:

当前对控制器类型的“登录”操作请求 'AgentController' 在以下操作方法之间不明确: System.Web.Mvc.ActionResult Login() 类型 NappWebsiteMvc.Controllers.AgentController System.Web.Mvc.ActionResult 登录(NappWebsiteMvc.Models.Agent.LoginModel,System.String)类型 NappWebsiteMvc.Controllers.AgentController

似乎在使用附加属性时忽略了 HttpPost 属性。如果我从这两个方法中删除 AjaxRequest 属性,那么代码就可以工作。

正确的实现应该是什么?谢谢!

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3


    【解决方案1】:

    根据 Pawel 的要求,代码如下:

    public class AjaxGetAttribute : ActionMethodSelectorAttribute
    {
        public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
        {
            var isHttpGet = new AcceptVerbsAttribute(HttpVerbs.Get).IsValidForRequest(controllerContext, methodInfo);
            return isHttpGet && controllerContext.HttpContext.Request.IsAjaxRequest();
        }
    }
    
    public class AjaxPostAttribute : ActionMethodSelectorAttribute
    {
        public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
        {
            var isHttpPost = new AcceptVerbsAttribute(HttpVerbs.Post).IsValidForRequest(controllerContext, methodInfo);
            return isHttpPost && controllerContext.HttpContext.Request.IsAjaxRequest();
        }
    }
    

    【讨论】:

      【解决方案2】:

      相信你也可以在第一个action方法中包含HttpGet属性:

      [HttpGet, AjaxRequest]
      public ActionResult Login()
      {
           ...
      }
      
      [HttpPost, AjaxRequest]
      public ActionResult Login(LoginModel model, string returnUrl)
      {
          ...
      }
      

      似乎所有 ActionMethodSelector 属性都必须返回 true 才能使操作方法有效。进行此更改意味着第一种方法将不会用于 POST,即使它是 Ajax 请求。

      我的情况略有不同,但这个解决方案对我有用。

      【讨论】:

        【解决方案3】:

        这是因为HttpPost 还扩展了ActionMethodSelectorAttribute,并具有自己的IsValidForRequest 覆盖。您是否尝试过将您的属性分为AjaxRequestAttributeAjaxPostRequestAttribute

        public class AjaxPostRequestAttribute : HttpPostAttribute
        {
            public override bool IsValidForRequest(
                ControllerContext controllerContext, MethodInfo methodInfo)
            {
                var isHttpPost = base.IsValidForRequest(controllerContext, methodInfo);
                return isHttpPost 
                    && controllerContext.HttpContext.Request.IsAjaxRequest();
            }
        }
        

        然后你可以像这样装饰:

        [AjaxPostRequest]
        public ActionResult Login(LoginModel model, string returnUrl)
        {
            ...
        }
        

        更新

        对不起,我没有注意到 HttpPostAttribute 源上的 seal 关键字。

        【讨论】:

        • 感谢您的回复。那么,方法选择管道只会考虑它找到的第一个 ActionMethodSelectAttribute 吗?它会以这种方式表现似乎很奇怪。我认为匹配失败只会在属性返回 false 时发生,否则会处理剩余的属性。我找不到任何文档来支持这两种方法,但这是我对典型“管道”行为的期望。
        • 将属性分离为 AjaxRequestAttribute 和 AjaxPostRequestAttribute 确实可以解决问题。 HttpPostAttribute 和 HttpGetAttribute 是密封的,因此实现与您发布的有点不同。谢谢你的帮助。我只是对方法选择管道步骤的行为方式感到惊讶。
        猜你喜欢
        • 2011-03-28
        • 1970-01-01
        • 2016-08-27
        • 1970-01-01
        • 2012-04-02
        • 2015-03-27
        • 2013-03-24
        • 1970-01-01
        • 2013-09-06
        相关资源
        最近更新 更多