如何将 Json.Net 设置为 WCF REST 服务的默认序列化程序

Posted

技术标签:

【中文标题】如何将 Json.Net 设置为 WCF REST 服务的默认序列化程序【英文标题】:How to set Json.Net as the default serializer for WCF REST service 【发布时间】:2011-03-08 07:19:38 【问题描述】:

是否可以在序列化/反序列化实体时覆盖默认的 WCF DataContractSerializer 行为并改用 JSON.NET?

我有以下处理城市实体的服务合同。出于设计原因,City 实体具有 IsReference=true,因此默认的 DataContractSerializer 会引发错误。

对于“GET”方法,我可以使用 JsonConvert.DeserializeObject 来处理这种情况,但使用“PUT、POST、DELETE”方法时,DataContractSerializer 具有优先权,并且由于无法序列化 IsReference 实体而抱怨失败。

我找到了这个Post 来实现 IOperationBehavior 并提供我自己的序列化器,但我不知道如何将 Json.NET 与它集成。我相信应该有更直接的方法来解决这个问题。

我将不胜感激有关此方案的任何帮助或指导,或对其他方法的建议。

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

非常感谢

霍萨姆

【问题讨论】:

对传入的请求做同样的事情怎么样?传入的请求是 json camelCase 并且需要在 C# PascalCase 类中序列化?请在此处查看我的帖子:***.com/questions/50884879/… 【参考方案1】:

使用扩展编码器和序列化器(请参阅http://msdn.microsoft.com/en-us/library/ms733092.aspx)或其他扩展 WCF 的方法(如使用 DataContractSerializerOperationBehavior)非常有趣,但对于您的特殊问题,有更简单的解决方法。

如果您已经使用 Message 类型返回结果并使用 WCF4,您可以执行以下操作:

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);

如果出现错误(如HttpStatusCode.UnauthorizedHttpStatusCode.Conflict)或其他需要设置HTTP状态码的情况(如HttpStatusCode.Created),您可以继续使用WebOperationContext.Current.OutgoingResponse.StatusCode

作为替代方案,您还可以返回 Stream(请参阅 http://blogs.msdn.com/b/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-web.aspx 和 http://msdn.microsoft.com/en-us/library/ms732038.aspx)而不是 Message 以返回任何数据,而无需 Microsoft JSON 序列化程序进行额外的默认处理。对于 WCF4,您可以使用 CreateStreamResponse(参见 http://msdn.microsoft.com/en-us/library/dd782273.aspx)而不是 CreateTextResponse。如果您将使用此技术产生响应,请不要忘记在写入流后将流位置设置为 0。

【讨论】:

如何处理反序列化传入的 City 对象? @Christopher Stott:请参阅以“阅读消息”开头的 msdn.microsoft.com/en-us/library/ms734675.aspx。 从该链接看来,UpdateCity 必须采用 Message 参数才能使用 JSON.NET 进行反序列化。那是对的吗?有什么办法吗? 我知道它很旧,但解决了我的 TimeSpan 和 DateTime 格式问题。 @ramires.cabral:这是个好消息!顺便说一句,JSON.NET (Newtonsoft.Json) 的使用允许在转换过程中设置一些附加选项:JsonSerializerSettings 作为JsonConvert.SerializeObjectFormatting.Indented 的第二/第三个参数。我个人最喜欢将ContractResolvernew CamelCasePropertyNamesContractResolver()NullValueHandlingNullValueHandling.Ignore 一起使用(参见here)【参考方案2】:

您是否有某些原因要专门使用 Json.NET 库。如果要返回 JSON,为什么不直接使用 WebGet 和 WebInvoke 属性中的 ResponseFormat 属性?

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

在大多数情况下应该如此。您正在运行哪个版本的 WCF?您返回 Message 类型而不是实际类型的任何原因?

【讨论】:

这是 WCF4。在我的 web.config 中,我的 具有 defaultOutgoingResponseFormat="Json",因此我不必装饰服务方法。按照设计,我的所有实体都具有 [IsReference=true] 并且无法使用默认的 DataContractSerializer 进行序列化。所以我必须使用像 Json.net 这样的序列化器,它可以处理带有 [IsReference=true] 的实体。我返回 Message 类型是为了不让我的响应序列化两次,一次是由 json.net,然后是由 DataContractSerializer。如果我返回实际类型,我会得到无效的 json,例如 "\"City\":\"Cairo\"" 感谢您的回复。 因此,如果您不使用 IsReference 属性但出于其他原因您必须按设计使用它,这对您有用吗? 正确,IsReference 是唯一的问题。这在许多帖子中报告了 DataContractJsonSerializer 无法序列化标记为 IsReference=true 的实体。这就是为什么我希望使用另一个序列化器。非常感谢 默认的 JSON 序列化程序缺乏对嵌入和恢复类型信息、保留对象引用和允许自引用循环的任何支持。 JSON.NET 通过包含 $type、$id 和 $ref 属性很好地处理它们。 DataContractJsonSerializer 的 DateTime 序列化也很糟糕。【参考方案3】:

在服务行为的服务 Web 配置中定义它:

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

或在您的接口的操作合同中

[OperationContract]
[WebInvoke(Method = "GET", 
           UriTemplate = "/advertisements/app_id/access_token/genero/age", 
           ResponseFormat = WebMessageFormat.Json,
           RequestFormat = WebMessageFormat.Json, 
           BodyStyle = WebMessageBodyStyle.Wrapped)]

【讨论】:

以上是关于如何将 Json.Net 设置为 WCF REST 服务的默认序列化程序的主要内容,如果未能解决你的问题,请参考以下文章

WCF REST 服务的 JSON.NET 序列化程序

如何将弱类型 JSON 转换为 C# 可读对象

如何在 C# 中正确使用 WCF REST API 上的 Stream 将文件(图像/视频/等)上传到服务器?

如何同时使用 SOAP WCF 服务和 REST API

将 WCF SOAP 和 WCF REST 服务托管为 Azure 应用服务

将 JSON 发送到 WCF Rest 服务 - 对象始终为空