ASP.NET Core Post Json 请求参数模型类型转换

2021年7月12日 3076点热度 0人点赞 1条评论
内容纲要

在后端中,当有分布式需求时,我们常常使用 64位 的数字类型表示字段类型,但是前端并不支持超过 16 位长度的数值类型,所以后端长度较大的 long、ulong 数值传到后端,其准确度就已经丢失。

解决方法就是将 ulong、long 转为字符串,传递给后端。

    public class TentantQueryDto
    {
        public ulong Id { get; set; }
    }

这是一个后端模型, Id 为 64 位数值,我们要做到前端传递 string,自动转 ulong;后端传递 ulong,自动返回 string 给前端。

首先定义两个转换器:

    public class ULongToStringConverter : JsonConverter<ulong>
    {
        public override ulong Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            string stringValue = reader.GetString();
            if (string.IsNullOrWhiteSpace(stringValue)) return 0;

            if (ulong.TryParse(stringValue, out var value)) return value;
            return 0;
        }

        public override void Write(Utf8JsonWriter writer, ulong value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString());
        }
    }
    public class StringToULongConverter : JsonConverter<string>
    {
        public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            return reader.GetString();
        }

        public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
        {
            ulong result = 0;
            if (string.IsNullOrWhiteSpace(value)) result = 0;
            if (ulong.TryParse(value, out var number)) result = number;

            writer.WriteNumberValue(result);
        }
    }

这两个转换器没有什么特别的地方,只是将数值和string互转。

然后定义特性,这个特性告诉我们应该使用什么字段、怎么在前后端传递 Json 时,自动转换参数类型:

    /// <summary>
    /// string 和 ulong 转换器
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property, AllowMultiple = false)]
    public class ULongConverterAttribute : JsonConverterAttribute
    {
        public override JsonConverter CreateConverter(Type typeToConvert)
        {
            if (typeToConvert == typeof(ulong))
                return new ULongToStringConverter();
            if (typeToConvert == typeof(string))
                return new StringToULongConverter();

            return base.CreateConverter(typeToConvert);
        }
    }

在要被转换的字段上使用该特性:

    public class TentantQueryDto
    {
        [ULongConverter]
        public ulong Id { get; set; }
    }

这样,我们无需另外加上转换代码,在前后端传递数据时, ASP.NET Core 调用转换器自动转换。

痴者工良

高级程序员劝退师

文章评论

  • 痴者工良

    using System.Reflection;
    using System.Text.Json.Serialization;
    
    namespace System.Text.Json;
    
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
    public class LongStringConverterAttribute : JsonConverterAttribute
    { 
        public override JsonConverter CreateConverter(Type typeToConvert)
        {
            if (typeToConvert == typeof(long))
                return new LongToStringConverter();
            if (typeToConvert == typeof(ulong))
                return new UlongToStringConverter();
    
            return base.CreateConverter(typeToConvert);
        }
    }
    
    public class LongToStringConverter : JsonConverter
    {
        public override bool CanConvert(Type typeToConvert)
        {
            return typeToConvert == typeof(long);
        }
    
        public override long Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            string? stringValue = reader.GetString();
            if (string.IsNullOrWhiteSpace(stringValue)) return 0;
    
            if (long.TryParse(stringValue, out var value)) return value;
            return 0;
        }
    
        public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString());
        }
    }
    
    public class UlongToStringConverter : JsonConverter
    {
        public override bool CanConvert(Type typeToConvert)
        {
            return typeToConvert == typeof(ulong);
        }
    
        public override ulong Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            string? stringValue = reader.GetString();
            if (string.IsNullOrWhiteSpace(stringValue)) return 0;
    
            if (ulong.TryParse(stringValue, out var value)) return value;
            return 0;
        }
    
        public override void Write(Utf8JsonWriter writer, ulong value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString());
        }
    }
    

    2022年7月22日