2012-08-01 10 views
6

Estoy buscando convertir una api JSON existente de una implementación hacky MVC3 a la última MVC4 Web Api. La implementación de MVC3 usa JSON.NET para hacer toda la serialización, lo que hará que la actualización sea agradable y fluida.Personalización de la API web ASP Json serialización mediante la cual se invoca a Action

Estoy atascado en personalizar cómo se serializan los resultados de algunas acciones. Por ejemplo, quiero que algunas acciones devuelvan solo algunas propiedades de los objetos generados, mientras que otras pueden hacer una serialización bastante profunda. En mi implementación actual, una acción puede agregar un grupo de sobrescrituras de serialización configurando las configuraciones apropiadas en el HttpContext. Estos son recogidos más adelante para la serialización personalizada a través de una clase derivada de JsonResult. El uso principal de agregar personalizado JsonConverters es controlar y reducir el número de claves/valores que se serializan, y variar los parámetros para serializar según la acción (ciertas acciones deben devolver más parámetros de objeto que otras).

ejemplo condensada de un controlador y la clase que controla la serialización JSON en mi actual aplicación MVC3:

public class TestController : JsonController { 
    public JsonResult Persons() { 
     ControllerContext.HttpContext.Items[typeof(IEnumerable<JsonConverter>)] = new JsonConverter[] { 
      new InterfaceExtractorJsonConverter<IPersonForList>(), 
      new StringEnumConverter() 
     }; 

     ControllerContext.HttpContext.Items[typeof(IContractResolver)] = new SpecialCamelCasePropertyNamesContractResolver(); 
    } 
} 

public class JsonNetResult : JsonResult { 
    public override void ExecuteResult(ControllerContext context) { 
     var response = context.HttpContext.Response; 

     var additionalConverters = context.HttpContext.Items[typeof(IEnumerable<JsonConverter>)] as IEnumerable<JsonConverter> ?? Enumerable.Empty<JsonConverter>(); 

     var contractResolver = context.HttpContext.Items[typeof(IContractResolver)] as IContractResolver ?? new JsonContractResolver(); 

     var typeNameHandling = TypeNameHandling.None; 
     if (context.HttpContext.Items.Contains(typeof(TypeNameHandling))) 
      typeNameHandling = (TypeNameHandling)context.HttpContext.Items[typeof(TypeNameHandling)]; 

     response.Write(JsonConvert.SerializeObject(Data, Formatting.Indented, new JsonSerializerSettings { 
      ContractResolver = contractResolver, 
      ReferenceLoopHandling = ReferenceLoopHandling.Ignore, 
      Converters = additionalConverters, 
      TypeNameHandling = typeNameHandling 
     })); 
    } 
} 

En Api Web veo que puedo conseguir el formateador JSON de la configuración y alterar las serializaciones a nivel mundial .

var config = new HttpSelfHostConfiguration("http://localhost:8080"); 

var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().Single(); 

jsonFormatter.SerializerSettings.ContractResolver = new SpecialCamelCasePropertyNamesContractResolver(); 
jsonFormatter.SerializerSettings.Converters = new[] { new InterfaceExtractorJsonConverter<ITesting>() }; 

Sin embargo, yo estaba pensando en el control de la serialización de las acciones de forma individual (o por controlador) mediante la adición de algunos atributos para especificar qué JsonConverter's de usar. Por lo tanto, me gustaría que el serializador Json encuentre los atributos relevantes dados a la acción/controlador invocado y modifique la serialización en consecuencia. No estoy seguro de dónde y cómo hacer esto. ¿Debo heredar de JsonMediaTypeFormatter y hacer el trabajo allí de alguna manera? ¿Qué otras opciones tengo?

Respuesta

2

Nunca he visto a nadie querer controlar la serialización de esa manera. Pero para lograr su objetivo con la cantidad mínima de retrabajo, volvería toda esa información de su método directamente:

class JsonNetResponse { 
    public IContractResolver ContractResolver { get;set; } 
    // Other Json.Net bits 
    public object Value { get; set; } 
} 

me permitiría crear un formateador personalizado que puede manejar esos objetos:

class JsonNetFormatter : MediaTypeFormatter { 
    public override bool CanWriteType(Type t) { 
     return typeof(JsonNetResponse).IsAssignableFrom(t); 
    } 
    // TODO WriteToStreamAsync which is basically a copy of your original JsonNetResult 
} 
Cuestiones relacionadas