将AjaxOnlyAttribute和ChildActionOnlyAttribute组合为一个操作筛选器

本文关键字:一个 操作 筛选 AjaxOnlyAttribute ChildActionOnlyAttribute 组合 | 更新日期: 2023-09-27 18:26:31

我希望能够标记控制器上的操作,以便通过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.

将AjaxOnlyAttribute和ChildActionOnlyAttribute组合为一个操作筛选器

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

我不知道这个[AjaxOnly]属性是什么,它来自哪里,但根据它的实现方式,如果它只依赖于Request.IsAjaxRequest()方法,您可能需要对它进行调整,以便允许子操作请求。例如,如果它是这样的东西:

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

你可能想这样调整:

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

受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();
    }
}

这样,验证甚至在尝试执行之前就完成了,如果您键入url,则会出现与尝试任何无效url完全相同的错误。