WebApi odata:序列化为字符串
WebApi odata: Serialize long as string
我正在从 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 header 元素。但这对生成的响应没有影响。我是不是忽略了什么?
另一种解决方案是在客户端 JSON.parse 期间将 64 位数字反序列化为字符串值。这可能吗?
虽然我对 ASP.net 了解不多,但我可以给你一个 rexeg,它可以用来在 JSON 中的大数字周围添加引号。这里我设置为任意16位以上的数字。
http://jsfiddle.net/yryk70qz/1/
value.replace(/:\s*(\d{16,})(\s*[,\}])/g, ':""');
无论长度如何,您都可以使用所有数字:
value.replace(/:\s*(\d+)(\s*[,\}])/g, ':""');
(受此问题启发:Convert all the integer value to string in JSON)
我终于让它工作了。 OdataLib 确实通过 IEEE754Compatible 参数支持这一点。它检查响应 Content-Type header 以查看参数是否存在。
问题是,header 值不会自动通过网络 api 框架传播到响应 header。你必须自己做。我构建了一个派生的 class 的 ODataController,它将 IEEE754Compatible 参数修补到响应的 Content-Type header 中,如下所示:
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 Header 中发送 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", ...
@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
的请求应该给你一个响应,它的长数值被转换成字符串。
我正在从 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 header 元素。但这对生成的响应没有影响。我是不是忽略了什么?
另一种解决方案是在客户端 JSON.parse 期间将 64 位数字反序列化为字符串值。这可能吗?
虽然我对 ASP.net 了解不多,但我可以给你一个 rexeg,它可以用来在 JSON 中的大数字周围添加引号。这里我设置为任意16位以上的数字。
http://jsfiddle.net/yryk70qz/1/
value.replace(/:\s*(\d{16,})(\s*[,\}])/g, ':""');
无论长度如何,您都可以使用所有数字:
value.replace(/:\s*(\d+)(\s*[,\}])/g, ':""');
(受此问题启发:Convert all the integer value to string in JSON)
我终于让它工作了。 OdataLib 确实通过 IEEE754Compatible 参数支持这一点。它检查响应 Content-Type header 以查看参数是否存在。
问题是,header 值不会自动通过网络 api 框架传播到响应 header。你必须自己做。我构建了一个派生的 class 的 ODataController,它将 IEEE754Compatible 参数修补到响应的 Content-Type header 中,如下所示:
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 Header 中发送 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", ...
@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
的请求应该给你一个响应,它的长数值被转换成字符串。