问题
Javascript 的 number 类型存在精度限制,浏览器反序列化 JSON 时,无法完整保留 long
类型的精度。
在 JSON 序列化时将 long
转换为 string
进行传递就可以保留精度。在 ASP.NET Core 中,可以创建一个 自定义 JsonConverter
来达到这一目的。
实现 long
和 string
转换的 JsonConverter
创建一个类 LongToStringJsonConverter
,示例代码(来自:https://github.com/cnblogs/Architecture/blob/main/src/Cnblogs.Architecture.Ddd.Cqrs.AspNetCore/LongToStringConverter.cs)
cs
/// <summary>
/// JSON 序列化时,在 long 和 string 类型之间转换。
/// </summary>
public class LongToStringConverter : JsonConverter<long>
{
/// <inheritdoc />
public override long Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.String)
{
return reader.GetInt64();
}
var raw = reader.GetString();
if (string.IsNullOrWhiteSpace(raw))
{
throw new JsonException("string is empty");
}
var success = long.TryParse(raw, out var parsed);
if (success == false)
{
throw new JsonException("string value can't be converted to long");
}
return parsed;
}
/// <inheritdoc />
public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}
然后可以在应用代码里启用将刚刚写好的自定义 JsonConverter
,可以根据项目的不同需求,指定启用的范围。
仅对类中的某一字段启用:
cs
public class TestDto
{
[JsonConverter(typeof(LongToStringJsonConverter))]
public long Id { get; set; }
}
对整个 API 项目全局启用:
新的 Minimal API 项目
cs
// Program.cs
builder.Services.ConfigureHttpJsonOptions(options => options.SerializerOptions.Converters.Add(new LongToStringJsonConverter()));
传统的 MVC 项目
cs
builder.Services.AddControllers().AddJsonOptions(options => options.SerializerOptions.Converters.Add(new LongToStringJsonConverter()))
在前端,如果使用 Typescript 的话,需要将对应类型从 number
改为 string
以实现正确的类型推断。
typescript
interface TestDto {
// id: number;
id: string;
}