zoukankan      html  css  js  c++  java
  • 在.Net Core 3.0中尝试新的System.Text.Json API

    .NET Core 3.0提供了一个名为System.Text.Json的全新命名空间,它支持reader/writer,文档对象模型(DOM)和序列化程序。在此博客文章中,我将介绍它如何工作以及如何使用。
    官方文档

    获取JSON库

    • 如果以.NET Core为目标,请安装.NET Core 3.0及以上版本,该版本提供了新的JSON库和ASP.NET Core集成。
    • 如果以.NET Standard或.NET Framework为目标。安装System.Text.Json NuGet软件包(确保安装.NET Framework4.6.0或更高版本)。为了与ASP.NET Core集成,必须以.NET Core 3.0为目标。

    NET Core 3.0中JSON特性

    新的JSON API通过使用Span进行性能优化,并且可以直接处理UTF-8,而无需转码为UTF-16 string 实例。这两个方面对于ASP.NET Core都是至关重要的,在ASP.NET Core中,吞吐量是关键要求。使用System.Text.Json,可以将速度提高大约1.3倍至5倍。

    使用System.Text.Json

    using System.Text.Json;
    using System.Text.Json.Serialization;
    

    使用序列化器Serializer

    • 学习.Net Core最好的方式是查看源码,下面是JsonSerializer Serialize的部分源码:
    namespace System.Text.Json
    {
        public static partial class JsonSerializer
        {
            /// <summary>
            /// Convert the provided value into a <see cref="System.String"/>.
            /// </summary>
            /// <returns>A <see cref="System.String"/> representation of the value.</returns>
            /// <param name="value">The value to convert.</param>
            /// <param name="options">Options to control the conversion behavior.</param>
            /// <remarks>Using a <see cref="System.String"/> is not as efficient as using UTF-8
            /// encoding since the implementation internally uses UTF-8. See also <see cref="SerializeToUtf8Bytes"/>
            /// and <see cref="SerializeAsync"/>.
            /// </remarks>
            public static string Serialize<TValue>(TValue value, JsonSerializerOptions options = null)
            {
                return ToStringInternal(value, typeof(TValue), options);
            }
    
            /// <summary>
            /// Convert the provided value into a <see cref="System.String"/>.
            /// </summary>
            /// <returns>A <see cref="System.String"/> representation of the value.</returns>
            /// <param name="value">The value to convert.</param>
            /// <param name="inputType">The type of the <paramref name="value"/> to convert.</param>
            /// <param name="options">Options to control the conversion behavior.</param>
            /// <remarks>Using a <see cref="System.String"/> is not as efficient as using UTF-8
            /// encoding since the implementation internally uses UTF-8. See also <see cref="SerializeToUtf8Bytes"/>
            /// and <see cref="SerializeAsync"/>.
            /// </remarks>
            public static string Serialize(object value, Type inputType, JsonSerializerOptions options = null)
            {
                VerifyValueAndType(value, inputType);
    
                return ToStringInternal(value, inputType, options);
            }
    
            private static string ToStringInternal(object value, Type inputType, JsonSerializerOptions options)
            {
                return WriteCoreString(value, inputType, options);
            }
        }
    }
    

    可以看到序列化最终调用的是ToStringInternal这个方法。

    • 示例
    class Sample
    {
        public DateTimeOffset Date { get; set; }
        public string Summary { get; set; }
    }
    
    string Serialize(Sample value)
    {
        return JsonSerializer.Serialize<Sample>(value);
    }
    //obj
    string SerializeObj(object value)
    {
        return JsonSerializer.Serialize(value);
    }
    

    JsonSerializerOptions用于在序列化时设置配置, 例如处理注释,null处理,尾随逗号和命名策略。

     public static string ToJson(this object obj)
     {
        var options = new JsonSerializerOptions() { IgnoreNullValues = true, WriteIndented = true, AllowTrailingCommas = true };
        return JsonSerializer.Serialize(obj, options);
     }
    

    使用反序列化器Deserialize

     Sample Deserialize(string json)
    {
        var options = new JsonSerializerOptions
        {
            AllowTrailingCommas = true
        };
    
        return JsonSerializer.Deserialize<Sample>(json, options);
    }
    

    自定义属性来控制序列化行为

    可以使用自定义属性来控制序列化行为,例如,忽略属性或者指定属性的名称:

    class Sample
    {
        //忽略
        [JsonIgnore]
        public DateTimeOffset Date { get; set; }
        //指定名称
        [JsonPropertyName("test")]
        public string Summary { get; set; }
    }
    

    使用DOM

    有时,不想反序列化JSON但仍然希望对其内容进行结构化访问,这时可以使用JsonDocument

    var options = new JsonDocumentOptions
        {
            AllowTrailingCommas = true
        };
    using (JsonDocument document = JsonDocument.Parse(json, options))
    {
        //todo
         foreach (JsonElement element in document.RootElement.EnumerateArray())
         {
            DateTimeOffset date = element.GetProperty("date").GetDateTimeOffset();
             //todo
         }
    }
    

    使用Utf8JsonWriter

    var options = new JsonWriterOptions
    {
        Indented = true
    };
    
    using (var stream = new MemoryStream())
    {
        using (var writer = new Utf8JsonWriter(stream, options))
        {
            writer.WriteStartObject();
            writer.WriteString("date", DateTimeOffset.UtcNow);
            writer.WriteEndObject();
        }
    
        string json = Encoding.UTF8.GetString(stream.ToArray());
        Console.WriteLine(json);
    }
    

    使用Utf8JsonReader

    byte[] data = Encoding.UTF8.GetBytes(json);
    Utf8JsonReader reader = new Utf8JsonReader(data, isFinalBlock: true, state: default);
    
    while (reader.Read())
    {
        Console.Write(reader.TokenType);
    
        switch (reader.TokenType)
        {
            case JsonTokenType.PropertyName:
            case JsonTokenType.String:
            {
                string text = reader.GetString();
                Console.Write(" ");
                Console.Write(text);
                break;
            }
    
            case JsonTokenType.Number:
            {
                int value = reader.GetInt32();
                Console.Write(" ");
                Console.Write(value);
                break;
            }
        }
    
        Console.WriteLine();
    }
    

    System.Text.Json中的DateTime和DateTimeOffset支持

    The System.Text.Json library parses and writes DateTime and DateTimeOffset values according to the ISO 8601:-2019 extended profile. Converters provide custom support for serializing and deserializing with JsonSerializer. Custom support can also be implemented when using Utf8JsonReader and Utf8JsonWriter.

    具体请参考官方文档
    示例:

     public class DateTimeConverterUsingDateTimeParse : JsonConverter<DateTime>
        {
            /// <summary>
            /// 日期格式
            /// </summary>
            public string dateTimeFormat { get; }
            /// <summary>
            /// ctor
            /// </summary>      
            /// <param name="dateTimeFormat"></param>
            public DateTimeConverterUsingDateTimeParse(string dateTimeFormat)
            {
                this.dateTimeFormat = dateTimeFormat;
            }
            public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
            {
                Debug.Assert(typeToConvert == typeof(DateTime));
                return DateTime.Parse(reader.GetString());
            }
    
            public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
            {
                writer.WriteStringValue(value.ToString(dateTimeFormat));
            }
        }
    
     public static class JsonHelper
        {
            /// <summary>Converts to json.</summary>
            /// <param name="obj">The object.</param>
            /// <param name="dateTimeFormat">The date time format.</param>
            /// <returns>System.String.</returns>
            public static string ToJson(this object obj, string dateTimeFormat = "yyyy-MM-dd")
            {
                var options = new JsonSerializerOptions() { IgnoreNullValues = true, WriteIndented = true };
                options.Converters.Add(new DateTimeConverterUsingDateTimeParse(dateTimeFormat));
                return JsonSerializer.Serialize(obj, options);
            }
        }
    

    总结

    • 在.NET Core 3.0中,System.Text.Json API提供对JSON的内置支持,包括reader/writer,只读DOM和序列化器/反序列化器。
    • 主要目标是实现高性能和低内存分配。
    • ASP.NET Core 3.0包括对System.Text.Json的支持,默认情况下启用。

    补充

    有博友提问了下图中的几个问题:
    1572506712_1_.jpg

    当前API版本反序列化不会将JSON字符串中的数字强制转换;但是JsonConverter转换器功能可以逐个属性有效地选择转换:

    public class NumberToStringConverter : JsonConverter<int>
        {
            public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
            {
                var number = 0;
                if (reader.TokenType == JsonTokenType.String)
                {
                    if (Int32.TryParse(reader.GetString(), out number))
                        return number;
                }
                return reader.GetInt32();
            }
    
            public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
            {
                writer.WriteStringValue(value.ToString());
            }
        }
    
    class Sample
        {
            public string Date { get; set; }
            public int Summary { get; set; }
        }
       var json = "{"Date":"2019-10-31","Summary":"1"}";
                var options = new JsonSerializerOptions() { IgnoreNullValues = true, WriteIndented = true };
                options.Converters.Add(new NumberToStringConverter());
                var deserialize = JsonSerializer.Deserialize<Sample>(json, options);
    

    当前API版本支持System.Text.Json 支持Dictionary<key,value>序列化。

    Dictionary<string, object> dictionary = new Dictionary<string, object>
                {
                    {"1", 2}
                };
     var serialize = JsonSerializer.Serialize(dictionary);
                var temjson = "{"1":2}";
                var deserializeDictionary = JsonSerializer.Deserialize<Dictionary<string, object>>(temjson);
    
  • 相关阅读:
    样式的使用
    样式的使用
    jqurey基础一
    jQuery三天复习.md
    webstorm快捷键大全
    计算机的进制与编码
    2016-4-29HTML标记的使用
    HTML的基本概况
    Apache Maven 入门篇 ( 上 )
    ehcache.xml 分布试缓存
  • 原文地址:https://www.cnblogs.com/muran/p/11770629.html
Copyright © 2011-2022 走看看