将AjaxOnlyAttribute和ChildActionOnlyAttribute组合到一个动作filter中

我希望能够在控制器上标记一个动作,从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. 

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

这样,validation即使在尝试执行之前也会完成,如果您键入url,则获得的错误与尝试任何无效的url完全相同。