WebApi odata:序列化长为字符串

时间:2015-05-07 12:52:07

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

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

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

Web API odata不会:

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

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

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

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

3 个答案:

答案 0 :(得分:2)

最后,我得到了这个工作。 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", ...

答案 1 :(得分:0)

虽然我对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

答案 2 :(得分:0)

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

public class IEEE754CompatibleAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        var parameter = actionExecutedContext.Request.Headers.Accept
            .Select(h => h.Parameters.FirstOrDefault(p =>
                p.Name.Equals("IEEE754Compatible", StringComparison.OrdinalIgnoreCase) &&
                p.Value.Equals("true", StringComparison.OrdinalIgnoreCase)))
            .FirstOrDefault(p => p != null);

        if (parameter != null)
        {
            actionExecutedContext.Response.Content.Headers.ContentType.Parameters.Add(parameter);
        }
    }
}

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

使用此功能后,指定类似Accept: application/json; IEEE754Compatible=true之类的请求应该会给您一个响应,该响应会将其长整数值转换为字符串。