Răsfoiți Sursa

MaskConverter支持System.Text.Json

懒得勤快 2 ani în urmă
părinte
comite
8109db956d

+ 1 - 1
BenchmarkTest/BenchmarkTest.csproj

@@ -7,7 +7,7 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="BenchmarkDotNet" Version="0.13.7" />
+    <PackageReference Include="BenchmarkDotNet" Version="0.13.8" />
   </ItemGroup>
 
   <ItemGroup>

+ 101 - 97
Masuit.Tools.Abstractions/Files/FileExt.cs

@@ -5,108 +5,112 @@ using System.Threading.Tasks;
 
 namespace Masuit.Tools.Files
 {
-    /// <summary>
-    /// 大文件操作扩展类
-    /// </summary>
-    public static class FileExt
-    {
-        /// <summary>
-        /// 以文件流的形式复制大文件
-        /// </summary>
-        /// <param name="fs">源</param>
-        /// <param name="dest">目标地址</param>
-        /// <param name="bufferSize">缓冲区大小,默认8MB</param>
-        public static void CopyToFile(this Stream fs, string dest, int bufferSize = 1024 * 8 * 1024)
-        {
-            using var fsWrite = new FileStream(dest, FileMode.OpenOrCreate, FileAccess.ReadWrite);
-            byte[] buf = new byte[bufferSize];
-            int len;
-            while ((len = fs.Read(buf, 0, buf.Length)) != 0)
-            {
-                fsWrite.Write(buf, 0, len);
-            }
-        }
+	/// <summary>
+	/// 大文件操作扩展类
+	/// </summary>
+	public static class FileExt
+	{
+		/// <summary>
+		/// 以文件流的形式复制大文件
+		/// </summary>
+		/// <param name="fs">源</param>
+		/// <param name="dest">目标地址</param>
+		/// <param name="bufferSize">缓冲区大小,默认8MB</param>
+		public static void CopyToFile(this Stream fs, string dest, int bufferSize = 1024 * 8 * 1024)
+		{
+			using var fsWrite = new FileStream(dest, FileMode.OpenOrCreate, FileAccess.ReadWrite);
+			var stream = new BufferedStream(fs, bufferSize);
+			stream.CopyTo(fsWrite);
+		}
 
-        /// <summary>
-        /// 以文件流的形式复制大文件(异步方式)
-        /// </summary>
-        /// <param name="fs">源</param>
-        /// <param name="dest">目标地址</param>
-        /// <param name="bufferSize">缓冲区大小,默认8MB</param>
-        public static async Task CopyToFileAsync(this Stream fs, string dest, int bufferSize = 1024 * 1024 * 8)
-        {
-            using var fsWrite = new FileStream(dest, FileMode.OpenOrCreate, FileAccess.ReadWrite);
-            byte[] buf = new byte[bufferSize];
-            int len;
-            while ((len = await fs.ReadAsync(buf, 0, buf.Length)) != 0)
-            {
-                await fsWrite.WriteAsync(buf, 0, len);
-            }
-        }
+		/// <summary>
+		/// 以文件流的形式复制大文件(异步方式)
+		/// </summary>
+		/// <param name="fs">源</param>
+		/// <param name="dest">目标地址</param>
+		/// <param name="bufferSize">缓冲区大小,默认8MB</param>
+		public static Task CopyToFileAsync(this Stream fs, string dest, int bufferSize = 1024 * 1024 * 8)
+		{
+			using var fsWrite = new FileStream(dest, FileMode.OpenOrCreate, FileAccess.ReadWrite);
+			var stream = new BufferedStream(fs, bufferSize);
+			return stream.CopyToAsync(fsWrite);
+		}
 
-        /// <summary>
-        /// 将内存流转储成文件
-        /// </summary>
-        /// <param name="ms"></param>
-        /// <param name="filename"></param>
-        public static void SaveFile(this Stream ms, string filename)
-        {
-            using var fs = new FileStream(filename, FileMode.Create, FileAccess.Write);
-            byte[] buffer = ms.ToArray(); // 转化为byte格式存储
-            fs.Write(buffer, 0, buffer.Length);
-            fs.Flush();
-        }
+		/// <summary>
+		/// 将内存流转储成文件
+		/// </summary>
+		/// <param name="ms"></param>
+		/// <param name="filename"></param>
+		public static void SaveFile(this Stream ms, string filename)
+		{
+			using var fs = new FileStream(filename, FileMode.Create, FileAccess.Write);
+			var stream = new BufferedStream(ms, 1048576);
+			stream.CopyTo(fs);
+		}
 
-        /// <summary>
-        /// 计算文件的 MD5 值
-        /// </summary>
-        /// <param name="fs">源文件流</param>
-        /// <returns>MD5 值16进制字符串</returns>
-        public static string GetFileMD5(this FileStream fs) => HashFile(fs, "md5");
+		/// <summary>
+		/// 将内存流转储成文件
+		/// </summary>
+		/// <param name="ms"></param>
+		/// <param name="filename"></param>
+		public static Task SaveFileAsync(this Stream ms, string filename)
+		{
+			using var fs = new FileStream(filename, FileMode.Create, FileAccess.Write);
+			var stream = new BufferedStream(ms, 1048576);
+			return stream.CopyToAsync(fs);
+		}
 
-        /// <summary>
-        /// 计算文件的 sha1 值
-        /// </summary>
-        /// <param name="fs">源文件流</param>
-        /// <returns>sha1 值16进制字符串</returns>
-        public static string GetFileSha1(this Stream fs) => HashFile(fs, "sha1");
+		/// <summary>
+		/// 计算文件的 MD5
+		/// </summary>
+		/// <param name="fs">源文件流</param>
+		/// <returns>MD5 值16进制字符串</returns>
+		public static string GetFileMD5(this FileStream fs) => HashFile(fs);
 
-        /// <summary>
-        /// 计算文件的 sha256
-        /// </summary>
-        /// <param name="fs">源文件流</param>
-        /// <returns>sha256 值16进制字符串</returns>
-        public static string GetFileSha256(this Stream fs) => HashFile(fs, "sha256");
+		/// <summary>
+		/// 计算文件的 sha1
+		/// </summary>
+		/// <param name="fs">源文件流</param>
+		/// <returns>sha1 值16进制字符串</returns>
+		public static string GetFileSha1(this Stream fs) => HashFile(fs, nameof(SHA1));
 
-        /// <summary>
-        /// 计算文件的 sha512
-        /// </summary>
-        /// <param name="fs">源文件流</param>
-        /// <returns>sha512 值16进制字符串</returns>
-        public static string GetFileSha512(this Stream fs) => HashFile(fs, "sha512");
+		/// <summary>
+		/// 计算文件的 sha256
+		/// </summary>
+		/// <param name="fs">源文件流</param>
+		/// <returns>sha256 值16进制字符串</returns>
+		public static string GetFileSha256(this Stream fs) => HashFile(fs, nameof(SHA256));
 
-        /// <summary>
-        /// 计算文件的哈希值
-        /// </summary>
-        /// <param name="fs">被操作的源数据流</param>
-        /// <param name="algo">加密算法</param>
-        /// <returns>哈希值16进制字符串</returns>
-        private static string HashFile(Stream fs, string algo)
-        {
-            using HashAlgorithm crypto = algo switch
-            {
-                "sha1" => SHA1.Create(),
-                "sha256" => SHA256.Create(),
-                "sha512" => SHA512.Create(),
-                _ => MD5.Create(),
-            };
-            byte[] retVal = crypto.ComputeHash(fs);
-            var sb = new StringBuilder();
-            foreach (var t in retVal)
-            {
-                sb.Append(t.ToString("x2"));
-            }
-            return sb.ToString();
-        }
-    }
+		/// <summary>
+		/// 计算文件的 sha512 值
+		/// </summary>
+		/// <param name="fs">源文件流</param>
+		/// <returns>sha512 值16进制字符串</returns>
+		public static string GetFileSha512(this Stream fs) => HashFile(fs, nameof(SHA512));
+
+		/// <summary>
+		/// 计算文件的哈希值
+		/// </summary>
+		/// <param name="fs">被操作的源数据流</param>
+		/// <param name="algo">加密算法</param>
+		/// <returns>哈希值16进制字符串</returns>
+		private static string HashFile(Stream fs, string algo = nameof(MD5))
+		{
+			using HashAlgorithm crypto = algo switch
+			{
+				nameof(SHA1) => SHA1.Create(),
+				nameof(SHA256) => SHA256.Create(),
+				nameof(SHA512) => SHA512.Create(),
+				_ => MD5.Create(),
+			};
+			var stream = new BufferedStream(fs, 1048576);
+			byte[] hash = crypto.ComputeHash(stream);
+			var sb = new StringBuilder();
+			foreach (var t in hash)
+			{
+				sb.Append(t.ToString("x2"));
+			}
+			return sb.ToString();
+		}
+	}
 }

+ 1 - 1
Masuit.Tools.Abstractions/Masuit.Tools.Abstractions.csproj

@@ -3,7 +3,7 @@
         <TargetFrameworks>netstandard2.0;netstandard2.1;net461;net5;net6;net7</TargetFrameworks>
         <LangVersion>latest</LangVersion>
         <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-        <Version>2.6.6.8</Version>
+        <Version>2.6.6.9</Version>
         <Authors>懒得勤快</Authors>
         <Description>新手友好的C#万能工具库,码数吐司库,Masuit.Tools基础公共库(适用于.NET4.6.1/.NET Standard2.0及以上项目),包含一些常用的操作类,大都是静态类,加密解密,反射操作,Excel简单导出,权重随机筛选算法,分布式短id,表达式树,linq扩展,文件压缩,多线程下载和FTP客户端,硬件信息,字符串扩展方法,日期时间扩展操作,中国农历,大文件拷贝,图像裁剪,验证码,断点续传,集合扩展等常用封装。
             官网教程:https://tools.masuit.org

+ 85 - 85
Masuit.Tools.Abstractions/Systems/FallbackJsonPropertyResolver.cs

@@ -12,102 +12,102 @@ namespace Masuit.Tools.Systems;
 /// </summary>
 public class FallbackJsonPropertyResolver : CamelCasePropertyNamesContractResolver
 {
-    /// <summary>
-    /// 序列化时忽略的字段集
-    /// </summary>
-    protected readonly Dictionary<Type, HashSet<string>> SerializeIgnores = new();
+	/// <summary>
+	/// 序列化时忽略的字段集
+	/// </summary>
+	protected readonly Dictionary<Type, HashSet<string>> SerializeIgnores = new();
 
-    /// <summary>
-    /// 反序列化时忽略的字段集
-    /// </summary>
-    protected readonly Dictionary<Type, HashSet<string>> DeserializeIgnores = new();
+	/// <summary>
+	/// 反序列化时忽略的字段集
+	/// </summary>
+	protected readonly Dictionary<Type, HashSet<string>> DeserializeIgnores = new();
 
-    /// <summary>
-    /// 序列化时忽略
-    /// </summary>
-    /// <param name="type">类型</param>
-    /// <param name="propertyName">属性名</param>
-    /// <returns></returns>
-    public FallbackJsonPropertyResolver SerializeIgnore(Type type, params string[] propertyName)
-    {
-        if (!SerializeIgnores.ContainsKey(type)) SerializeIgnores[type] = new HashSet<string>();
-        foreach (var prop in propertyName)
-        {
-            SerializeIgnores[type].Add(prop);
-        }
+	/// <summary>
+	/// 序列化时忽略
+	/// </summary>
+	/// <param name="type">类型</param>
+	/// <param name="propertyName">属性名</param>
+	/// <returns></returns>
+	public FallbackJsonPropertyResolver SerializeIgnore(Type type, params string[] propertyName)
+	{
+		if (!SerializeIgnores.ContainsKey(type)) SerializeIgnores[type] = new HashSet<string>();
+		foreach (var prop in propertyName)
+		{
+			SerializeIgnores[type].Add(prop);
+		}
 
-        return this;
-    }
+		return this;
+	}
 
-    /// <summary>
-    /// 反序列化时忽略
-    /// </summary>
-    /// <param name="type">类型</param>
-    /// <param name="propertyName">属性名</param>
-    /// <returns></returns>
-    public FallbackJsonPropertyResolver DeserializeIgnore(Type type, params string[] propertyName)
-    {
-        if (!DeserializeIgnores.ContainsKey(type)) DeserializeIgnores[type] = new HashSet<string>();
-        foreach (var prop in propertyName)
-        {
-            DeserializeIgnores[type].Add(prop);
-        }
+	/// <summary>
+	/// 反序列化时忽略
+	/// </summary>
+	/// <param name="type">类型</param>
+	/// <param name="propertyName">属性名</param>
+	/// <returns></returns>
+	public FallbackJsonPropertyResolver DeserializeIgnore(Type type, params string[] propertyName)
+	{
+		if (!DeserializeIgnores.ContainsKey(type)) DeserializeIgnores[type] = new HashSet<string>();
+		foreach (var prop in propertyName)
+		{
+			DeserializeIgnores[type].Add(prop);
+		}
 
-        return this;
-    }
+		return this;
+	}
 
-    public bool IsSerializeIgnored(Type type, string propertyName)
-    {
-        if (!SerializeIgnores.ContainsKey(type)) return false;
-        if (SerializeIgnores[type].Count == 0) return true;
-        return SerializeIgnores[type].Contains(propertyName, StringComparer.CurrentCultureIgnoreCase);
-    }
+	public bool IsSerializeIgnored(Type type, string propertyName)
+	{
+		if (!SerializeIgnores.ContainsKey(type)) return false;
+		if (SerializeIgnores[type].Count == 0) return true;
+		return SerializeIgnores[type].Contains(propertyName, StringComparer.CurrentCultureIgnoreCase);
+	}
 
-    public bool IsDeserializeIgnored(Type type, string propertyName)
-    {
-        if (!DeserializeIgnores.ContainsKey(type)) return false;
-        if (DeserializeIgnores[type].Count == 0) return true;
-        return DeserializeIgnores[type].Contains(propertyName, StringComparer.CurrentCultureIgnoreCase);
-    }
+	public bool IsDeserializeIgnored(Type type, string propertyName)
+	{
+		if (!DeserializeIgnores.ContainsKey(type)) return false;
+		if (DeserializeIgnores[type].Count == 0) return true;
+		return DeserializeIgnores[type].Contains(propertyName, StringComparer.CurrentCultureIgnoreCase);
+	}
 
-    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
-    {
-        var typeMembers = GetSerializableMembers(type).DistinctBy(m => m.Name);
-        var properties = new List<JsonProperty>();
+	protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
+	{
+		var typeMembers = GetSerializableMembers(type).DistinctBy(m => m.Name);
+		var properties = new List<JsonProperty>();
 
-        foreach (var member in typeMembers)
-        {
-            var property = CreateProperty(member, memberSerialization);
-            if (IsSerializeIgnored(property.DeclaringType, property.PropertyName))
-            {
-                property.ShouldSerialize = _ => false;
-            }
+		foreach (var member in typeMembers)
+		{
+			var property = CreateProperty(member, memberSerialization);
+			if (IsSerializeIgnored(property.DeclaringType, property.PropertyName))
+			{
+				property.ShouldSerialize = _ => false;
+			}
 
-            if (IsDeserializeIgnored(property.DeclaringType, property.PropertyName))
-            {
-                property.ShouldDeserialize = _ => false;
-            }
+			if (IsDeserializeIgnored(property.DeclaringType, property.PropertyName))
+			{
+				property.ShouldDeserialize = _ => false;
+			}
 
-            properties.RemoveAll(p => p.PropertyName == property.PropertyName);
-            properties.Add(property);
-            var fallbackAttribute = member.GetCustomAttribute<FallbackJsonProperty>();
-            if (fallbackAttribute == null)
-            {
-                continue;
-            }
+			properties.RemoveAll(p => p.PropertyName == property.PropertyName);
+			properties.Add(property);
+			var fallbackAttribute = member.GetCustomAttribute<FallbackJsonProperty>();
+			if (fallbackAttribute == null)
+			{
+				continue;
+			}
 
-            property.PropertyName = fallbackAttribute.PreferredName;
-            foreach (var alternateName in fallbackAttribute.FallbackReadNames)
-            {
-                properties.RemoveAll(p => p.PropertyName == alternateName);
-                var fallbackProperty = CreateProperty(member, memberSerialization);
-                fallbackProperty.PropertyName = alternateName;
-                fallbackProperty.ShouldSerialize = _ => false;
-                fallbackProperty.ShouldDeserialize = _ => true;
-                properties.Add(fallbackProperty);
-            }
-        }
+			property.PropertyName = fallbackAttribute.PreferredName;
+			foreach (var alternateName in fallbackAttribute.FallbackReadNames)
+			{
+				properties.RemoveAll(p => p.PropertyName == alternateName);
+				var fallbackProperty = CreateProperty(member, memberSerialization);
+				fallbackProperty.PropertyName = alternateName;
+				fallbackProperty.ShouldSerialize = _ => false;
+				fallbackProperty.ShouldDeserialize = _ => true;
+				properties.Add(fallbackProperty);
+			}
+		}
 
-        return properties;
-    }
+		return properties;
+	}
 }

+ 52 - 0
Masuit.Tools.Abstractions/Systems/MaskConverter2.cs

@@ -0,0 +1,52 @@
+#if NET5_0_OR_GREATER
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Masuit.Tools.Systems.Text.Json;
+
+public class MaskConverter : JsonConverter<string>
+{
+	/// <summary>Reads and converts the JSON to type <typeparamref name="T" />.</summary>
+	/// <param name="reader">The reader.</param>
+	/// <param name="typeToConvert">The type to convert.</param>
+	/// <param name="options">An object that specifies serialization options to use.</param>
+	/// <returns>The converted value.</returns>
+	public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+	{
+		return reader.GetString();
+	}
+
+	/// <summary>Writes a specified value as JSON.</summary>
+	/// <param name="writer">The writer to write to.</param>
+	/// <param name="value">The value to convert to JSON.</param>
+	/// <param name="options">An object that specifies serialization options to use.</param>
+	public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
+	{
+		writer.WriteStringValue(value.Mask());
+	}
+}
+
+public class MaskEmailConverter : JsonConverter<string>
+{
+	/// <summary>Reads and converts the JSON to type <typeparamref name="T" />.</summary>
+	/// <param name="reader">The reader.</param>
+	/// <param name="typeToConvert">The type to convert.</param>
+	/// <param name="options">An object that specifies serialization options to use.</param>
+	/// <returns>The converted value.</returns>
+	public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+	{
+		return reader.GetString();
+	}
+
+	/// <summary>Writes a specified value as JSON.</summary>
+	/// <param name="writer">The writer to write to.</param>
+	/// <param name="value">The value to convert to JSON.</param>
+	/// <param name="options">An object that specifies serialization options to use.</param>
+	public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
+	{
+		writer.WriteStringValue(value.MaskEmail());
+	}
+}
+
+#endif

+ 25 - 0
Masuit.Tools.Abstractions/Systems/SerializeIgnoreResolver.cs

@@ -0,0 +1,25 @@
+#if NET5_0_OR_GREATER
+using System;
+using System.Linq;
+using System.Text.Json;
+using System.Text.Json.Serialization.Metadata;
+
+namespace Masuit.Tools.Systems;
+
+public class SerializeIgnoreResolver : DefaultJsonTypeInfoResolver
+{
+	public override JsonTypeInfo GetTypeInfo(Type t, JsonSerializerOptions o)
+	{
+		var jti = base.GetTypeInfo(t, o);
+		foreach (var prop in jti.Properties)
+		{
+			if (prop.AttributeProvider.GetCustomAttributes(typeof(DeserializeOnlyJsonPropertyAttribute), true).Union(prop.AttributeProvider.GetCustomAttributes(typeof(SerializeIgnoreAttribute), true)).Any())
+			{
+				prop.ShouldSerialize = (_, _) => false;
+			}
+		}
+
+		return jti;
+	}
+}
+#endif

+ 1 - 1
Masuit.Tools.AspNetCore/Masuit.Tools.AspNetCore.csproj

@@ -18,7 +18,7 @@
         <Product>Masuit.Tools.AspNetCore</Product>
         <PackageId>Masuit.Tools.AspNetCore</PackageId>
         <LangVersion>latest</LangVersion>
-        <Version>1.2.6.11</Version>
+        <Version>1.2.6.12</Version>
         <RepositoryType></RepositoryType>
         <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
         <FileVersion>1.1.9</FileVersion>

+ 1 - 1
Masuit.Tools.Core/Masuit.Tools.Core.csproj

@@ -6,7 +6,7 @@
 官网教程:https://tools.masuit.org
 github:https://github.com/ldqk/Masuit.Tools
         </Description>
-        <Version>2.6.6.8</Version>
+        <Version>2.6.6.9</Version>
         <Copyright>Copyright © 懒得勤快</Copyright>
         <PackageProjectUrl>https://github.com/ldqk/Masuit.Tools</PackageProjectUrl>
         <PackageTags>Masuit.Tools,工具库,Utility,Crypt,Extensions</PackageTags>

+ 2 - 2
Masuit.Tools.Excel/Masuit.Tools.Excel.csproj

@@ -3,7 +3,7 @@
         <TargetFramework>netstandard2.0</TargetFramework>
         <LangVersion>latest</LangVersion>
         <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-        <Version>1.2.7.1</Version>
+        <Version>1.2.7.2</Version>
         <Authors>懒得勤快</Authors>
         <Description>Masuit.Tools.Excel导出库,支持一些简单数据的导出,支持图片列</Description>
         <Copyright>懒得勤快</Copyright>
@@ -38,7 +38,7 @@
       </None>
     </ItemGroup>
     <ItemGroup>
-        <PackageReference Include="EPPlus" Version="6.2.8" />
+        <PackageReference Include="EPPlus" Version="6.2.9" />
         <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
     </ItemGroup>
     <ItemGroup>

+ 7 - 3
README.md

@@ -794,10 +794,10 @@ public override Post SavePost(Post t)
 // Attribute的方式为json序列化时进行数据脱敏
 public class MyClass
 {
-    [JsonConverter(typeof(MaskEmailConverter))]
+    [JsonConverter(typeof(MaskEmailConverter))] // 请注意命名空间,使用Newtonsoft.Json请导入Masuit.Tools.Systems命名空间,使用System.Text.Json请导入Masuit.Tools.Systems.Text.Json命名空间
     public string Email { get; set; }
 
-    [JsonConverter(typeof(MaskConverter))]
+    [JsonConverter(typeof(MaskConverter))] // 请注意命名空间,使用Newtonsoft.Json请导入Masuit.Tools.Systems命名空间,使用System.Text.Json请导入Masuit.Tools.Systems.Text.Json命名空间
     public string PhoneNumber { get; set; }
 }
 ```
@@ -1147,7 +1147,7 @@ a.Next(func1).Next(func2).Next(func3);
 "123".Next(s=>s.ToInt32()).Next(x=>x*2).Next(x=>Math.Log(x));
 ```
 
-### 41.Newtonsoft.Json的只允许字段(反)序列化行为的契约解释器
+### 41.Newtonsoft.Json和System.Text.Json的只允许字段(反)序列化行为的契约解释器
 
 #### DeserializeOnlyContractResolver
 
@@ -1167,10 +1167,14 @@ public class ClassDto
         public int Num { get; set; }
     }
   
+    // Newtonsoft.Json
     JsonConvert.SerializeObject(new MyClass(),new JsonSerializerSettings()
     {
         ContractResolver = new DeserializeOnlyContractResolver() // 配置使用DeserializeOnlyContractResolver解释器
     });
+
+    // System.Text.Json
+    JsonSerializer.Serialize(object, new JsonSerializerOptions() { TypeInfoResolver = new SerializeIgnoreResolver() });
 ```
 
 如果是WebAPI全局使用: