C#asp.net将具有长属性的对象传递给前端会改变它的值[重复]

Posted

技术标签:

【中文标题】C#asp.net将具有长属性的对象传递给前端会改变它的值[重复]【英文标题】:C# asp.net passing an object with a long property to front end changes it's value [duplicate] 【发布时间】:2021-05-27 00:56:03 【问题描述】:

我正在构建一个带有 react.js 前端(尽管我相当确定这与问题无关)和 asp.net 后端(针对 net5.0,不确定是否相关)的应用程序)。当我调用后端 API 时,我得到一个对象,其中部分包括它根据传入的数据生成的 ID,它是 C# 中的 long 类型(64 位 int)。我看到的行为是 C# 中的变量和从前端响应中读取的变量是不同的。它们似乎在大约 16-17 位数字后漂移。

这是预期的吗?有什么办法可以解决吗?

复制代码/我看到的图片:

C#

[HttpPost]
[Route("test")]
public object TestPassingLongInObject()

    /* actual logic omitted for brevity */

    var rv = new
    
        DataReadIn = new  /* omitted */ ,
        ValidationResult = new ValidationResult(),
        GeneratedID =  long.Parse($"922337203new Random().Next(int.MaxValue):0000000000") // close to long.MaxValue
    ;

    Console.WriteLine($"ID in C# controller method: rv.GeneratedID");

    return rv;

控制台输出:ID in C# controller method: 9223372030653055062

Chrome 开发工具:

当我尝试访问前端的 ID 时,我得到了以 000 而不是 062 结尾的错误 ID。

编辑 1:有人建议这是因为 javascriptNumber.MAX_SAFE_INTEGER 小于我传递的值。我不相信这是原因,但也许我错了,有人可以启发我。在 JS 方面,我使用BigInt,正是因为我传递的数字对于Number 来说太大了。问题是在我将结果解析为 JS 对象之前(除非 Chrome 自动执行此操作,导致问题中引用的图片)。

编辑 2:根据下面的答案,看起来 JS 可能在我将值解析为 BigInt 之前将其解析为数字,所以我仍然在丢失精度。更熟悉网络的人可以证实这一点吗?

【问题讨论】:

我认为这是Javascript或Json格式的限制,您可以使用字符串而不是long吗? long.Parse() 大约是最慢的方法。使用9223372030000000000 + rand.Next(int.MaxValue) 另外,重新使用 Random 实例(使其成为静态成员)。这不仅是一个弱性能优化,还可以确保您不会意外使用相同的种子。 @JoelCoehoorn 省略了实际逻辑。这实际上并不是生成 ID 的方式,只是说明问题的一种方式。真正的公式中没有使用 Random()。 @phuzi 我编辑了我的问题,说我在前端使用 BigInt,但也许 JS 仍在使用 Number?我对网络开发还不是很熟悉。 如果在您有机会使用 BigInt 之前将响应解析为 JS 对象,则该数字将已经转换为常规 JS 数字,精度将降低。您可以调试 AJAX 请求/响应来确认这一点。 【参考方案1】:

JavaScript 引擎(显然)无法创建这么大的数字。尝试打开您的控制台并输入以下内容:

var myLong = 9223372030653055062;

console.log(myLong);

您也可以检查9223372030653055 > Number.MAX_SAFE_INTEGER,作为您越界的指针。

【讨论】:

【参考方案2】:

JavaScript 将该值解释为 number,它是一个 64 位浮点数。如果您想保留该值,最好将其作为字符串传回。

示例 JS 演示问题:

var value = 9223372030653055062;
console.log(value);
console.log(typeof(value));

【讨论】:

有没有办法告诉 JS 使用 BigInt(我认为应该解决 Number 的问题)? 我很确定没有办法阻止浏览器这样做。【参考方案3】:

Javascript 中数字的最大大小为 2^53 - 1,即 9007199254740991。在 C# 中,long 为 2^64 - 1,更大。所以“9223372030653055062”作为 C# long 但不能作为 JavaScript 数字,因为它太大了。如果这个 ID 正在使用 long 的数据库中使用,我建议您将它作为字符串传递给 JavaScript。

【讨论】:

OP 的数字是 9223372030653055000 比您在 9007199254740991 处为 Number 声明的最大值大得多,使得 Number 的最大大小远大于 2^53-1【参考方案4】:

虽然原因是数字大于 JS 可以准确表示的数字,但您似乎已经被 Chrome 的 Dev Tools Preview 分心了。这只是一个“有用”的预览,不一定是事实。

开发工具预览显示了一个有用的响应视图。我假设 AJAX 响应是使用 application/json 的内容类型传输的,因此 Chrome 有助于将 JSON 解析为 JS 对象并让您预览响应。检查响应选项卡,这是您的 AJAX 代码实际接收的内容。

有可能在您有机会对该数字使用BigInt 之前解析JSON,从而限制精度。您还没有向我们展示您的 AJAX 代码,所以这是我的最佳猜测。

唯一的解决方案是将其序列化为字符串,然后添加手动步骤将字符串转换为BigInt

jsObject.generatedId = BigInt(jsObject.generatedId);

如果您将其用作 ID,那么您不妨将其作为字符串保存在客户端,因为您不太可能使用它来进行任何计算。

【讨论】:

以上是关于C#asp.net将具有长属性的对象传递给前端会改变它的值[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何从 jQuery ajax 调用将复杂对象传递给 ASP.NET WebApi GET?

如何将参数传递给 jQuery document.ready() 函数(ASP.NET MVC、C#)

我应该如何将多个参数传递给 ASP.Net Web API GET?

在 ASP.Net Core 项目中使用 ADO.Net 将 JSON 类型作为参数传递给 SQL Server 2016 存储过程

将 QObject 指针从 QML 对象传递给 C++

将数组作为命令行参数传递给 Asp.Net Core