2010-06-25 20 views
18

¿Es posible anular el comportamiento predeterminado de WCF DataContractSerializer cuando Serialize/DeSerialize entidades y usar JSON.NET en su lugar?Cómo configurar Json.Net como el serializador predeterminado para el servicio WCF REST

Tengo el siguiente contrato de servicio para manejar la entidad de la ciudad. Por motivos de diseño, la entidad de la ciudad tiene IsReference = true y, por lo tanto, el DataContractSerializer predeterminado genera errores.

Para los métodos "GET" puedo manejar la situación con JsonConvert.DeserializeObject, pero con los métodos "PUT, POST, DELETE" DataContractSerializer tiene prioridad y falla al quejarse por las entidades IsReference no se pueden serializar.

He encontrado este Post para implementar IOperationBehavior y proporcionar mi propio serializador pero no sé cómo integrar Json.NET con esto. y creo que debería haber un enfoque más directo para esto.

Agradecería cualquier ayuda u orientación con respecto a este escenario, o consejos para otros enfoques.

[ServiceContract] 
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed) 
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] 
public class CityService 
{ 
    [Description("Get all Cities")] 
    [WebGet(UriTemplate = "")] 
    public Message Cities() 
    { 

    } 

    [Description("Allows the details of a single City to be updated.")] 
    [WebInvoke(UriTemplate = "{code}", Method = "PUT")] 
    public Message UpdateCity(string code, City city) 
    { 
    } 
} 

Muchas gracias

Hossam

Respuesta

19

El uso de encoders y serializadores extendidos (ver http://msdn.microsoft.com/en-us/library/ms733092.aspx) u otros métodos de extender WCF como el uso de DataContractSerializerOperationBehavior es muy interesante, pero para su problema especial hay formas de solución más fáciles.

Si ya utiliza Message tipo para devolver los resultados de un uso WCF4 se puede hacer algo como lo siguiente:

public Message UpdateCity(string code, City city) 
{ 
    MyResponseDataClass message = CreateMyResponse(); 
    // use JSON.NET to serialize the response data 
    string myResponseBody = JsonConvert.Serialize(message); 
    return WebOperationContext.Current.CreateTextResponse (myResponseBody, 
       "application/json; charset=utf-8", 
       Encoding.UTF8); 
} 

En caso de errores (como HttpStatusCode.Unauthorized o HttpStatusCode.Conflict) o en otras situaciones en las que es necesario establecer un código de estado HTTP (como HttpStatusCode.Created) puede continuar usando WebOperationContext.Current.OutgoingResponse.StatusCode.

Como alternativa también se puede devolver un Stream (ver http://blogs.msdn.com/b/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-web.aspx y http://msdn.microsoft.com/en-us/library/ms732038.aspx) en lugar de Message a devolver ningún dato sin un procesamiento adicional por defecto por Microsoft JSON serializador. En el caso de WCF4, puede usar CreateStreamResponse (consulte http://msdn.microsoft.com/en-us/library/dd782273.aspx) en lugar de CreateTextResponse. No olvides establecer la posición del flujo en 0 después de escribir en el flujo si usarás esta técnica para producir la respuesta.

+0

Oleg, muchas gracias, funciona como un encanto al devolver el tipo de Stream, detiene el serializador de Microsoft. Conozco DataContractSerializerOperationBehavior, pero me lleva a instalar mi propio serializador de XmlObjectSerializer, que no es una tarea fácil. Su propuesta es mucho más simple y directa, gracias una vez más. – Hossam

+0

¿Cómo maneja eso la deserialización del objeto City entrante? –

+1

@Christopher Stott: consulte, por ejemplo, http://msdn.microsoft.com/en-us/library/ms734675.aspx, comenzando con "Leer mensajes". – Oleg

1

¿Hay alguna razón por la que desea utilizar la biblioteca Json.NET específicamente. Si desea devolver JSON, ¿por qué no utilizar la propiedad ResponseFormat de los atributos WebGet y WebInvoke?

[WebGet(UriTemplate = "", ResponseFormat = WebMessageFormat.Json)] 

Eso debería para la mayoría de los casos. ¿Qué versión de WCF está ejecutando? ¿Alguna razón por la que está devolviendo un tipo de mensaje en lugar del tipo real?

+0

Es WCF4. En mi webconfig, mi tiene defaultOutgoingResponseFormat = "Json", así que no tengo que decorar los métodos de servicio. Por diseño, todas mis entidades tienen [IsReference = true] y no pueden serializarse con el DataContractSerializer predeterminado. Así que tengo que usar otro Serializador como Json.net que puede manejar Entidades con [IsReference = true]. Devuelvo el tipo de mensaje para no recibir mi respuesta serializada dos veces, una vez por json.net y luego por DataContractSerializer. Si devuelvo el tipo real, obtendría un json no válido como "{\" City \ ": \" Cairo \ "}" Gracias por su respuesta. – Hossam

+0

¿Esto funciona para usted si no usa el atributo IsReference pero tiene que usarlo por diseño por otra razón? –

+0

Correcto, IsReference es el único problema. Esto se informa en muchas publicaciones. DataContractJsonSerializer no puede serializar entidades marcadas con IsReference = true. Es por eso que estoy buscando usar otro Serializador. Muchas gracias – Hossam

0

definirlo en su servicio web.config en los comportamientos de servicios:

<endpointBehaviors> 
    <behavior name="restfulBehavior"> 
     <webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Wrapped" automaticFormatSelectionEnabled="False" /> 
     <!--<enableWebScript />--> 
    </behavior> 
</endpointBehaviors> 

o en su contrato de operación de su interfaz

Cuestiones relacionadas