【问题标题】:WebApi odata: Serialize long as stringWebApi odata:序列化长为字符串
【发布时间】:2021-01-13 02:20:15
【问题描述】:

我正在从 WCF 数据服务迁移到 Web API odata v4。 WCF 数据服务确实对引号中的长值进行了序列化:

{
   "value":[{
     "ID":"4527895973896126465"
   },{
     "ID":"4527895973896126466"
   }]
}

Web API odata 没有:

{
   "value":[{
     "ID":4527895973896126465
   },{
     "ID":4527895973896126466
   }]
}

这意味着我在 JavaScript 中 JSON.parse 期间丢失了 64 位数字的精度,因为 JavaScript 数字只有 53 位。

WebApi 是否具有将长值作为字符串值处理的内置机制?我正在考虑 IEEE754Compatible 标头元素。但这对生成的响应没有影响。我忽略了什么吗?

另一种解决方案是在客户端的 JSON.parse 期间将 64 位数字反序列化为字符串值。这可能吗?

【问题讨论】:

    标签: javascript asp.net-web-api odata wcf-data-services


    【解决方案1】:

    最后我得到了这个工作。 OdataLib 确实通过 IEEE754Compatible 参数支持这一点。它检查响应 Content-Type 标头以查看参数是否存在。

    问题是,Web API 框架不会自动将标头值传播到响应标头。你必须自己做。我已经构建了一个 ODataController 派生类,将 IEEE754Compatible 参数修补到响应的 Content-Type 标头中,如下所示:

    public abstract class ODataControllerIEEE754Compatible : ODataController 
    {
        private void PatchResponse(HttpResponseMessage responseMessage)
        {
            if (responseMessage != null && responseMessage.Content != null)
            {
               if (this.Request.Content.Headers.GetValues("Content-Type").Any(
                   h => h.Contains("IEEE754Compatible=true")))
               {
                   responseMessage.Content.Headers.TryAddWithoutValidation(
                      "Content-Type", "IEEE754Compatible=true");
               }
           }
        }
    
        public override Task<HttpResponseMessage> ExecuteAsync(
           HttpControllerContext controllerContext, CancellationToken cancellationToken)
        {
                var response = base.ExecuteAsync(
                   controllerContext, cancellationToken);
                response.Wait(cancellationToken);
    
                PatchResponse(response.Result);
    
                return response;
        }
    }
    

    现在通过在 Content-Type 标头中发送 IEEE754Compatible=true 参数,我会收到所有序列化为 JSON 字符串的长值:

    GET http://localhost/some/url HTTP/1.1
    OData-Version: 4.0;
    Content-Type: application/json;odata.metadata=minimal;IEEE754Compatible=true;charset=utf-8
    Cache-Control: no-cache
    
    HTTP/1.1 200 OK
    Content-Type: application/json;odata.metadata=minimal;IEEE754Compatible=true
    Server: Microsoft-HTTPAPI/2.0
    OData-Version: 4.0
    
    {
      "@odata.context":"http://localhost/some/url","value":[
    {
      "ID":"4527895973896126465", ...
    

    【讨论】:

      【解决方案2】:

      虽然我对 ASP.net 了解不多,但我可以给你一个 rexeg,它可用于在 JSON 中的大数字周围添加引号。在这里,我将其设置为 16 位或更多位的任意数量。

      http://jsfiddle.net/yryk70qz/1/
      value.replace(/:\s*(\d{16,})(\s*[,\}])/g, ':"$1"$2');

      您可以通过以下方式处理所有数字,无论其长度如何:
      value.replace(/:\s*(\d+)(\s*[,\}])/g, ':"$1"$2');

      (受此问题启发:Convert all the integer value to string in JSON

      【讨论】:

      • 谢谢。我可以将其用作“最后的手段”,但我想知道在 JSON.parse 期间是否可以这样做(或类似的东西)(以获得更好的性能)。最好的办法是让我在服务器端使用 wcf 数据服务的旧行为。
      【解决方案3】:

      @Jeldrik 的回答有效,但这是一种更简洁的方法。

      public class IEEE754CompatibleAttribute : ActionFilterAttribute
      {
          public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
          {
              var parameter = actionExecutedContext.Request.Headers.Accept
                  .SelectMany(h => h.Parameters.Where(p =>
                      p.Name.Equals("IEEE754Compatible", StringComparison.OrdinalIgnoreCase) &&
                      p.Value.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase)))
                  .FirstOrDefault();
      
              if (parameter != null)
              {
                  actionExecutedContext.Response.Content?.Headers.ContentType.Parameters.Add(parameter);
              }
          }
      }
      

      将此[IEEE754Compatible] 属性放在您要开始尊重IEEE754Compatible=true 的任何OData 控制器上。或者,将new IEEE754CompatibleAttribute() 添加到GlobalFilterCollection 以使其自动适用于每个控制器。

      有了这个,指定 Accept: application/json; IEEE754Compatible=true 之类的请求应该会给你一个响应,将它的长数字值转换为字符串。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-18
        • 2014-01-06
        • 1970-01-01
        • 2019-04-08
        • 1970-01-01
        相关资源
        最近更新 更多