欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

.NET Core 内置的 System.Text.Json 使用注意(MVC模型绑定后台获取不到解决方式)

程序员文章站 2024-01-21 18:48:28
...

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)

相关标签: core