2012-03-02 3 views
7

Я хочу, чтобы иметь возможность отмечать действие на контроллере, вызываемое как из вызовов ajax, так и через RenderAction. Проблема в том, что оба этих атрибута выводят или реализуют различные абстракции. Один из вариантов - следующий:Объединение AjaxOnlyAttribute и ChildActionOnlyAttribute в один фильтр действий

[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. 

ответ

16

Это не имеет никакого смысла. Эти 2 атрибута являются взаимоисключающими. Если действие помечено [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(); 
     } 
    } 
} 
+0

Почему? Предположим, что ваше действие повторно используется из разных мест как с помощью RenderAction(), так и с ajax-запросов. Предположим, что они повторно используются на разных страницах, так как smt рисует некоторую стандартную панель инструментов для многих мест и используется немного по-разному в разных контекстах –

+0

@Hohhi, поэтому вы хотите, чтобы ваше действие было доступно только через вызов AJAX или как действие Child ? –

+0

Точно, спасибо за ваше предложение, я бы обновил вопрос и рассказал, как далеко я за какое-то время заработал –

1

Вдохновленный на ответ Дарин и исходный код ChildActionOnlyAttribute «s, это решение я пришел с, который я думаю, что это чуть-чуть лучше:

[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 является точным сэм e, как попытку любого неверного URL-адреса.

Смежные вопросы