【问题标题】:Change the json DateTime serialization in WCF 4.0 REST Service更改 WCF 4.0 REST 服务中的 json DateTime 序列化
【发布时间】:2014-11-11 16:42:35
【问题描述】:

我需要在 WCF REST 自托管服务中替换 JSON 的 DateTime 序列化。现在,我正在使用类似下面的代码来完成它,但这绝对不是要走的路,因为它需要操纵每个类。

[DataContract]
public class Test
{
    [IgnoreDataMember]
    public DateTime StartDate;

    [DataMember(Name = "StartDate")]
    public string StartDateStr
    {
        get { return DateUtil.DateToStr(StartDate); }
        set { StartDate = DateTime.Parse(value); }
    }
}

我的实用函数 DateUtil.DateToStr 完成所有格式化工作。

是否有任何简单的方法可以做到这一点,而不必触及我的类上具有 DataContract 属性的属性?理想情况下,不会有任何属性,而是在我的配置中添加几行代码,将序列化程序替换为我已覆盖 DateTime 序列化的序列化程序。

我发现的所有东西看起来我都必须更换大量的管道。

这篇文章似乎不适用,因为我使用的是 WebServiceHost 而不是 HttpServiceHost,它不是 4.5.1 框架的一部分。

JSON.NET Serializer for WCF REST Services

【问题讨论】:

    标签: json wcf rest


    【解决方案1】:

    默认情况下,WCF 使用 DataContractJsonSerializer 将数据序列化为 JSON。不幸的是,这个序列化程序的日期格式很难被人脑解析。

    "DateTime": "\/Date(1535481994306+0200)\/"
    

    要覆盖此行为,我们需要编写自定义 IDispatchMessageFormatter。该类将接收所有应返回给请求者的数据,并根据我们的需要进行更改。

    要实现端点中的操作,请添加自定义格式化程序 - ClientJsonDateFormatter

    ServiceHost host=new ServiceHost(typeof(CustomService));
    host.AddServiceEndpoint(typeof(ICustomContract), new WebHttpBinding(), Consts.WebHttpAddress);
    
    foreach (var endpoint in host.Description.Endpoints)
    {
        if (endpoint.Address.Uri.Scheme.StartsWith("http"))
        {
            foreach (var operation in endpoint.Contract.Operations)
            {
                operation.OperationBehaviors.Add(new ClientJsonDateFormatter());
            }
            endpoint.Behaviors.Add(new WebHttpBehavior());
         }
     }
    

    ClientJsonDateFormatter 是一个简单的类,它只应用格式化程序 ClientJsonDateFormatter

    public class ClientJsonDateFormatter : IOperationBehavior
    {
        public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) {  }
    
        public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { }
    
        public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
        {
            dispatchOperation.Formatter = new ResponseJsonFormatter(operationDescription);
        }
    
        public void Validate(OperationDescription operationDescription) { }
    }
    

    在格式化程序中,我们使用更改后的序列化器进行输入和序列化:

    public class ResponseJsonFormatter : IDispatchMessageFormatter
    {
        OperationDescription Operation;
        public ResponseJsonFormatter(OperationDescription operation)
        {
            this.Operation = operation;
        }
    
        public void DeserializeRequest(Message message, object[] parameters)
        {
        }
    
        public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
        {
            string json=Newtonsoft.Json.JsonConvert.SerializeObject(result);
            byte[] bytes = Encoding.UTF8.GetBytes(json);
            Message replyMessage = Message.CreateMessage(messageVersion, Operation.Messages[1].Action, new RawDataWriter(bytes));
            replyMessage.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Raw));
            return replyMessage;
        }
    }
    

    为了向客户端发送信息,我们需要数据写入器 - RawDataWriter。它的实现很简单:

    class RawDataWriter : BodyWriter
    {
        byte[] data;
        public RawDataWriter(byte[] data)
            : base(true)
        {
            this.data = data;
        }
    
        protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
        {
            writer.WriteStartElement("Binary");
            writer.WriteBase64(data, 0, data.Length);
            writer.WriteEndElement();
        }
    }
    

    应用所有代码会以更友好的格式返回日期:

    "DateTime":"2018-08-28T20:56:48.6411976+02:00"
    

    为了在实践中展示它,我在 github 分支 DateTimeFormatter 中创建了示例。

    请检查this 答案,因为您很可能也需要它。

    【讨论】:

      【解决方案2】:

      JSON 转换DateTime 存在限制,特别是根据您的情况。

      请看http://msdn.microsoft.com/en-us/library/bb412170(v=vs.110).aspx 并阅读Dates/Times and JSON部分

      为了解决这个问题,我只是将包括DateTime在内的所有调用的序列化类型从JSON更改为XML

      【讨论】:

      • 我查看了 WCF json 序列化程序的参考源,它有一个名为 DateTimeFormat 的属性,但我不知道如何更改它。我也在 MSDN 论坛上发过帖子,但似乎没有人知道如何访问它。您链接到的文章并没有说这是不可能的,也没有说有限制。它只是谈论默认使用的格式。
      • @bpeikes 有一个限制。我忘记了看到限制详细信息的确切链接,但是您尝试过 XML 吗?它适用于 XML。另请参阅 JSON 中的数据如何序列化,例如 /DATE(7002340200+3000)/
      • 我们已经有大量在客户端使用 json 的代码。我已经在服务器上使用了我的工作。所以我们可以继续使用它。我已经阅读了您发布的两篇文章。他们都没有提到 DataContractJsonSerializer 是 WCF 的一部分,它有一个名为 DateTimeFormat 的成员。下载 WCF 的参考源,你会看到它在那里。
      【解决方案3】:

      经过长时间的讨论,我已经找到了解决方案。 请使用以下代码解决序列化日期..

      [IgnoreDataMember]
      public DateTime? PerformanceDate { get; set; }
      
      [DataMember(EmitDefaultValue = false, Name = "PerformanceDate")]
      public string UpdateStartDateStr
      {
          get
          {
              if (this.PerformanceDate.HasValue)
                  return this.PerformanceDate.Value.ToUniversalTime().ToString("s", CultureInfo.InvariantCulture);
              else
                  return null;
          }
          set
          {
              // should implement this...
          }
      }
      

      【讨论】:

      • 您的解决方案正是我在问题中提出的。
      • 我的服务有 96 个日期时间。我应该坐下来做这个改变 96 次吗?如果我错过了一个或者我忘记在将来应用该模式怎么办。更集中的方式会更好。
      猜你喜欢
      • 2019-01-04
      • 1970-01-01
      • 2015-03-21
      • 1970-01-01
      • 2012-04-07
      • 1970-01-01
      • 2011-03-16
      • 2014-04-08
      • 1970-01-01
      相关资源
      最近更新 更多