2009-08-19 9 views
31

Esiste un modo per controllare l'output JSON di JsonResult con attributi, in modo simile a come è possibile utilizzare XmlElementAttribute ei relativi bretheren per controllare l'output della serializzazione XML?ASP.NET MVC: controllo della serializzazione dei nomi delle proprietà con JsonResult

Ad esempio, data la seguente classe:

public class Foo 
{ 
    [SomeJsonSerializationAttribute("bar")] 
    public String Bar { get; set; } 

    [SomeJsonSerializationAttribute("oygevalt")] 
    public String Oygevalt { get; set; } 
} 

mi piacerebbe quindi ottenere il seguente risultato:

{ bar: '', oygevalt: '' } 

Al contrario:

{ Bar: '', Oygevalt: '' } 
+0

Scopri la nuova Sierra rilasciata: http://kohari.org/2009/08/10/siesta-painless-rest-via-asp-net-mvc/ –

+1

Questo sembra promettente (e interessante!), Ma io speravo in qualcosa già cotto. Un modo per ottenere il serializzatore esistente per rispettare gli attributi DataContract? –

risposta

38

volevo qualcosa di un po 'più cotto nel quadro di quello che Jarrett ha suggerito, quindi ecco cosa ho fatto:

JsonDataContractActionResult:

public class JsonDataContractActionResult : ActionResult 
{ 
    public JsonDataContractActionResult(Object data) 
    { 
     this.Data = data; 
    } 

    public Object Data { get; private set; } 

    public override void ExecuteResult(ControllerContext context) 
    { 
     var serializer = new DataContractJsonSerializer(this.Data.GetType()); 
     String output = String.Empty; 
     using (var ms = new MemoryStream()) 
     { 
      serializer.WriteObject(ms, this.Data); 
      output = Encoding.Default.GetString(ms.ToArray()); 
     } 
     context.HttpContext.Response.ContentType = "application/json"; 
     context.HttpContext.Response.Write(output); 
    } 
} 

JsonContract metodo(), aggiunto alla mia classe di controller di base:

public ActionResult JsonContract(Object data) 
    { 
     return new JsonDataContractActionResult(data); 
    } 

campione Uso:

public ActionResult Update(String id, [Bind(Exclude="Id")] Advertiser advertiser) 
    { 
     Int32 advertiserId; 
     if (Int32.TryParse(id, out advertiserId)) 
     { 
      // update 
     } 
     else 
     { 
      // insert 
     } 

     return JsonContract(advertiser); 
    } 

Nota: Se stai cercando qualcosa di più performante di JsonDataContractSerializer, puoi fare la stessa cosa usando JSON.NET. Sebbene JSON.NET non sembri utilizzare DataMemberAttribute, ha il proprio JsonPropertyAttribute che può essere utilizzato per realizzare la stessa cosa.

+1

La parte fantastica di MVC è la facilità con cui scrivere. Puoi mettere insieme alcune soluzioni davvero sofisticate abbastanza rapidamente! –

+1

In effetti lo è! Non ho intenzione di tornare indietro a WebForms. –

+0

Soluzione molto bella! La classe 'JsonDataContractActionResult' può essere ulteriormente semplificata se si eredita da' JsonResult' invece che dalla base 'ActionResult' - quindi è sufficiente sovrascrivere il metodo' ExecuteResult'! –

1

Risposta facile: lo DataContractJsonSerializer deve rispettare gli attributi [DataContract] e [DataMember] nello spazio dei nomi System.Runtime.Serialization del BCL.

+15

Per essere chiari a chi ignaro, Nate sta esprimendo il comportamento desiderato di MVC, non il comportamento effettivo di MVC oggi. A partire da MVC2, MVC utilizza JavaScriptSerializer, che non supporta gli attributi DataMember supportati dal serializzatore DataContract di WCF. Oggi è necessario un ActionResult personalizzato per far sì che MVC utilizzi gli attributi DataContract/DataMember. – Todd

16

Ecco la mia implementazione della risposta di Daniel Schaffer, con i miglioramenti suggeriti da Justin Rusbatch e Daniel incorporati.

using System; 
using System.Runtime.Serialization.Json; 
using System.Web.Mvc; 

public class JsonDataContractActionResult : JsonResult 
{ 
    public JsonDataContractActionResult(Object data) 
    { 
     this.Data = data; 
    } 

    public override void ExecuteResult(ControllerContext context) 
    { 
     var serializer = new DataContractJsonSerializer(this.Data.GetType()); 
     context.HttpContext.Response.ContentType = "application/json"; 
     serializer.WriteObject(context.HttpContext.Response.OutputStream, 
      this.Data); 
    } 
} 
+0

+1 - il meglio che posso dire, il 'DataContractJsonSerializer' non è ancora supportato direttamente in MVC 4, quindi questa è una soluzione elegante. –

5

So che questa è una vecchia questione, ma per coloro che cercano solo come evitare di oggetti di uso di essere serializzato il ScriptIgnoreAttribute nel System.Web.Script.Serialization namespace. Purtroppo ancora non è possibile controllare il nome delle proprietà serializzate ma qualcuno potrebbe trovare questo utile.

public class MyClass { 

    [ScriptIgnoreAttribute] 
    public bool PropertyNotSerialized { get; set; } 

    public bool AnyProperty { get; set; } 
} 

uscita Volontà come risultato JSON il seguente:

{"AnyProperty ": false} 
+0

Posso confermare che questo funziona. Questo spazio dei nomi si trova nell'assembly System.Web.Extensions. –

+0

Perfetto ... Tanx molto, funziona correttamente ... –

3

Questa è la soluzione di utilizzare NewtonSoft JSON.Net (per le prestazioni) ho trovato parte della soluzione here e su SO

public class JsonNetResult : ActionResult 
    { 
     public Encoding ContentEncoding { get; set; } 
     public string ContentType { get; set; } 
     public object Data { get; set; } 

     public JsonSerializerSettings SerializerSettings { get; set; } 
     public Formatting Formatting { get; set; } 

     public JsonNetResult(object data, Formatting formatting) 
      : this(data) 
     { 
      Formatting = formatting; 
     } 

     public JsonNetResult(object data):this() 
     { 
      Data = data; 
     } 

     public JsonNetResult() 
     { 
      Formatting = Formatting.None; 
      SerializerSettings = new JsonSerializerSettings(); 
     } 

     public override void ExecuteResult(ControllerContext context) 
     { 
      if (context == null) 
       throw new ArgumentNullException("context"); 
      var response = context.HttpContext.Response; 
      response.ContentType = !string.IsNullOrEmpty(ContentType) 
       ? ContentType 
       : "application/json"; 
      if (ContentEncoding != null) 
       response.ContentEncoding = ContentEncoding; 

      if (Data == null) return; 

      var writer = new JsonTextWriter(response.Output) { Formatting = Formatting }; 
      var serializer = JsonSerializer.Create(SerializerSettings); 
      serializer.Serialize(writer, Data); 
      writer.Flush(); 
     } 
    } 

Così che nel mio controller, posso farlo

 return new JsonNetResult(result); 

Nel mio modello, ora posso avere :

[JsonProperty(PropertyName = "n")] 
    public string Name { get; set; } 

Nota che ora, è necessario impostare la JsonPropertyAttribute per ogni proprietà che si desidera serializzare.

+0

grazie un milione –

Problemi correlati