2009-08-19 9 views
31

¿Hay alguna forma de controlar la salida JSON de JsonResult con atributos, similar a cómo puede usar XmlElementAttribute y su bretheren para controlar el resultado de la serialización XML?ASP.NET MVC: control de la serialización de los nombres de propiedad con JsonResult

Por ejemplo, dada la siguiente clase:

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

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

me gustaría a continuación, obtener el siguiente resultado:

{ bar: '', oygevalt: '' } 

A diferencia:

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

Echa un vistazo a la recientemente lanzada Sierra: http://kohari.org/2009/08/10/siesta-painless-rest-via-asp-net-mvc/ –

+1

Esto parece prometedor (¡e interesante!), Pero yo estaba esperando algo ya procesado. ¿Hay alguna forma de que el serializador existente respete los atributos de DataContract? –

Respuesta

38

quería algo un poco más integrado en el marco de lo que sugirió Jarrett, así que esto es lo que hice:

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 método(), añadido a mi clase controlador base: Uso

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

muestra:

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: Si está buscando algo más eficaz que JsonDataContractSerializer, puede hacer lo mismo con JSON.NET. Aunque JSON.NET no parece utilizar DataMemberAttribute, sí tiene su propio JsonPropertyAttribute que se puede usar para lograr lo mismo.

+1

Lo mejor de MVC es lo fácil que es escribir este material. ¡Puede armar algunas soluciones realmente sofisticadas con bastante rapidez! –

+1

¡De hecho lo es! No pienso volver a mirar WebForms. –

+0

¡Muy buena solución! La clase 'JsonDataContractActionResult' se puede simplificar aún más si heredas de' JsonResult' en lugar de la base 'ActionResult' - ¡entonces solo tienes que anular el método' ExecuteResult'! –

1

Respuesta fácil: el DataContractJsonSerializer debe respetar los atributos [DataContract] y [DataMember] en el espacio de nombres System.Runtime.Serialization del BCL.

+15

Para ser claro para los que no lo saben, Nate está expresando el comportamiento deseado de MVC, no el comportamiento actual de MVC. A partir de MVC2, MVC usa JavaScriptSerializer, que no admite los atributos DataMember admitidos por el serializador WCF DataContract. Hoy se requiere un ActionResult personalizado para que MVC use los atributos DataContract/DataMember. – Todd

16

Aquí está mi implementación de la respuesta de Daniel Schaffer, con las mejoras sugeridas por Justin Rusbatch y Daniel incorporadas.

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: lo mejor que puedo decir es que el 'DataContractJsonSerializer' todavía no es compatible directamente en MVC 4, por lo que esta es una solución elegante. –

5

Sé que esto es una vieja pregunta, pero para aquellos que buscan cómo evitar las propiedades de ser serializado uso del ScriptIgnoreAttribute en el espacio de nombres System.Web.Script.Serialization. Lamentablemente todavía no se puede controlar el nombre de las propiedades serializadas, pero alguien puede encontrar esto útil.

public class MyClass { 

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

    public bool AnyProperty { get; set; } 
} 

salida será como resultado JSON lo siguiente:

{"AnyProperty ": false} 
+0

Puedo confirmar que esto funciona. Este espacio de nombres se encuentra en el ensamblado System.Web.Extensions. –

+0

Perfecto ... Tanx mucho, Funciona correctamente ... –

3

Esta es la solución a utilizar NewtonSoft JSON.Net (para un rendimiento) he encontrado parte de la solución here y el 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(); 
     } 
    } 

Así que en mi controlador, que puede hacer que

 return new JsonNetResult(result); 

En mi modelo, ahora puedo tener :

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

tenga en cuenta que ahora, usted tiene que fijar el JsonPropertyAttribute a cada propiedad que desea serializar.

+0

gracias un millón –

Cuestiones relacionadas