wcf rest serialization json.net

¿Cómo puedo devolver json desde mi servicio de descanso WCF(.NET 4), usando Json.Net, sin que sea una cadena, entre comillas?



rest serialization (2)

Finalmente descubrí una solución para esto. No es lo que hubiera preferido (que sería devolver el tipo de objeto específico, y de alguna forma instruir a WCF para que use un serializador Json.Net, en lugar del DataContractJsonSerializer), pero está funcionando muy bien, y es simple y claro.

Extendiendo mi ejemplo artificial usando esta nueva solución:

[WebGet(UriTemplate = "hello")] public void SayHello() { SimpleMessage message = new SimpleMessage() {Message = "Hello World"}; string json = JsonConvert.Serialize(message); HttpContext.Current.Response.ContentType = "application/json; charset=utf-8"; HttpContext.Current.Response.Write(json); }

Tenga en cuenta el tipo de devolución de void . No devolvemos nada, ya que se serializaría con DataContractJsonSerializer. En cambio, escribo directamente en la secuencia de salida de respuesta. Como el tipo de devolución es nulo, la interconexión de procesamiento no establece el tipo de contenido en el tipo predeterminado de "aplicación / json", por lo que lo configuro explícitamente.

Como esto utiliza HttpContext , supongo que solo funcionará si tiene [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] en su clase de servicio, ya que eso obligará a las solicitudes al servicio a pasar por la interconexión ASP.NET. Sin la compatibilidad con asp.net, HttpContext no estará disponible, ya que se supone que wcf hosting es independiente del host.

Usando este método, los resultados se ven perfectos en firebug para solicitudes GET. Corrija el tipo de contenido, la longitud correcta del contenido y el json sin formato, sin incluir comillas. Y obtengo la serialización que quiero con Json.Net. Lo mejor de ambos mundos.

No estoy 100% seguro de los obstáculos con los que podría tropezar en cuanto a la serialización, cuando mis métodos de servicio tienen tipos de objetos [DataContract] como parámetros de entrada. Supongo que el DataContractJsonSerializer se usará también para eso. Cruzaré ese puente cuando llegue a él ... si crea un problema. No ha sido hasta ahora, con mis DTO simples.

ACTUALIZAR Vea la respuesta de Oleg (la parte UPDATE2). Cambia el tipo de devolución del método de servicio de vacío a System.ServiceModel.Channels.Message , y en lugar de utilizar HttpContext.Current.Response.Write() , utiliza:

return WebOperationContext.Current.CreateTextResponse (json, "application/json; charset=utf-8", Encoding.UTF8);

Que de hecho es una mejor solución. Gracias Oleg.

ACTUALIZACIÓN 2 Hay otra forma de lograr esto. Cambie el tipo de devolución de su servicio de Message to Stream y devuelva esto:

WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8"; return new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json));

No he hecho ninguna prueba específica, pero es posible que esta sea una mejor opción para los métodos que podrían devolver grandes cantidades de datos. Sin embargo, no sé si eso importa para datos no binarios. De todos modos, un pensamiento.

ACTUALIZACIÓN 19/10/2010 Sé que hice esta pregunta hace un tiempo, pero las soluciones alternativas que se muestran en estas respuestas no son satisfactorias, y este sigue siendo un problema común para muchos. WCF simplemente no es flexible. Inicié mi propia biblioteca C # de código abierto para crear servicios REST sin WCF. Consulte restcake.net o rest.codeplex.com para obtener información sobre dicha biblioteca. FINALIZAR ACTUALIZACIÓN

ACTUALIZACIÓN 8/2/2012 ASP.NET Web API (anteriormente WCF Web API, el reemplazo de REST WCF) utiliza Json.NET de forma predeterminada END UPDATE

El DataContractJsonSerializer no puede manejar muchos escenarios que Json.Net maneja bien cuando está configurado correctamente (específicamente, ciclos).

Un método de servicio puede devolver un tipo de objeto específico (en este caso un DTO ), en cuyo caso se utilizará el DataContractJsonSerializer , o puedo hacer que el método devuelva una cadena, y hacer la serialización yo mismo con Json.Net. El problema es que cuando devuelvo una cadena json en lugar de un objeto, la json que se envía al cliente se envuelve entre comillas.

Usando DataContractJsonSerializer , devolviendo un tipo de objeto específico, la respuesta es:
{"Message":"Hello World"}

Usando Json.Net para devolver una cadena json, la respuesta es:
"{/"Message/":/"Hello World/"}"

No quiero tener que eval () o JSON.parse () el resultado en el cliente, que es lo que tendría que hacer si el json vuelve como una cadena, entre comillas. Me doy cuenta de que el comportamiento es correcto; simplemente no es lo que quiero / necesito. Necesito el JSON crudo; el comportamiento cuando el tipo de devolución del método de servicio es un objeto, no una cadena.

Entonces, ¿cómo puedo hacer que mi método devuelva un tipo de objeto, pero no use el DataContractJsonSerializer? ¿Cómo puedo decirle que use el serializador Json.Net en su lugar?

O, ¿hay alguna manera de escribir directamente en la secuencia de respuesta? ¿Así que puedo devolver el JSON crudo yo mismo? Sin las citas de embalaje?

Aquí está mi ejemplo ideado, para referencia:

[DataContract] public class SimpleMessage { [DataMember] public string Message { get; set; } } [ServiceContract] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class PersonService { // uses DataContractJsonSerializer // returns {"Message":"Hello World"} [WebGet(UriTemplate = "helloObject")] public SimpleMessage SayHelloObject() { return new SimpleMessage("Hello World"); } // uses Json.Net serialization, to return a json string // returns "{/"Message/":/"Hello World/"}" [WebGet(UriTemplate = "helloString")] public string SayHelloString() { SimpleMessage message = new SimpleMessage() { Message = "Hello World" }; string json = JsonConvert.Serialize(message); return json; } // I need a mix of the two. Return an object type, but use the Json.Net serializer. }


Me parece que usted usa no corrige DataContractJsonSerializer . Lo extraño es que no se define el atributo ResponseFormat = ResponseFormat.Json para el public SimpleMessage SayHelloObject() .

Además, si tiene {"Message":"Hello World"} en una cadena y lo muestra en el depurador, se mostrará como "{/"Message/":/"Hello World/"}" , exactamente como ve la string json = JsonConvert.Serialize(message); (Json.Net). Entonces me parece que tienes en ambos casos los mismos resultados.

Para verificar esto, use un software de cliente que lea los resultados. Vea algunos ejemplos

JQuery ajax llamada a httpget webmethod (c #) no funciona

¿Puedo devolver JSON desde un servicio web .asmx si el ContentType no es JSON?

¿Cómo construyo un objeto JSON para enviar a un WebService de AJAX?

ACTUALIZADO : en tu código defines el método SayHelloString() . Su resultado es una cadena. Si llama al método, esta cadena será una vez más JSON serializada. La serialización JSON de la cadena {"Message":"Hello World"} es una cadena entre comillas (ver http://www.json.org/ para no un objeto, sino una cadena) o exactamente una cadena "{/"Message/":/"Hello World/"}" . Entonces, todo es correcto con ambos métodos de su servicio web.

ACTUALIZADO 2 : Me alegro de que mi sugerencia de la parte de "Actualización" de mi respuesta te ayudó a cambiar la doble serialización de JSON.

Sin embargo, le recomendaría que cambie un poco la solución para mantenerse en el concepto de WCF.

Si desea implementar una codificación personalizada de la respuesta web en WCF (consulte http://msdn.microsoft.com/en-us/library/ms734675.aspx ), su método WCF debería devolver el Message lugar de void :

[WebGet(UriTemplate = "hello")] public Message SayHello() { SimpleMessage message = new SimpleMessage() {Message = "Hello World"}; string myResponseBody = JsonConvert.Serialize(message); return WebOperationContext.Current.CreateTextResponse (myResponseBody, "application/json; charset=utf-8", Encoding.UTF8); }

Puede causar el uso de otro formateador de mensajes: por ejemplo CreateStreamResponse (u otro ver http://msdn.microsoft.com/en-us/library/system.servicemodel.web.weboperationcontext_methods(v=VS.100).aspx ) en lugar de CreateTextResponse Si desea establecer algunos encabezados HTTP adicionales o un código de estado Http (por ejemplo, en caso de algún error) puede hacerlo de esta manera:

OutgoingWebResponseContext ctx = WebOperationContext.Current.OutgoingResponse; ctx.StatusCode = HttpStatusCode.BadRequest;

Al final quiero repetir mi pregunta de un comentario: ¿podría explicar por qué quiere usar Json.Net lugar de DataContractJsonSerializer ? ¿Es la mejora del rendimiento? ¿Necesita implementar la serialización de algunos tipos de datos como DateTime de otra manera como lo hace DataContractJsonSerializer ? ¿O la razón principal de su elección de Json.Net es alguna otra?