将AjaxOnlyAttribute和ChildActionOnlyAttribute组合到一个动作过滤器中

时间:2012-03-02 13:35:57

标签: c# asp.net-mvc asp.net-mvc-3 asp.net-ajax

我希望能够在控制器上标记一个动作,从ajax调用和RenderAction调用。问题是这两个属性都衍生或实现了不同的抽象。唯一的出路是下一个:

[AjaxOnly]
PartialViewResult GetViewAjax(int foo) { return GetView(foo); }
[ChildActionOnly]
PartialViewResult GetView(int foo) { ... }

但这根本不是很好。


我所说的AjaxOnly属性是:

public sealed class AjaxOnlyAttribute : ActionFilterAttribute
{
    #region Public members

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext == null)
            throw new ArgumentNullException("filterContext");
        if (filterContext.HttpContext.Request.Headers["X-Requested-With"] != "XMLHttpRequest")
            filterContext.Result = new HttpNotFoundResult();
    }

    #endregion
}

此方法取自MVC3期货。一个重要的评论为什么条件不是filterContext.HttpContext.Request.IsAjaxRequest()由开发团队做出并说明如下:

// Dev10 #939671 - If this attribute is going to say AJAX *only*, then we need to check the header
// specifically, as otherwise clients can modify the form or query string to contain the name/value
// pair we're looking for.

2 个答案:

答案 0 :(得分:16)

这没有任何意义。这两个属性是互斥的。如果操作标有[ChildActionOnly],则客户端永远不能使用HTTP请求(无论是同步还是异步)直接访问它。因此,如果您希望使用AJAX可以访问某个操作,则不应该使用[ChildActionOnly]属性来装饰它。

我不知道这个[AjaxOnly]属性是什么以及它来自哪里但是根据它的实现方式,您可能需要调整它以便允许子操作请求,如果它仅依赖于{{ 1}}方法。例如,如果它是这样的:

Request.IsAjaxRequest()

您可能想要像这样调整它:

public class AjaxOnlyAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (!filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.Result = new HttpNotFoundResult();
        }
    }
}

答案 1 :(得分:1)

受到Darin的答案和ChildActionOnlyAttribute的源代码的启发,这是我提出的解决方案,我认为它更好一点:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class AjaxOrChildAttribute : ActionMethodSelectorAttribute
{
    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        return controllerContext.IsChildAction || controllerContext.RequestContext.HttpContext.Request.IsAjaxRequest();
    }
}

这样,验证即使在尝试执行之前也会完成,如果您输入网址,则输入的错误与尝试任何无效网址完全相同。