2012-07-30 10 views
6

Sto implementando un livello REST in .NET MVC 3. Sto cercando un modo pulito per prendere l'intestazione Accept per determinare se dovrei restituire Json o Xml.Il modo più semplice per creare il modello Accetta l'intestazione in .NET MVC

Mi piacerebbe anche essere in grado di spoofare questa intestazione con un parametro GET per il debug (voglio che questo rimanga anche per prod).

Ecco come Attualmente sto rilevando questo:

if (Request.AcceptTypes.Contains("application/json") || Request.Url.Query.Contains("application/json")) 

Questo è l'unico posto nel mio codice di controllo che tocca direttamente l'oggetto Request. Vorrei un modo più pulito, più testabile per leggerlo. La mia soluzione ideale sarebbe un parametro sul controller.

Ho provato diverse parole chiave per vedere se il raccoglitore modello di default si riprendeva su di esso, ma nulla di ciò che ho provato funzionava.

Quindi qual è il modo più pulito per ottenere queste informazioni? Un modello di legatura personalizzato? Puoi fornire un esempio?

+0

Se non si è contrari a mvc4 webapi è possibile averlo gestito per te. Per non parlare del fatto che quando migrerai la tua app su mvc4 + in futuro, gestirai qualcosa che MVC già fa per te. Cerca la negoziazione del tipo di contenuto mvc4 per maggiori informazioni. –

+0

L'ho notato e ne sono molto entusiasta, ma sfortunatamente non posso consegnare questo progetto sotto un RC e da quello che posso dire non esiste una data di rilascio per 4. – Travis

+0

http://prideparrot.com/blog/archive/2012/3/returning_data_view_from_controller_action – VJAI

risposta

2

Un attributo del filtro azione sarebbe una soluzione buona e pulita.

C'è un buon tutorial qui: http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/understanding-action-filters-cs

+0

Grazie per la risposta, ma se ho capito bene, dovrò duplicare ogni azione, una per Xml e una per Json. Sembra un po 'eccessivo solo per l'incapsulamento e la testabilità. O mi sta sfuggendo qualcosa? – Travis

+1

Puoi registrarlo come filtro di azione globale e avere sia l'Xml che Json gestiti nell'unico filtro .. non è quello che cerchi? Dovrai comunque conservarlo nel ViewData/Bag che non è così "pulito", immagino .. –

2

Non vedo alternative migliori per un modello personalizzato legante. Pubblicherò la mia implementazione del raccoglitore qui nel caso in cui qualcun altro lo veda. L'uso di un raccoglitore modello consente all'intestazione Accept di essere fortemente vincolato a un input diretto sull'azione, consentendo il test diretto dei tipi restituiti e non costringe a eseguire artificialmente più azioni di quelle necessarie, né a generare il viewdata dinamico digitato /Borsa.

Ecco il modello Binder con un tipo enum supporto:

public enum RequestAcceptType 
{ 
    NotSpecified, 
    Json, 
    Xml 
} 

public class RequestAcceptTypeModelBinder : IModelBinder 
{ 
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     if (bindingContext == null) 
     { 
      throw new ArgumentNullException("bindingContext"); 
     } 

     RequestAcceptType acceptType = RequestAcceptType.NotSpecified; 

     // Try for Json 
     if (controllerContext.HttpContext.Request.AcceptTypes.Contains("application/json") || controllerContext.HttpContext.Request.Url.Query.Contains("application/json")) 
     { 
      acceptType = RequestAcceptType.Json; 
     } 

     // Default to Xml 
     if (acceptType == RequestAcceptType.NotSpecified) 
     { 
      acceptType = RequestAcceptType.Xml; 
     } 

     return acceptType; 
    } 
} 

Ecco il bit rilevante nel Global.asax nel metodo Application:

ModelBinders.Binders[typeof(RequestAcceptType)] = new RequestAcceptTypeModelBinder(); 

Poi, per usarlo nelle vostre azioni, solo fare un argomento (qualsiasi nome) con il tipo enum:

public ActionResult Index(RequestAcceptType acceptType) 

Se nessuno risponde con un Il metodo migliore in un paio di giorni, lo accetterò come risposta.

Problemi correlati