.NET Core 内置的 System.Text.Json 使用注意(MVC模型绑定后台获取不到解决方式)
System.Text.Json 是 .NET Core 3.0 新引入的高性能 json 解析、序列化、反序列化类库,武功高强,但毕竟初入江湖,炉火还没纯青,使用时需要注意,以下是我们在实现使用中遇到的一下问题。
我这里遇到的是Json字符串的类型值与模型定义的类型不一致,后台无法获取到参数问题:
解决方式:ASP.NET Core 中的模型绑定——使用输入格式化程序自定义模型绑定
//注册输入格式化程序自定义模型绑定
services.AddMvc(options =>
{
// options.InputFormatters.Insert(0,new
//RawRequestBodyFormatter());
}).AddJsonOptions(options =>
{
optionsJsonConverRload.AddConverters(options);
});
///核心代码
public class optionsJsonConverRload
{
public static void AddConverters(Microsoft.AspNetCore.Mvc.JsonOptions configure)
{
//添加支持string转int的操作
configure.JsonSerializerOptions.Converters.Add(new IntToStringConverter());
configure.JsonSerializerOptions.Converters.Add(new StringToStringConverter());
}
}
public class IntToStringConverter : JsonConverter<Int32>
{
public override Int32 Read(ref System.Text.Json.Utf8JsonReader reader, Type type, System.Text.Json.JsonSerializerOptions options)
{
if (reader.TokenType == System.Text.Json.JsonTokenType.String)
{
ReadOnlySpan<byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
if (System.Buffers.Text.Utf8Parser.TryParse(span, out Int32 number, out int bytesConsumed) && span.Length == bytesConsumed)
return number;
if (Int32.TryParse(reader.GetString(), out number))
return number;
}
return reader.GetInt32();
}
public override void Write(Utf8JsonWriter writer, Int32 value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}
public class StringToStringConverter : JsonConverter<String>
{
public override String Read(ref System.Text.Json.Utf8JsonReader reader, Type type, System.Text.Json.JsonSerializerOptions options)
{
if (reader.TokenType == System.Text.Json.JsonTokenType.String)
{
return reader.GetString();
}
else if(reader.TokenType == System.Text.Json.JsonTokenType.Number)
{
ReadOnlySpan<byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
if (System.Buffers.Text.Utf8Parser.TryParse(span, out Int32 number, out int bytesConsumed) && span.Length == bytesConsumed)
return number.ToString();
if (Int32.TryParse(reader.GetString(), out number))
return number.ToString();
}
return null;
//return reader.GetInt32();
}
public override void Write(Utf8JsonWriter writer, String value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}
参考:使用输入格式化程序自定义模型绑定(https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/model-binding?view=aspnetcore-3.1)
如何在 .NET 中编写用于 JSON 序列化(封送)的自定义转换器(https://docs.microsoft.com/zh-cn/dotnet/standard/serialization/system-text-json-converters-how-to)、
System.Text.Json: (De)serialization support for quoted numbers (https://github.com/dotnet/runtime/issues/30255)
问题延伸:其他人员遇到的坑及解决方式(2问题,可行我也到过)
1)默认设置下中文会被编码
序列化时中文会被编码,详见博问 .NET Core 3.0 中使用 System.Text.Json 序列化中文时的编码问题 。
解决方法:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
});
}
2)不能序列化公有字段(成员变量),只能序列化公有属性。
比如
public class FollowBloggerRequest
{
public Guid blogUserGuid;
}
要改为
public class FollowBloggerRequest
{
public Guid blogUserGuid { get; set; }
}
3)全是数字的字符串不能隐式反序列化为 int 类型
比如 { “postId”: “12345” } 不能反序列化为 int PostId ,github 上的相关 issue : System.Text.Json: Deserialization support for quoted numbers( https://github.com/dotnet/runtime/issues/30255 )
4)对于枚举类型属性值(非数字型)的序列化,需要加 [JsonStringEnumConverter] 特性
比如
[JsonConverter(typeof(JsonStringEnumConverter))]
public SiteCategoryType CategoryType { get; set; }
Json.NET 对应的是 StringEnumConverter
5)反序列化 Guid 的问题
详见博问:https://q.cnblogs.com/q/120383/
注:对应类型转换问题,可以通过实现自定义 JsonConverter 解决,参考 corefx#36639 (comment)
上一篇: phpcms 开源程序的定时发布功能
下一篇: javaSE基础学习笔记 day02