diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/Array[int]/SeparatedByVBarInt32ArrayConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/Newtonsoft.Json/Array[Integer]/TextualIntegerArrayWithPipeSplitConverter.cs similarity index 57% rename from src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/Array[int]/SeparatedByVBarInt32ArrayConverter.cs rename to src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/Newtonsoft.Json/Array[Integer]/TextualIntegerArrayWithPipeSplitConverter.cs index 22849996..478c5a8a 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/Array[int]/SeparatedByVBarInt32ArrayConverter.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/Newtonsoft.Json/Array[Integer]/TextualIntegerArrayWithPipeSplitConverter.cs @@ -1,12 +1,9 @@ using System; -using System.Linq; namespace Newtonsoft.Json.Converters { - internal class SeparatedByVBarInt32ArrayConverter : JsonConverter + internal class TextualIntegerArrayWithPipeSplitConverter : JsonConverter { - private const string SEPARATOR = "|"; - public override bool CanRead { get { return true; } @@ -27,28 +24,29 @@ namespace Newtonsoft.Json.Converters { string? value = serializer.Deserialize(reader); if (value == null) - return existingValue; + return null; + if (string.IsNullOrEmpty(value)) + return Array.Empty(); - try + string[] strArr = value.Split('|'); + int[] intArr = new int[strArr.Length]; + for (int i = 0; i < strArr.Length; i++) { - return value - .Split(new string[] { SEPARATOR }, StringSplitOptions.RemoveEmptyEntries) - .Select(e => int.Parse(e)) - .ToArray(); - } - catch (FormatException ex) - { - throw new JsonReaderException(ex.Message, ex); + if (!int.TryParse(strArr[i], out int j)) + throw new JsonSerializationException("Unexpected token when parsing string to integer."); + + intArr[i] = j; } + return intArr; } - throw new JsonReaderException(); + throw new JsonSerializationException(); } public override void WriteJson(JsonWriter writer, int[]? value, JsonSerializer serializer) { if (value != null) - writer.WriteValue(string.Join(SEPARATOR, value)); + writer.WriteValue(string.Join("|", value)); else writer.WriteNull(); } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/Array[string]/SeparatedByVBarStringArrayConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/Newtonsoft.Json/Array[String]/TextualStringArrayWithPipeSplitConverter.cs similarity index 70% rename from src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/Array[string]/SeparatedByVBarStringArrayConverter.cs rename to src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/Newtonsoft.Json/Array[String]/TextualStringArrayWithPipeSplitConverter.cs index 5ba3d29d..4ee5f811 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/Array[string]/SeparatedByVBarStringArrayConverter.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/Newtonsoft.Json/Array[String]/TextualStringArrayWithPipeSplitConverter.cs @@ -2,10 +2,8 @@ namespace Newtonsoft.Json.Converters { - internal class SeparatedByVBarStringArrayConverter : JsonConverter + internal class TextualStringArrayWithPipeSplitConverter : JsonConverter { - private const string SEPARATOR = "|"; - public override bool CanRead { get { return true; } @@ -26,18 +24,20 @@ namespace Newtonsoft.Json.Converters { string? value = serializer.Deserialize(reader); if (value == null) - return existingValue; + return null; + if (string.IsNullOrEmpty(value)) + return Array.Empty(); - return value.Split(new string[] { SEPARATOR }, StringSplitOptions.RemoveEmptyEntries); + return value.Split('|'); } - throw new JsonReaderException(); + throw new JsonSerializationException(); } public override void WriteJson(JsonWriter writer, string[]? value, JsonSerializer serializer) { if (value != null) - writer.WriteValue(string.Join(SEPARATOR, value)); + writer.WriteValue(string.Join("|", value)); else writer.WriteNull(); } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/Newtonsoft.Json/List[Integer]/TextualIntegerListWithPipeSplitConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/Newtonsoft.Json/List[Integer]/TextualIntegerListWithPipeSplitConverter.cs new file mode 100644 index 00000000..6c2e1661 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/Newtonsoft.Json/List[Integer]/TextualIntegerListWithPipeSplitConverter.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Newtonsoft.Json.Converters +{ + internal class TextualIntegerListWithPipeSplitConverter : JsonConverter + { + private readonly JsonConverter _converter = new TextualIntegerArrayWithPipeSplitConverter(); + + public override bool CanConvert(Type objectType) + { + return objectType.IsGenericType && + typeof(IList<>).IsAssignableFrom(objectType.GetGenericTypeDefinition()) && + typeof(int) == objectType.GetGenericArguments()[0]; + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + int[]? array = _converter.ReadJson(reader, objectType, null, false, serializer); + return array?.ToList(); + } + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + _converter.WriteJson(writer, ((IList?)value)?.ToArray(), serializer); + } + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/Newtonsoft.Json/List[String]/TextualStringListWithPipeSplitConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/Newtonsoft.Json/List[String]/TextualStringListWithPipeSplitConverter.cs new file mode 100644 index 00000000..8436e7ae --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/Newtonsoft.Json/List[String]/TextualStringListWithPipeSplitConverter.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Newtonsoft.Json.Converters +{ + internal class TextualStringListWithPipeSplitConverter : JsonConverter + { + private readonly JsonConverter _converter = new TextualStringArrayWithPipeSplitConverter(); + + public override bool CanConvert(Type objectType) + { + return objectType.IsGenericType && + typeof(IList<>).IsAssignableFrom(objectType.GetGenericTypeDefinition()) && + typeof(string) == objectType.GetGenericArguments()[0]; + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + string[]? array = _converter.ReadJson(reader, objectType, null, false, serializer); + return array?.ToList(); + } + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + _converter.WriteJson(writer, ((IList?)value)?.ToArray(), serializer); + } + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/Array[int]/SeparatedByVBarInt32ArrayConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/System.Text.Json/Array[Integer]/TextualIntegerArrayWithPipeSplitConverter.cs similarity index 58% rename from src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/Array[int]/SeparatedByVBarInt32ArrayConverter.cs rename to src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/System.Text.Json/Array[Integer]/TextualIntegerArrayWithPipeSplitConverter.cs index eccf787c..45be8070 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/Array[int]/SeparatedByVBarInt32ArrayConverter.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/System.Text.Json/Array[Integer]/TextualIntegerArrayWithPipeSplitConverter.cs @@ -3,7 +3,7 @@ using System.Text.Json.Serialization; namespace System.Text.Json.Converters { - internal class SeparatedByVBarInt32ArrayConverter : JsonConverter + internal class TextualIntegerArrayWithPipeSplitConverter : JsonConverter { private const string SEPARATOR = "|"; @@ -18,18 +18,19 @@ namespace System.Text.Json.Converters string? value = reader.GetString(); if (value == null) return null; + if (string.IsNullOrEmpty(value)) + return Array.Empty(); - try + string[] strArr = value.Split('|'); + int[] intArr = new int[strArr.Length]; + for (int i = 0; i < strArr.Length; i++) { - return value - .Split(new string[] { SEPARATOR }, StringSplitOptions.RemoveEmptyEntries) - .Select(e => int.Parse(e)) - .ToArray(); - } - catch (FormatException ex) - { - throw new JsonException(ex.Message, ex); + if (!int.TryParse(strArr[i], out int j)) + throw new JsonException("Unexpected token when parsing string to integer."); + + intArr[i] = j; } + return intArr; } throw new JsonException(); @@ -38,7 +39,7 @@ namespace System.Text.Json.Converters public override void Write(Utf8JsonWriter writer, int[]? value, JsonSerializerOptions options) { if (value != null) - writer.WriteStringValue(string.Join(SEPARATOR, value)); + writer.WriteStringValue(string.Join("|", value)); else writer.WriteNullValue(); } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/List[int]/SeparatedByVBarStringArrayConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/System.Text.Json/Array[String]/TextualStringArrayWithPipeSplitConverter.cs similarity index 72% rename from src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/List[int]/SeparatedByVBarStringArrayConverter.cs rename to src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/System.Text.Json/Array[String]/TextualStringArrayWithPipeSplitConverter.cs index 83297b61..6d567988 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/List[int]/SeparatedByVBarStringArrayConverter.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/System.Text.Json/Array[String]/TextualStringArrayWithPipeSplitConverter.cs @@ -2,10 +2,8 @@ namespace System.Text.Json.Converters { - internal class SeparatedByVBarStringArrayConverter : JsonConverter + internal class TextualStringArrayWithPipeSplitConverter : JsonConverter { - private const string SEPARATOR = "|"; - public override string[]? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.Null) @@ -17,8 +15,10 @@ namespace System.Text.Json.Converters string? value = reader.GetString(); if (value == null) return null; + if (string.IsNullOrEmpty(value)) + return Array.Empty(); - return value.Split(new string[] { SEPARATOR }, StringSplitOptions.RemoveEmptyEntries); + return value.Split('|'); } throw new JsonException(); @@ -27,7 +27,7 @@ namespace System.Text.Json.Converters public override void Write(Utf8JsonWriter writer, string[]? value, JsonSerializerOptions options) { if (value != null) - writer.WriteStringValue(string.Join(SEPARATOR, value)); + writer.WriteStringValue(string.Join("|", value)); else writer.WriteNullValue(); } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/System.Text.Json/List[Integer]/TextualIntegerListWithPipeSplitConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/System.Text.Json/List[Integer]/TextualIntegerListWithPipeSplitConverter.cs new file mode 100644 index 00000000..9dc68fd5 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/System.Text.Json/List[Integer]/TextualIntegerListWithPipeSplitConverter.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; + +namespace System.Text.Json.Converters +{ + internal class TextualIntegerListWithPipeSplitConverter : JsonConverterFactory + { + private sealed class InnerTextualIntegerListWithVBarSplitConverter : JsonConverter?> + { + private readonly JsonConverter _converter = new TextualIntegerArrayWithPipeSplitConverter(); + + public override IList? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + int[]? array = _converter.Read(ref reader, typeToConvert, options); + IList? list = array?.ToList(); + return list; + } + + public override void Write(Utf8JsonWriter writer, IList? value, JsonSerializerOptions options) + { + _converter.Write(writer, value?.ToArray(), options); + } + } + + public override bool CanConvert(Type typeToConvert) + { + return typeToConvert.IsGenericType && + typeof(IList<>).IsAssignableFrom(typeToConvert.GetGenericTypeDefinition()) && + typeof(int) == typeToConvert.GetGenericArguments()[0]; + } + + public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + return new InnerTextualIntegerListWithVBarSplitConverter(); + } + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/System.Text.Json/List[String]/TextualStringListWithPipeSplitConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/System.Text.Json/List[String]/TextualStringListWithPipeSplitConverter.cs new file mode 100644 index 00000000..f582b069 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Internal/System.Text.Json/List[String]/TextualStringListWithPipeSplitConverter.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; + +namespace System.Text.Json.Converters +{ + internal class TextualStringListWithPipeSplitConverter : JsonConverterFactory + { + private sealed class InnerTextualStringListWithVBarSplitConverter : JsonConverter?> + { + private readonly JsonConverter _converter = new TextualStringArrayWithPipeSplitConverter(); + + public override IList? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + string[]? array = _converter.Read(ref reader, typeToConvert, options); + IList? list = array?.ToList(); + return list; + } + + public override void Write(Utf8JsonWriter writer, IList? value, JsonSerializerOptions options) + { + _converter.Write(writer, value?.ToArray(), options); + } + } + + public override bool CanConvert(Type typeToConvert) + { + return typeToConvert.IsGenericType && + typeof(IList<>).IsAssignableFrom(typeToConvert.GetGenericTypeDefinition()) && + typeof(string) == typeToConvert.GetGenericArguments()[0]; + } + + public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + return new InnerTextualStringListWithVBarSplitConverter(); + } + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/List[int]/SeparatedByVBarInt32IListConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/List[int]/SeparatedByVBarInt32IListConverter.cs deleted file mode 100644 index a9aa9fcb..00000000 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/List[int]/SeparatedByVBarInt32IListConverter.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Newtonsoft.Json.Converters -{ - internal class SeparatedByVBarInt32IListConverter : JsonConverter?> - { - private readonly JsonConverter?> _converter = new SeparatedByVBarInt32ListConverter(); - - public override bool CanRead - { - get { return true; } - } - - public override bool CanWrite - { - get { return true; } - } - - public override IList? ReadJson(JsonReader reader, Type objectType, IList? existingValue, bool hasExistingValue, JsonSerializer serializer) - { - return _converter.ReadJson(reader, objectType, ConvertIListToList(existingValue), hasExistingValue, serializer); - } - - public override void WriteJson(JsonWriter writer, IList? value, JsonSerializer serializer) - { - _converter.WriteJson(writer, ConvertIListToList(value), serializer); - } - - private List? ConvertIListToList(IList? src) - { - if (src == null) - return null; - - List? dest = src as List; - if (dest != null) - return dest; - - return new List(src); - } - } -} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/List[int]/SeparatedByVBarInt32ListConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/List[int]/SeparatedByVBarInt32ListConverter.cs deleted file mode 100644 index 4f211d6b..00000000 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/List[int]/SeparatedByVBarInt32ListConverter.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Newtonsoft.Json.Converters -{ - internal class SeparatedByVBarInt32ListConverter : JsonConverter?> - { - private readonly JsonConverter _converter = new SeparatedByVBarInt32ArrayConverter(); - - public override bool CanRead - { - get { return true; } - } - - public override bool CanWrite - { - get { return true; } - } - - public override List? ReadJson(JsonReader reader, Type objectType, List? existingValue, bool hasExistingValue, JsonSerializer serializer) - { - return _converter.ReadJson(reader, objectType, existingValue?.ToArray(), hasExistingValue, serializer)?.ToList(); - } - - public override void WriteJson(JsonWriter writer, List? value, JsonSerializer serializer) - { - _converter.WriteJson(writer, value?.ToArray(), serializer); - } - } -} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/List[string]/SeparatedByVBarStringIListConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/List[string]/SeparatedByVBarStringIListConverter.cs deleted file mode 100644 index 285ac97f..00000000 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/List[string]/SeparatedByVBarStringIListConverter.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Newtonsoft.Json.Converters -{ - internal class SeparatedByVBarStringIListConverter : JsonConverter?> - { - private readonly JsonConverter?> _converter = new SeparatedByVBarStringListConverter(); - - public override bool CanRead - { - get { return true; } - } - - public override bool CanWrite - { - get { return true; } - } - - public override IList? ReadJson(JsonReader reader, Type objectType, IList? existingValue, bool hasExistingValue, JsonSerializer serializer) - { - return _converter.ReadJson(reader, objectType, ConvertIListToList(existingValue), hasExistingValue, serializer); - } - - public override void WriteJson(JsonWriter writer, IList? value, JsonSerializer serializer) - { - _converter.WriteJson(writer, ConvertIListToList(value), serializer); - } - - private List? ConvertIListToList(IList? src) - { - if (src == null) - return null; - - List? dest = src as List; - if (dest != null) - return dest; - - return new List(src); - } - } -} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/List[string]/SeparatedByVBarStringListConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/List[string]/SeparatedByVBarStringListConverter.cs deleted file mode 100644 index f2a55855..00000000 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/Newtonsoft.Json/List[string]/SeparatedByVBarStringListConverter.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Newtonsoft.Json.Converters -{ - internal class SeparatedByVBarStringListConverter : JsonConverter?> - { - private readonly JsonConverter _converter = new SeparatedByVBarStringArrayConverter(); - - public override bool CanRead - { - get { return true; } - } - - public override bool CanWrite - { - get { return true; } - } - - public override List? ReadJson(JsonReader reader, Type objectType, List? existingValue, bool hasExistingValue, JsonSerializer serializer) - { - return _converter.ReadJson(reader, objectType, existingValue?.ToArray(), hasExistingValue, serializer)?.ToList(); - } - - public override void WriteJson(JsonWriter writer, List? value, JsonSerializer serializer) - { - _converter.WriteJson(writer, value?.ToArray(), serializer); - } - } -} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/Array[string]/SeparatedByVBarInt32IListConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/Array[string]/SeparatedByVBarInt32IListConverter.cs deleted file mode 100644 index 684bcbba..00000000 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/Array[string]/SeparatedByVBarInt32IListConverter.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections.Generic; -using System.Text.Json.Serialization; - -namespace System.Text.Json.Converters -{ - internal class SeparatedByVBarInt32IListConverter : JsonConverter?> - { - private readonly JsonConverter?> _converter = new SeparatedByVBarInt32ListConverter(); - - public override IList? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return _converter.Read(ref reader, typeToConvert, options); - } - - public override void Write(Utf8JsonWriter writer, IList? value, JsonSerializerOptions options) - { - _converter.Write(writer, ConvertIListToList(value), options); - } - - private List? ConvertIListToList(IList? src) - { - if (src == null) - return null; - - List? dest = src as List; - if (dest != null) - return dest; - - return new List(src); - } - } -} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/Array[string]/SeparatedByVBarInt32ListConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/Array[string]/SeparatedByVBarInt32ListConverter.cs deleted file mode 100644 index 60fc9331..00000000 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/Array[string]/SeparatedByVBarInt32ListConverter.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Text.Json.Serialization; - -namespace System.Text.Json.Converters -{ - internal class SeparatedByVBarInt32ListConverter : JsonConverter?> - { - private readonly JsonConverter _converter = new SeparatedByVBarInt32ArrayConverter(); - - public override List? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return _converter.Read(ref reader, typeToConvert, options)?.ToList(); - } - - public override void Write(Utf8JsonWriter writer, List? value, JsonSerializerOptions options) - { - _converter.Write(writer, value?.ToArray(), options); - } - } -} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/List[string]/SeparatedByVBarStringIListConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/List[string]/SeparatedByVBarStringIListConverter.cs deleted file mode 100644 index 40b8dc23..00000000 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/List[string]/SeparatedByVBarStringIListConverter.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections.Generic; -using System.Text.Json.Serialization; - -namespace System.Text.Json.Converters -{ - internal class SeparatedByVBarStringIListConverter : JsonConverter?> - { - private readonly JsonConverter?> _converter = new SeparatedByVBarStringListConverter(); - - public override IList? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return _converter.Read(ref reader, typeToConvert, options); - } - - public override void Write(Utf8JsonWriter writer, IList? value, JsonSerializerOptions options) - { - _converter.Write(writer, ConvertIListToList(value), options); - } - - private List? ConvertIListToList(IList? src) - { - if (src == null) - return null; - - List? dest = src as List; - if (dest != null) - return dest; - - return new List(src); - } - } -} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/List[string]/SeparatedByVBarStringListConverter.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/List[string]/SeparatedByVBarStringListConverter.cs deleted file mode 100644 index de374ed2..00000000 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Converters/System.Text.Json/List[string]/SeparatedByVBarStringListConverter.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Text.Json.Serialization; - -namespace System.Text.Json.Converters -{ - internal class SeparatedByVBarStringListConverter : JsonConverter?> - { - private readonly JsonConverter _converter = new SeparatedByVBarStringArrayConverter(); - - public override List? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return _converter.Read(ref reader, typeToConvert, options)?.ToList(); - } - - public override void Write(Utf8JsonWriter writer, List? value, JsonSerializerOptions options) - { - _converter.Write(writer, value?.ToArray(), options); - } - } -} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Models/CgibinMessage/CgibinMessageSendRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Models/CgibinMessage/CgibinMessageSendRequest.cs index 71deef46..5da271ca 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Models/CgibinMessage/CgibinMessageSendRequest.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Models/CgibinMessage/CgibinMessageSendRequest.cs @@ -964,27 +964,27 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Models /// 获取或设置接收消息的成员账号列表。 /// [Newtonsoft.Json.JsonProperty("touser")] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.SeparatedByVBarStringIListConverter))] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.TextualStringListWithPipeSplitConverter))] [System.Text.Json.Serialization.JsonPropertyName("touser")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.SeparatedByVBarStringIListConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.TextualStringListWithPipeSplitConverter))] public IList? ToUserIdList { get; set; } /// /// 获取或设置接收消息的部门 ID 列表。 /// [Newtonsoft.Json.JsonProperty("toparty")] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.SeparatedByVBarInt32IListConverter))] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.TextualIntegerListWithPipeSplitConverter))] [System.Text.Json.Serialization.JsonPropertyName("toparty")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.SeparatedByVBarInt32IListConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.TextualIntegerListWithPipeSplitConverter))] public IList? ToDepartmentIdList { get; set; } /// /// 获取或设置接收消息的标签 ID 列表。 /// [Newtonsoft.Json.JsonProperty("totag")] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.SeparatedByVBarInt32IListConverter))] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.TextualIntegerListWithPipeSplitConverter))] [System.Text.Json.Serialization.JsonPropertyName("totag")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.SeparatedByVBarInt32IListConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.TextualIntegerListWithPipeSplitConverter))] public IList? ToTagIdList { get; set; } /// diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Models/CgibinMessage/CgibinMessageSendResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Models/CgibinMessage/CgibinMessageSendResponse.cs index b0245cc6..d7abe3a0 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Models/CgibinMessage/CgibinMessageSendResponse.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Models/CgibinMessage/CgibinMessageSendResponse.cs @@ -9,27 +9,27 @@ /// 获取或设置无效的成员账号列表。 /// [Newtonsoft.Json.JsonProperty("invaliduser")] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.SeparatedByVBarStringArrayConverter))] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.TextualStringArrayWithPipeSplitConverter))] [System.Text.Json.Serialization.JsonPropertyName("invaliduser")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.SeparatedByVBarStringArrayConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.TextualStringArrayWithPipeSplitConverter))] public string[]? InvalidUserIdList { get; set; } /// /// 获取或设置无效的部门 ID 列表。 /// [Newtonsoft.Json.JsonProperty("invalidparty")] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.SeparatedByVBarInt32ArrayConverter))] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.TextualIntegerArrayWithPipeSplitConverter))] [System.Text.Json.Serialization.JsonPropertyName("invalidparty")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.SeparatedByVBarInt32ArrayConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.TextualIntegerArrayWithPipeSplitConverter))] public int[]? InvalidDepartmentIdList { get; set; } /// /// 获取或设置无效的标签 ID 列表。 /// [Newtonsoft.Json.JsonProperty("invalidtag")] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.SeparatedByVBarInt32ArrayConverter))] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.TextualIntegerArrayWithPipeSplitConverter))] [System.Text.Json.Serialization.JsonPropertyName("invalidtag")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.SeparatedByVBarInt32ArrayConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.TextualIntegerArrayWithPipeSplitConverter))] public int[]? InvalidTagIdList { get; set; } /// diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Models/CgibinTag/TagUser/CgibinTagAddTagUsersResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Models/CgibinTag/TagUser/CgibinTagAddTagUsersResponse.cs index 1dfa5f0c..0057cc3a 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Models/CgibinTag/TagUser/CgibinTagAddTagUsersResponse.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Models/CgibinTag/TagUser/CgibinTagAddTagUsersResponse.cs @@ -9,9 +9,9 @@ /// 获取或设置无效的成员账号列表。 /// [Newtonsoft.Json.JsonProperty("invalidlist")] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.SeparatedByVBarStringArrayConverter))] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.TextualStringArrayWithPipeSplitConverter))] [System.Text.Json.Serialization.JsonPropertyName("invalidlist")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.SeparatedByVBarStringArrayConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.TextualStringArrayWithPipeSplitConverter))] public string[]? InvalidUserIdList { get; set; } /// diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/README.md b/src/SKIT.FlurlHttpClient.Wechat.Work/README.md new file mode 100644 index 00000000..02b6d93b --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/README.md @@ -0,0 +1,26 @@ +## SKIT.FlurlHttpClient.Wechat.Work + +[![GitHub Stars](https://img.shields.io/github/stars/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat?logo=github&label=Stars)](https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat) [![GitHub Forks](https://img.shields.io/github/forks/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat?logo=github&label=Forks)](https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat) [![NuGet Download](https://img.shields.io/nuget/dt/SKIT.FlurlHttpClient.Wechat.Work.svg?sanitize=true&label=Downloads)](https://www.nuget.org/packages/SKIT.FlurlHttpClient.Wechat.Work) [![License](https://img.shields.io/github/license/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat?label=License)](https://mit-license.org/) + +基于 `Flurl.Http` 的企业微信 API 客户端。 + +--- + +### 【功能特性】 + +- 基于企业微信 API 封装。 +- 支持企业内部开发、第三方应用开发(即服务商)、智慧硬件开发(即硬件接入)三种模式。 +- 提供了企业微信 API 所需的 SHA-1、AES 等算法工具类。 +- 提供了 JS-SDK 签名、解析回调通知事件等扩展方法。 + +--- + +### 【开发文档】 + +[点此查看](https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat)。 + +--- + +### 【更新日志】 + +[点此查看](https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat/blob/main/CHANGELOG.md)。 \ No newline at end of file diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/SKIT.FlurlHttpClient.Wechat.Work.csproj b/src/SKIT.FlurlHttpClient.Wechat.Work/SKIT.FlurlHttpClient.Wechat.Work.csproj index c66c265c..2e91176a 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/SKIT.FlurlHttpClient.Wechat.Work.csproj +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/SKIT.FlurlHttpClient.Wechat.Work.csproj @@ -9,6 +9,8 @@ SKIT.FlurlHttpClient.Wechat.Work + LOGO.png + README.md MIT https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat Flurl.Http Wechat Weixin MicroMessage WechatWork WeixinWork Wxwork 微信 企业微信 企业号 微信企业号 @@ -17,17 +19,28 @@ Fu Diwei git https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat.git - true - true - snupkg + + true + true + true + true + true + snupkg + + + + + + + - + \ No newline at end of file diff --git a/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/SHA1Utility.cs b/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/SHA1Utility.cs index 8fc8c6fd..13c9996b 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/SHA1Utility.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Work/Utilities/SHA1Utility.cs @@ -10,7 +10,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities public static class SHA1Utility { /// - /// 获取信息摘要。 + /// 获取 SHA-1 信息摘要。 /// /// 信息字节数组。 /// 信息摘要。 @@ -24,7 +24,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities } /// - /// 获取信息摘要。 + /// 获取 SHA-1 信息摘要。 /// /// 文本信息。 /// 信息摘要。 diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/SKIT.FlurlHttpClient.Wechat.Work.UnitTests.csproj b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/SKIT.FlurlHttpClient.Wechat.Work.UnitTests.csproj index 6825e4ff..9a53d103 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/SKIT.FlurlHttpClient.Wechat.Work.UnitTests.csproj +++ b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/SKIT.FlurlHttpClient.Wechat.Work.UnitTests.csproj @@ -1,8 +1,11 @@  - netcoreapp3.1; net6.0 - 9.0 + net472; netcoreapp3.1; net6.0 + latest + enable + true + false diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkExecuteCgibinTests.cs b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_ApiExecuteCgibinTests.cs similarity index 70% rename from test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkExecuteCgibinTests.cs rename to test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_ApiExecuteCgibinTests.cs index 83499250..a619952c 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkExecuteCgibinTests.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_ApiExecuteCgibinTests.cs @@ -7,10 +7,10 @@ using Xunit; namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests { - public class WechatWorkExecuteCgibinTests + public class TestCase_ApiExecuteCgibinTests { - [Fact(DisplayName = "[GET] /cgi-bin/gettoken")] - public async Task CgibinTokenTest() + [Fact(DisplayName = "测试用例:调用 API [GET] /cgi-bin/gettoken")] + public async Task TestExecuteCgibinToken() { var request = new Models.CgibinGetTokenRequest(); var response = await TestClients.Instance.ExecuteCgibinGetTokenAsync(request); diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkDeclarationTests.cs b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_CodeReviewAnalyzer.cs similarity index 51% rename from test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkDeclarationTests.cs rename to test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_CodeReviewAnalyzer.cs index f94fccf5..168d60a5 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkDeclarationTests.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_CodeReviewAnalyzer.cs @@ -9,25 +9,25 @@ using Xunit; namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests { - public class WechatWorkDeclarationTests + public class TestCase_CodeReviewAnalyzer { - private static readonly Assembly _assembly = Assembly.Load("SKIT.FlurlHttpClient.Wechat.Work"); + private Assembly SourceAssembly { get; } = Assembly.Load("SKIT.FlurlHttpClient.Wechat.Work"); - [Fact(DisplayName = "验证 API 模型命名")] - public void ApiModelsNamingTest() + [Fact(DisplayName = "代码评审:分析 API 模型命名")] + public void TestApiModelsNaming() { - CodeStyleUtil.VerifyApiModelsNaming(_assembly, out var ex); + CodeStyleUtil.VerifyApiModelsNaming(SourceAssembly, out var ex); if (ex != null) throw ex; Assert.Null(ex); } - [Fact(DisplayName = "验证 API 模型定义")] - public void ApiModelsDefinitionTest() + [Fact(DisplayName = "代码评审:分析 API 模型定义")] + public void TestApiModelsDefinition() { string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "ModelSamples"); - CodeStyleUtil.VerifyApiModelsDefinition(_assembly, workdir, out var ex); + CodeStyleUtil.VerifyApiModelsDefinition(SourceAssembly, workdir, out var ex); if (ex != null) throw ex; @@ -35,11 +35,11 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests Assert.Null(ex); } - [Fact(DisplayName = "验证 API 事件定义")] - public void ApiEventsDefinitionTest() + [Fact(DisplayName = "代码评审:分析 API 事件定义")] + public void TestApiEventsDefinition() { string workdir = Path.Combine(TestConfigs.ProjectTestDirectory, "EventSamples"); - CodeStyleUtil.VerifyApiEventsDefinition(_assembly, workdir, out var ex); + CodeStyleUtil.VerifyApiEventsDefinition(SourceAssembly, workdir, out var ex); if (ex != null) throw ex; @@ -47,10 +47,10 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests Assert.Null(ex); } - [Fact(DisplayName = "验证 API 接口命名")] - public void ApiExtensionsNamingTest() + [Fact(DisplayName = "代码评审:分析 API 接口命名")] + public void TestApiExtensionsNaming() { - CodeStyleUtil.VerifyApiExtensionsNaming(_assembly, out var ex); + CodeStyleUtil.VerifyApiExtensionsNaming(SourceAssembly, out var ex); if (ex != null) throw ex; @@ -58,8 +58,8 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests Assert.Null(ex); } - [Fact(DisplayName = "验证代码规范")] - public void CodeStyleTest() + [Fact(DisplayName = "代码评审:分析代码规范")] + public void TestCodeStyle() { string workdir = Path.Combine(TestConfigs.ProjectSourceDirectory); CodeStyleUtil.VerifySourceCodeStyle(workdir, out var ex); diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkEventDeserializationTests.cs b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_EventTests.cs similarity index 62% rename from test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkEventDeserializationTests.cs rename to test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_EventTests.cs index 46f33f17..53d6a9cc 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkEventDeserializationTests.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_EventTests.cs @@ -8,10 +8,10 @@ using Xunit; namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests { - public class WechatWorkEventDeserializationTests + public class TestCase_EventTests { - [Fact(DisplayName = "验签并解密回调数据")] - public void GetEventMessageTypeTest() + [Fact(DisplayName = "测试用例:验签并解密回调数据")] + public void TestDeserializeEventFromXml() { string callbacMsgSig = "477715d11cdb4164915debcba66cb864d751f3e6"; string callbacTimeStamp = "1409659813"; @@ -33,5 +33,25 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests Assert.Equal("wx5823bf96d3bd56c7", eventModel.ToUserName); Assert.Equal("mycreate", eventModel.FromUserName); } + + [Fact(DisplayName = "测试用例:验证微信服务器")] + public void TestVerifyEventSignatureForEcho() + { + string callbacMsgSig = "5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3"; + string callbacTimeStamp = "1409659589"; + string callbacNonce = "263014780"; + string callbackEcho = "P9nAzCzyDtyTWESHep1vC5X9xho/qYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp+4RPcs8TgAE7OaBO+FZXvnaqQ=="; + + var options = new WechatWorkClientOptions() + { + CorpId = "wx5823bf96d3bd56c7", + PushEncodingAESKey = "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C", + PushToken = "QDG6eK" + }; + var client = new WechatWorkClient(options); + + Assert.True(client.VerifyEventSignatureForEcho(callbacTimeStamp, callbacNonce, callbackEcho, callbacMsgSig, out string replyEcho)); + Assert.Equal("1616140317555161061", replyEcho); + } } } diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkUtilityTests.cs b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_WxBizMsgCryptorUtilityTests.cs similarity index 74% rename from test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkUtilityTests.cs rename to test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_WxBizMsgCryptorUtilityTests.cs index 63d1b28e..06e4049c 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkUtilityTests.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestCase_WxBizMsgCryptorUtilityTests.cs @@ -8,10 +8,10 @@ using Xunit; namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests { - public class WechatWorkUtilityTests + public class TestCase_WxBizMsgCryptorUtilityTests { - [Fact(DisplayName = "回调信息解析")] - public void WxBizMsgCryptorParsingTest() + [Fact(DisplayName = "测试用例:回调信息解析")] + public void TestWxBizMsgCryptorParsing() { string xml = ""; @@ -22,8 +22,22 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests Assert.Equal("RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==", encryptedMsg); } - [Fact(DisplayName = "回调信息验签")] - public void WxBizMsgCryptorSignatureTest() + [Fact(DisplayName = "测试用例:回调信息解密")] + public void TestWxBizMsgCryptorDecrypt() + { + string corpId = "wx5823bf96d3bd56c7"; + string encodingAESKey = "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C"; + string cipherText = "RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q=="; + + string actualCipherText = Utilities.WxBizMsgCryptor.AESDecrypt(cipherText, encodingAESKey, out string actualCorpId); + string expectedCipherText = "\n\n1409659813\n\n\n4561255354251345929\n218\n"; + + Assert.Equal(corpId, actualCorpId); + Assert.Equal(expectedCipherText, actualCipherText, ignoreCase: true); + } + + [Fact(DisplayName = "测试用例:回调信息生成签名")] + public void TestWxBizMsgCryptorGenerateSignature() { string token = "QDG6eK"; string timestamp = "1409659813"; @@ -37,18 +51,16 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests Assert.True(Utilities.WxBizMsgCryptor.VerifySignature(sToken: token, sTimestamp: timestamp, sNonce: nonce, sMsgEncrypt: cipherText, sMsgSign: expectedSignText)); } - [Fact(DisplayName = "回调信息解密")] - public void WxBizMsgCryptorDecryptTest() + [Fact(DisplayName = "测试用例:回调信息验证签名")] + public void TestWxBizMsgCryptorVerifySignature() { - string corpId = "wx5823bf96d3bd56c7"; - string encodingAESKey = "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C"; - string cipherText = "RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q=="; + string token = "ovAkP0Tb"; + string reqMsgSig = "8128e41a38892d814e4aa67753425da9dc8ec2b3"; + string reqTimeStamp = "1628737717"; + string reqNonce = "1811081856"; + string reqCipherText = "Q/jUxIL3/jRaFeTKesIr1QSq2SOEApDqlzcRrRM6Jlk4EbMBns3plPOR/W3gThOEq+zYI42fNSoIUb3cQwt9zyD1aLU/7D3WNLute7LQ9LSHjZEfVmx5zcIR9zvrUWGjhe1whTPH4e1WR6vbOYs8o/bDRF0vX/NcE4XK7P83Y6CzQiJoKbjVCne84s0zcw5eh+ZUDB55eaDHPSoS7kAC8kB00pfBoDF0jyfc8CUKLW97e72vJGyUWjZ0BvYN+R+tFjMgEzg/EN1imuuFnf40DMAcvB6y+C97TuaWjpgfRdowGWzn10JAFNukRfQqjdA0e2bfczJ7+t9w/t8/XSMADJOt1xbnP+I5cRX/r7ueBGmG/6ejP3myO9yTXHdujGvwrXHuWw+J7qD4VoUVjbm2vQ1qQKbrweKssr6O+3XSbanZ5R3n26EpN/gfgX+r6rcGViqsFop9Ai9xMnfJUubB6Q=="; - string actualCipherText = Utilities.WxBizMsgCryptor.AESDecrypt(cipherText, encodingAESKey, out string actualCorpId); - string expectedCipherText = "\n\n1409659813\n\n\n4561255354251345929\n218\n"; - - Assert.Equal(corpId, actualCorpId); - Assert.Equal(expectedCipherText, actualCipherText, ignoreCase: true); + Assert.True(Utilities.WxBizMsgCryptor.VerifySignature(token, reqTimeStamp, reqNonce, reqCipherText, reqMsgSig)); } } } diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestConfigs.cs b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestConfigs.cs index 720744f9..b68612f5 100644 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestConfigs.cs +++ b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/TestConfigs.cs @@ -8,8 +8,9 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests { static TestConfigs() { - // NOTICE: 请在项目根目录下按照 appsettings.json 的格式新建 appsettings.local.json 填入测试参数。 - // WARN: 敏感信息请不要提交到 git! + // NOTICE: 请在项目根目录下按照 appsettings.json 的格式新建 appsettings.local.json 填入测试参数。 + // WARNING: 请在 DEBUG 模式下运行测试用例。 + // WARNING: 敏感信息请不要提交到 git! try { @@ -17,12 +18,12 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests using var jdoc = JsonDocument.Parse(stream); var config = jdoc.RootElement.GetProperty("TestConfig"); - WechatCorpId = config.GetProperty("CorpId").GetString(); - WechatAgentId = int.Parse(config.GetProperty("AgentId").GetString()); - WechatAgentSecret = config.GetProperty("AgentSecret").GetString(); + WechatCorpId = config.GetProperty("CorpId").GetString()!; + WechatAgentId = int.Parse(config.GetProperty("AgentId").GetString())!; + WechatAgentSecret = config.GetProperty("AgentSecret").GetString()!; - ProjectSourceDirectory = jdoc.RootElement.GetProperty("ProjectSourceDirectory").GetString(); - ProjectTestDirectory = jdoc.RootElement.GetProperty("ProjectTestDirectory").GetString(); + ProjectSourceDirectory = jdoc.RootElement.GetProperty("ProjectSourceDirectory").GetString()!; + ProjectTestDirectory = jdoc.RootElement.GetProperty("ProjectTestDirectory").GetString()!; } catch (Exception ex) { diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkEventVerificationTests.cs b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkEventVerificationTests.cs deleted file mode 100644 index 6beff27f..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkEventVerificationTests.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Xml.Linq; -using Xunit; - -namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests -{ - public class WechatWorkEventVerificationTests - { - [Fact(DisplayName = "验证微信服务器")] - public void GetEventMessageTypeTest() - { - string callbacMsgSig = "5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3"; - string callbacTimeStamp = "1409659589"; - string callbacNonce = "263014780"; - string callbackEcho = "P9nAzCzyDtyTWESHep1vC5X9xho/qYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp+4RPcs8TgAE7OaBO+FZXvnaqQ=="; - - var options = new WechatWorkClientOptions() - { - CorpId = "wx5823bf96d3bd56c7", - PushEncodingAESKey = "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C", - PushToken = "QDG6eK" - }; - var client = new WechatWorkClient(options); - - Assert.True(client.VerifyEventSignatureForEcho(callbacTimeStamp, callbacNonce, callbackEcho, callbacMsgSig, out string replyEcho)); - Assert.Equal("1616140317555161061", replyEcho); - } - } -} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkWxBizMsgCryptorTests.cs b/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkWxBizMsgCryptorTests.cs deleted file mode 100644 index 13b8722c..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.Work.UnitTests/WechatWorkWxBizMsgCryptorTests.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Xunit; - -namespace SKIT.FlurlHttpClient.Wechat.Work.UnitTests -{ - public class WechatWorkWxBizMsgCryptorTests - { - [Fact(DisplayName = "验签回调数据")] - public void VerifyEventTest() - { - string token = "ovAkP0Tb"; - string reqMsgSig = "8128e41a38892d814e4aa67753425da9dc8ec2b3"; - string reqTimeStamp = "1628737717"; - string reqNonce = "1811081856"; - string reqCipherText = "Q/jUxIL3/jRaFeTKesIr1QSq2SOEApDqlzcRrRM6Jlk4EbMBns3plPOR/W3gThOEq+zYI42fNSoIUb3cQwt9zyD1aLU/7D3WNLute7LQ9LSHjZEfVmx5zcIR9zvrUWGjhe1whTPH4e1WR6vbOYs8o/bDRF0vX/NcE4XK7P83Y6CzQiJoKbjVCne84s0zcw5eh+ZUDB55eaDHPSoS7kAC8kB00pfBoDF0jyfc8CUKLW97e72vJGyUWjZ0BvYN+R+tFjMgEzg/EN1imuuFnf40DMAcvB6y+C97TuaWjpgfRdowGWzn10JAFNukRfQqjdA0e2bfczJ7+t9w/t8/XSMADJOt1xbnP+I5cRX/r7ueBGmG/6ejP3myO9yTXHdujGvwrXHuWw+J7qD4VoUVjbm2vQ1qQKbrweKssr6O+3XSbanZ5R3n26EpN/gfgX+r6rcGViqsFop9Ai9xMnfJUubB6Q=="; - - Assert.True(Utilities.WxBizMsgCryptor.VerifySignature(token, reqTimeStamp, reqNonce, reqCipherText, reqMsgSig)); - } - } -}