2012-03-02 12 views
7

Quiero poder marcar una acción en el controlador para que se llame tanto desde llamadas ajax como a través de RenderAction. El problema es que ambos atributos derivan o implementan diferentes abstracciones. Una salida es la siguiente:Combinación de AjaxOnlyAttribute y ChildActionOnlyAttribute en un filtro de acción

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

Pero esto no está del todo limpio.


El AjaxOnly atributo que estoy hablando es la siguiente: se toma

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 
} 

Este método de futuros MvC3. Un comentario importante por la que la condición no se filterContext.HttpContext.Request.IsAjaxRequest() fue hecho por el equipo de desarrollo y dice lo siguiente:

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

Respuesta

16

Esto no tiene ningún sentido. Esos 2 atributos son mutuamente excluyentes. Si una acción está marcada con [ChildActionOnly], el cliente nunca puede acceder directamente a ella mediante una solicitud HTTP (ya sea sincrónica o asincrónica). Por lo tanto, si desea que una acción sea accesible con AJAX, nunca debe decorarla con el atributo [ChildActionOnly].

No sé qué es este atributo [AjaxOnly] y de dónde viene, pero dependiendo de cómo se implemente, es posible que deba modificarlo para permitir las solicitudes de acción infantil si se basa únicamente en el método Request.IsAjaxRequest(). Por ejemplo si se trata de algo como esto:

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

es posible que desee ajustar de esta manera:

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

¿Por qué? Supongamos que su acción se vuelve a utilizar desde diferentes lugares a través de RenderAction() y las solicitudes ajax. Supongamos que se vuelven a usar en diferentes páginas como algo que se dibuja en un panel de herramientas estándar para muchos lugares y se usa ligeramente diferente en contextos diferentes –

+0

@Hohhi, por lo que desea que su acción sea accesible solo a través de una llamada AJAX o como acción infantil ? –

+0

Exactamente, gracias por su sugerencia, actualizaría la pregunta y le diría cuánto llegué en algún momento –

1

Inspirado en la respuesta de Darin y el código fuente ChildActionOnlyAttribute 's, esta es la solución que he llegado con, que creo que es un poco mejor:

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

de esta manera, la validación se realiza antes incluso de intentar ejecutar, y el error que se obtiene si se escribe en la URL es la exacta sam e uno como intentar cualquier URL inválida.

Cuestiones relacionadas