2010-06-25 3 views
18

Est-il possible de remplacer le comportement WCF DataContractSerializer par défaut lors de la sérialisation/DeSerialize entités et utiliser JSON.NET à la place?Comment définir Json.Net comme sérialiseur par défaut pour le service REST WCF

J'ai le contrat de service suivant pour gérer l'entité City. Pour des raisons de conception, l'entité City a IsReference = true et, par conséquent, DataContractSerializer par défaut génère des erreurs. Pour les méthodes "GET" je peux gérer la situation avec JsonConvert.DeserializeObject, mais avec les méthodes "PUT, POST, DELETE" DataContractSerializer a priorité et échoue à se plaindre pour les entités IsReference ne peut pas être sérialisé.

J'ai trouvé ce Post pour implémenter IOperationBehavior et fournir mon propre Serializer mais je ne sais pas comment intégrer Json.NET avec ceci. et je crois qu'il devrait y avoir une approche plus directe pour cela.

J'apprécierais n'importe quelle aide ou conseil concernant ce scénario, ou conseil à d'autres approches.

[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) 
    { 
    } 
} 

Un grand merci

Hossam

Répondre

19

L'utilisation de codeurs extensibles et sérialiseurs (voir http://msdn.microsoft.com/en-us/library/ms733092.aspx) ou d'autres méthodes d'extension de l'utilisation de WCF comme DataContractSerializerOperationBehavior est très intéressante, mais pour votre problème particulier, il existe des solutions plus simples.

Si vous utilisez déjà le type Message pour retourner les résultats d'une utilisation WCF4 vous pouvez faire quelque chose comme ce qui suit:

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 cas d'erreurs (comme HttpStatusCode.Unauthorized ou HttpStatusCode.Conflict) ou dans d'autres situations où vous devez définir un code d'état HTTP (comme HttpStatusCode.Created), vous pouvez continuer à utiliser WebOperationContext.Current.OutgoingResponse.StatusCode.

Comme alternative, vous pouvez également retourner un Stream (voir http://blogs.msdn.com/b/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-web.aspx et http://msdn.microsoft.com/en-us/library/ms732038.aspx) au lieu de Message pour retourner des données sans traitement par défaut supplémentaire par Microsoft sérialiseur JSON. Dans le cas de WCF4, vous pouvez utiliser CreateStreamResponse (voir http://msdn.microsoft.com/en-us/library/dd782273.aspx) au lieu de CreateTextResponse. N'oubliez pas de mettre la position du flux à 0 après avoir écrit dans le flux si vous allez utiliser cette technique pour produire la réponse.

+0

Oleg, merci beaucoup, ça fonctionne comme un charme en retournant le type Stream, il arrête le sérialiseur Microsft. Je connais DataContractSerializerOperationBehavior, mais il me faut hériter de mon propre sérialiseur de XmlObjectSerializer, ce qui n'est pas une tâche facile. Votre proposition est beaucoup plus simple et directe, merci encore une fois. – Hossam

+0

Comment cela gère-t-il la désérialisation de l'objet City entrant? –

+1

@Christopher Stott: Voir par exemple http://msdn.microsoft.com/en-us/library/ms734675.aspx en commençant par "Reading Messages". – Oleg

1

Y at-il une raison pour laquelle vous souhaitez utiliser spécifiquement la bibliothèque Json.NET. Si vous voulez retourner JSON, pourquoi ne pas simplement utiliser la propriété ResponseFormat des attributs WebGet et WebInvoke?

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

Cela devrait dans la plupart des cas. Quelle version de WCF utilisez-vous? Quelle est la raison pour laquelle vous renvoyez un type de message plutôt que le type réel?

+0

Il est WCF4. Dans mon web.config, mon a defaultOutgoingResponseFormat = "Json", donc je n'ai pas besoin de décorer les méthodes de service. Par conception, toutes mes entités ont [IsReference = true] et ne peuvent pas être sérialisées avec DataContractSerializer par défaut. Je dois donc utiliser un Serializer comme Json.net qui peut gérer les entités avec [IsReference = true]. Je renvoie le type de message pour ne pas obtenir ma réponse serialzed deux fois, une fois par json.net, puis par DataContractSerializer. Si je retournais le type d'actuall j'obtiendrais json invalide comme "{\" City \ ": \" Cairo \ "}" Merci pour votre réponse. – Hossam

+0

Donc, cela fonctionne pour vous si vous n'utilisez pas l'attribut IsReference, mais vous devez l'utiliser par conception pour une autre raison? –

+0

Correct, IsReference est le seul problème. Cela est signalé dans plusieurs messages DataContractJsonSerializer ne peut pas sérialiser les entités marquées avec IsReference = true. C'est pourquoi je cherche à utiliser un autre Serializer. Nombreux remerciements – Hossam

0

Define dans votre config web de service sur les comportements de service:

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

ou dans votre contrat d'exploitation de votre interface

Questions connexes