2012-03-02 12 views
7

Desidero poter contrassegnare un'azione sul controller da chiamare sia da chiamate ajax che tramite RenderAction. Il problema è che entrambi questi attributi derivano o implementano diverse astrazioni. Una via d'uscita è la seguente:Combinazione di AjaxOnlyAttribute e ChildActionOnlyAttribute in un filtro di azione

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

Ma questo non è affatto pulito.


L'AjaxOnly attributo di cui sto parlando è:

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 
} 

Questo metodo è tratto da futuri MVC3. Un commento importante per cui la condizione non filterContext.HttpContext.Request.IsAjaxRequest() è stata fatta dal team di dev e dice quanto segue:

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

risposta

16

Questo non ha alcun senso. Questi 2 attributi si escludono a vicenda. Se un'azione è contrassegnata con [ChildActionOnly], non può mai essere direttamente accessibile dal client utilizzando una richiesta HTTP (sia essa sincrona o asincrona). Quindi, se vuoi che un'azione sia sempre accessibile usando AJAX, non devi mai decorarla con l'attributo [ChildActionOnly].

Non so cosa sia questo attributo [AjaxOnly] e da dove proviene ma, a seconda di come è implementato, potrebbe essere necessario modificarlo per consentire le richieste di azioni figlio se si basa solo sul metodo Request.IsAjaxRequest(). Per esempio, se si tratta di qualcosa di simile:

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

si potrebbe desiderare di modificarlo in questo modo:

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

Perché? Supponiamo che la tua azione venga riutilizzata da diverse posizioni sia tramite RenderAction() che ajax. Supponiamo che questi vengano riutilizzati su pagine diverse come smth che disegnano alcuni strumenti standard per molti posti e sono usati in modi diversi in contesti diversi –

+0

@Hohhi, quindi vuoi che l'azione sia accessibile solo tramite una chiamata AJAX o come azione Child ? –

+0

Esattamente, grazie per il tuo suggerimento, vorrei aggiornare la domanda e dire fino a che punto arriva in un certo tempo –

1

Ispirato alla risposta di Darin e il codice sorgente s' ChildActionOnlyAttribute, questa è la soluzione sono venuto con, che penso che sia un pochino meglio:

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

in questo modo, la convalida è fatto prima ancora di tentare di eseguire e l'errore che si ottiene se si digita l'URL è l'esatto sam e uno come provare qualsiasi URL non valido.

Problemi correlati