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

23

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

我有以下处理City实体的服务契约。由于设计原因,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)
    {
    }
}
很感谢。
Hossam。

那么对于传入请求做同样的处理怎么样?传入请求是json驼峰命名法,需要在C# PascalCase类中进行序列化处理。请参阅我的帖子:https://stackoverflow.com/questions/50884879/wcf-rest-incoming-camelcase-json-to-pascalcase-object - Code-Strings
3个回答

25

使用扩展编码器和序列化器(参见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://msdn.microsoft.com/en-us/library/ms732038.aspx),而不是Message,以返回任何数据,而无需通过Microsoft JSON序列化器进行额外的默认处理。对于WCF4,您可以使用CreateStreamResponse(参见http://msdn.microsoft.com/en-us/library/dd782273.aspx)代替CreateTextResponse。如果您将使用此技术生成响应,请不要忘记将流位置设置为0后写入流。


2
那如何处理反序列化传入的City对象? - Christopher Stott
1
@Christopher Stott:例如,请参阅http://msdn.microsoft.com/en-us/library/ms734675.aspx,从“Reading Messages”开始。 - Oleg
1
从那个链接来看,UpdateCity似乎必须接受一个Message参数才能使用JSON.NET进行反序列化。这是正确的吗?有没有其他方法可以解决这个问题? - Christopher Stott
1
我知道这很老,但解决了我的TimeSpan和DateTime格式问题。 - ramires.cabral
1
@ramires.cabral:这是个好消息!顺便说一下,使用JSON.NET(Newtonsoft.Json)可以在转换期间设置一些附加选项:JsonSerializerSettings作为JsonConvert.SerializeObject的第二/第三个参数以及Formatting.Indented。我个人最喜欢使用ContractResolvernew CamelCasePropertyNamesContractResolver()以及NullValueHandlingNullValueHandling.Ignore(参见此处)。 - Oleg
显示剩余2条评论

1

你有使用Json.NET库的特定原因吗?如果你想返回JSON,为什么不直接使用WebGet和WebInvoke属性中的ResponseFormat属性呢?

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

对于大多数情况来说,那应该是可以的。你正在运行哪个版本的WCF?为什么要返回Message类型而不是实际类型呢?


这是WCF4。在我的web.config中,我的<standardEndpoint>具有defaultOutgoingResponseFormat="Json",因此我不必装饰服务方法。按设计,我的所有实体都具有[IsReference=true],并且不能使用默认的DataContractSerializer进行序列化。因此,我必须使用另一个可以处理带有[IsReference=true]实体的序列化程序,例如Json.net。我返回Message类型,以免我的响应被json.net和DataContractSerializer两次序列化。如果我返回实际类型,我将得到无效的JSON,例如"{"City":"Cairo"}"。谢谢您的回复。 - Hossam
如果您不使用IsReference属性,那么这对您是有效的,但如果您由于其他原因而必须使用它,那么该怎么办? - Steve Michelotti
正确,IsReference是唯一的问题。许多帖子中都报告了DataContractJsonSerializer无法序列化标记为IsReference=true的实体。这就是为什么我正在寻找使用另一个序列化程序的原因。非常感谢 - Hossam
默认的JSON序列化程序缺乏嵌入和恢复类型信息、保留对象引用以及允许自引用循环的支持。JSON.NET通过包含$type、$id和$ref属性来很好地处理它们。 - Triynko
5
DataContractJsonSerializer 对 DateTime 的序列化也非常糟糕。 - Robert

-2

在服务行为中,在您的服务 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)]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接