为什么 long 类型在 .NET Web API JSON 响应负载中的 16 位数字后四舍五入?
Why long types are rounded in .NET Web API JSON response payload after 16 digits?
我正在使用 web api 2,我巧合地意识到它会在响应模型中舍入 long
类型值,如果它长于 16 位数字。
(为了问题简化示例)假设我有一个 Web api 方法作为 "GetOrders" 其中 returns orderVm 模型列表定义如下:
public class OrderVm{
public int OrderID {get;set;}
public long? OrderNumber {get;set;}
}
发生的情况是,如果我的订单号值为
1234567890123459
没有问题 - 总共 16 位数字。
1234567890123499
没有问题 - 总共 16 位数字。
12345678901234599
这是有问题的。共 17 位数字。将其四舍五入为 12345678901234600
下面是我的简化示例API方法:
[HttpPost]
[Route("get-orders/")]
public IHttpActionResult GetOrders(PostedVm postedVm)
{
var orderDtoList = _orderManager.GetOrders(postedVm.Active); // I checked the value in orderDtoList and it is not rounded at this moment...
var orderVmList = MapDtoToVm(orderDtoList);
return Ok(orderVmList);// I thought maybe something happens during the property mapping (which is just using simple reflection) but I checked the value in orderVmList and it is not rounded at this moment...
}
尽管就在返回响应之前,我检查了这些值实际上没有四舍五入..但是不知何故在客户端,它是四舍五入的。我想也许浏览器做了一些魔法(出于某种原因),但我检查了邮递员和提琴手上的有效载荷,它显示响应有效载荷中的值是四舍五入的。
这听起来与网络 api 配置有关,但如果是这样,我如何将其设置为不修改数据?我也很好奇 "why it is happening after 16 digits?"
以防万一我在下面添加了我的 WebApiConfig class:
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
//GZip Compression
GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor()));
// Web API routes
config.MapHttpAttributeRoutes();
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
config.Routes.MapHttpRoute(
name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new {
id = RouteParameter.Optional
});
}
}
这很可能是因为数字表示为 IEEE 754(C# 中的 double
)。
由于二进制表示可能会四舍五入,因此 12345678901234599
和 12345678901234600
具有相同的二进制表示。
您也可以在 C# 中观察到此行为:
double x = 12345678901234599;
double y = 12345678901234600;
Console.WriteLine(x == y); // Prints true
https://dotnetfiddle.net/G0KOqZ
编辑:尽管我最初的回答是 JSON 标准没有指定数字限制,但问题是一样的。
This specification allows implementations to set limits on the range
and precision of numbers accepted. Since software that implements
IEEE 754 binary64 (double precision) numbers [IEEE754] is generally
available and widely used, good interoperability can be achieved by
implementations that expect no more precision or range than these
provide, in the sense that implementations will approximate JSON
numbers within the expected precision.
感谢 Guy Incognito 他向我指出了 JSON 的原始回复。在原始响应中,我的值没有四舍五入。但是 当我解析 JSON 时,这个数字对于 JavaScript 来说太大了,而且由于浮点数没有无限精度 ,我遇到了这个问题。我最终将我的数据类型更改为 string
,因为无论如何我都不对其进行任何算术运算。
再次感谢 Guy Incognito,这个 SO post 也很有帮助。
我正在使用 web api 2,我巧合地意识到它会在响应模型中舍入 long
类型值,如果它长于 16 位数字。
(为了问题简化示例)假设我有一个 Web api 方法作为 "GetOrders" 其中 returns orderVm 模型列表定义如下:
public class OrderVm{
public int OrderID {get;set;}
public long? OrderNumber {get;set;}
}
发生的情况是,如果我的订单号值为
1234567890123459
没有问题 - 总共 16 位数字。1234567890123499
没有问题 - 总共 16 位数字。12345678901234599
这是有问题的。共 17 位数字。将其四舍五入为12345678901234600
下面是我的简化示例API方法:
[HttpPost]
[Route("get-orders/")]
public IHttpActionResult GetOrders(PostedVm postedVm)
{
var orderDtoList = _orderManager.GetOrders(postedVm.Active); // I checked the value in orderDtoList and it is not rounded at this moment...
var orderVmList = MapDtoToVm(orderDtoList);
return Ok(orderVmList);// I thought maybe something happens during the property mapping (which is just using simple reflection) but I checked the value in orderVmList and it is not rounded at this moment...
}
尽管就在返回响应之前,我检查了这些值实际上没有四舍五入..但是不知何故在客户端,它是四舍五入的。我想也许浏览器做了一些魔法(出于某种原因),但我检查了邮递员和提琴手上的有效载荷,它显示响应有效载荷中的值是四舍五入的。
这听起来与网络 api 配置有关,但如果是这样,我如何将其设置为不修改数据?我也很好奇 "why it is happening after 16 digits?"
以防万一我在下面添加了我的 WebApiConfig class:
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
//GZip Compression
GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor()));
// Web API routes
config.MapHttpAttributeRoutes();
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
config.Routes.MapHttpRoute(
name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new {
id = RouteParameter.Optional
});
}
}
这很可能是因为数字表示为 IEEE 754(C# 中的 double
)。
由于二进制表示可能会四舍五入,因此 12345678901234599
和 12345678901234600
具有相同的二进制表示。
您也可以在 C# 中观察到此行为:
double x = 12345678901234599;
double y = 12345678901234600;
Console.WriteLine(x == y); // Prints true
https://dotnetfiddle.net/G0KOqZ
编辑:尽管我最初的回答是 JSON 标准没有指定数字限制,但问题是一样的。
This specification allows implementations to set limits on the range and precision of numbers accepted. Since software that implements IEEE 754 binary64 (double precision) numbers [IEEE754] is generally available and widely used, good interoperability can be achieved by implementations that expect no more precision or range than these provide, in the sense that implementations will approximate JSON numbers within the expected precision.
感谢 Guy Incognito 他向我指出了 JSON 的原始回复。在原始响应中,我的值没有四舍五入。但是 当我解析 JSON 时,这个数字对于 JavaScript 来说太大了,而且由于浮点数没有无限精度 ,我遇到了这个问题。我最终将我的数据类型更改为 string
,因为无论如何我都不对其进行任何算术运算。
再次感谢 Guy Incognito,这个 SO post 也很有帮助。