diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs index a87add029e..0d571aa0e8 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Extensions.Options; @@ -20,7 +21,28 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - return _clock.Normalize(reader.GetDateTime()); + if (!_options.DefaultDateTimeFormat.IsNullOrWhiteSpace()) + { + if (reader.TokenType == JsonTokenType.String) + { + var s = reader.GetString(); + if (DateTime.TryParseExact(s, _options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1)) + { + return _clock.Normalize(d1); + } + + throw new JsonException($"'{s}' can't parse to DateTime({_options.DefaultDateTimeFormat})!"); + } + + throw new JsonException("Reader's TokenType is not String!"); + } + + if (reader.TryGetDateTime(out var d2)) + { + return _clock.Normalize(d2); + } + + throw new JsonException("Can't get datetime from the reader!"); } public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) @@ -31,7 +53,7 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters } else { - writer.WriteStringValue(_clock.Normalize(value).ToString(_options.DefaultDateTimeFormat)); + writer.WriteStringValue(_clock.Normalize(value).ToString(_options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture)); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs index 40227dd5c3..47640ec306 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs @@ -16,15 +16,21 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters x.GetType() == typeof(AbpHasExtraPropertiesJsonConverterFactory)); var rootElement = JsonDocument.ParseValue(ref reader).RootElement; - var extensibleObject = JsonSerializer.Deserialize(rootElement.GetRawText(), newOptions); + if (rootElement.ValueKind == JsonValueKind.Object) + { + var extensibleObject = JsonSerializer.Deserialize(rootElement.GetRawText(), newOptions); - var extraProperties = rootElement.EnumerateObject().FirstOrDefault(x => - x.Name.Equals(nameof(IHasExtraProperties.ExtraProperties), StringComparison.OrdinalIgnoreCase)) - .Value.GetRawText(); - var extraPropertyDictionary = JsonSerializer.Deserialize(extraProperties, typeof(ExtraPropertyDictionary), newOptions); - ObjectHelper.TrySetProperty(extensibleObject, x => x.ExtraProperties, () => extraPropertyDictionary); + var extraPropertiesJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IHasExtraProperties.ExtraProperties), StringComparison.OrdinalIgnoreCase)); + if (extraPropertiesJsonProperty.Value.ValueKind == JsonValueKind.Object) + { + var extraPropertyDictionary = JsonSerializer.Deserialize(extraPropertiesJsonProperty.Value.GetRawText(), typeof(ExtraPropertyDictionary), newOptions); + ObjectHelper.TrySetProperty(extensibleObject, x => x.ExtraProperties, () => extraPropertyDictionary); + } - return extensibleObject; + return extensibleObject; + } + + throw new JsonException("RootElement's ValueKind is not Object!"); } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs index bad650b4d8..ad9e6cb52a 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Extensions.Options; @@ -20,9 +21,25 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TryGetDateTime(out var dateTime)) + if (!_options.DefaultDateTimeFormat.IsNullOrWhiteSpace()) { - return _clock.Normalize(dateTime); + if (reader.TokenType == JsonTokenType.String) + { + var s = reader.GetString(); + if (DateTime.TryParseExact(s, _options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1)) + { + return _clock.Normalize(d1); + } + + throw new JsonException($"'{s}' can't parse to DateTime({_options.DefaultDateTimeFormat})!"); + } + + throw new JsonException("Reader's TokenType is not String!"); + } + + if (reader.TryGetDateTime(out var d2)) + { + return _clock.Normalize(d2); } return null; @@ -42,7 +59,7 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters } else { - writer.WriteStringValue(_clock.Normalize(value.Value).ToString(_options.DefaultDateTimeFormat)); + writer.WriteStringValue(_clock.Normalize(value.Value).ToString(_options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture)); } } } diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs index da49f7ebc6..3f7ce5dc26 100644 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs @@ -1,30 +1,89 @@ -using Shouldly; +using System; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; using Volo.Abp.Data; using Volo.Abp.Json.SystemTextJson; using Volo.Abp.ObjectExtending; +using Volo.Abp.Timing; using Xunit; namespace Volo.Abp.Json { - public class AbpSystemTextJsonSerializerProvider_Tests : AbpJsonTestBase + public abstract class AbpSystemTextJsonSerializerProvider_TestBase : AbpJsonTestBase { - private readonly AbpSystemTextJsonSerializerProvider _jsonSerializer; + protected AbpSystemTextJsonSerializerProvider JsonSerializer; - public AbpSystemTextJsonSerializerProvider_Tests() + public AbpSystemTextJsonSerializerProvider_TestBase() { - _jsonSerializer = GetRequiredService(); + JsonSerializer = GetRequiredService(); } + public class TestExtensibleObjectClass : ExtensibleObject + { + public string Name { get; set; } + } + + public class FileWithBoolean + { + public string Name { get; set; } + + public bool IsDeleted { get; set; } + } + + public class FileWithNullableBoolean + { + public string Name { get; set; } + + public bool? IsDeleted { get; set; } + } + + public class FileWithEnum + { + public string Name { get; set; } + + public FileType Type { get; set; } + } + + public class FileWithNullableEnum + { + public string Name { get; set; } + + public FileType? Type { get; set; } + } + + public enum FileType + { + Zip = 0, + Exe = 2 + } + + public class FileWithDatetime + { + public string Name { get; set; } + + public DateTime CreationTime { get; set; } + } + + public class FileWithNullableDatetime + { + public string Name { get; set; } + + public DateTime? CreationTime { get; set; } + } + } + + public class AbpSystemTextJsonSerializerProvider_Tests : AbpSystemTextJsonSerializerProvider_TestBase + { [Fact] public void Serialize_Deserialize_With_Boolean() { var json = "{\"name\":\"abp\",\"IsDeleted\":\"fAlSe\"}"; - var file = _jsonSerializer.Deserialize(json); + var file = JsonSerializer.Deserialize(json); file.Name.ShouldBe("abp"); file.IsDeleted.ShouldBeFalse(); file.IsDeleted = false; - var newJson = _jsonSerializer.Serialize(file); + var newJson = JsonSerializer.Serialize(file); newJson.ShouldBe("{\"name\":\"abp\",\"isDeleted\":false}"); } @@ -32,19 +91,19 @@ namespace Volo.Abp.Json public void Serialize_Deserialize_With_Nullable_Boolean() { var json = "{\"name\":\"abp\",\"IsDeleted\":null}"; - var file = _jsonSerializer.Deserialize(json); + var file = JsonSerializer.Deserialize(json); file.Name.ShouldBe("abp"); file.IsDeleted.ShouldBeNull(); - var newJson = _jsonSerializer.Serialize(file); + var newJson = JsonSerializer.Serialize(file); newJson.ShouldBe("{\"name\":\"abp\",\"isDeleted\":null}"); json = "{\"name\":\"abp\",\"IsDeleted\":\"true\"}"; - file = _jsonSerializer.Deserialize(json); + file = JsonSerializer.Deserialize(json); file.IsDeleted.ShouldNotBeNull(); file.IsDeleted.Value.ShouldBeTrue(); - newJson = _jsonSerializer.Serialize(file); + newJson = JsonSerializer.Serialize(file); newJson.ShouldBe("{\"name\":\"abp\",\"isDeleted\":true}"); } @@ -52,11 +111,11 @@ namespace Volo.Abp.Json public void Serialize_Deserialize_With_Enum() { var json = "{\"name\":\"abp\",\"type\":\"Exe\"}"; - var file = _jsonSerializer.Deserialize(json); + var file = JsonSerializer.Deserialize(json); file.Name.ShouldBe("abp"); file.Type.ShouldBe(FileType.Exe); - var newJson = _jsonSerializer.Serialize(file); + var newJson = JsonSerializer.Serialize(file); newJson.ShouldBe("{\"name\":\"abp\",\"type\":2}"); } @@ -64,72 +123,178 @@ namespace Volo.Abp.Json public void Serialize_Deserialize_With_Nullable_Enum() { var json = "{\"name\":\"abp\",\"type\":null}"; - var file = _jsonSerializer.Deserialize(json); + var file = JsonSerializer.Deserialize(json); file.Name.ShouldBe("abp"); file.Type.ShouldBeNull(); - var newJson = _jsonSerializer.Serialize(file); + var newJson = JsonSerializer.Serialize(file); newJson.ShouldBe("{\"name\":\"abp\",\"type\":null}"); json = "{\"name\":\"abp\",\"type\":\"Exe\"}"; - file = _jsonSerializer.Deserialize(json); + file = JsonSerializer.Deserialize(json); file.Type.ShouldNotBeNull(); file.Type.ShouldBe(FileType.Exe); - newJson = _jsonSerializer.Serialize(file); + newJson = JsonSerializer.Serialize(file); newJson.ShouldBe("{\"name\":\"abp\",\"type\":2}"); } - [Fact] public void Serialize_Deserialize_ExtensibleObject() { var json = "{\"name\":\"test\",\"extraProperties\":{\"One\":\"123\",\"Two\":456}}"; - var extensibleObject = _jsonSerializer.Deserialize(json); + var extensibleObject = JsonSerializer.Deserialize(json); extensibleObject.GetProperty("One").ShouldBe("123"); extensibleObject.GetProperty("Two").ShouldBe(456); - var newJson = _jsonSerializer.Serialize(extensibleObject); + var newJson = JsonSerializer.Serialize(extensibleObject); newJson.ShouldBe(json); } - class TestExtensibleObjectClass : ExtensibleObject + [Fact] + public void Serialize_Deserialize_ExtensibleObject_Without_String() { - public string Name { get; set; } + var json = "{\"name\":\"test\"}"; + var extensibleObject = JsonSerializer.Deserialize(json); + extensibleObject.ExtraProperties.ShouldNotBeNull(); + extensibleObject.ExtraProperties.ShouldBeEmpty(); } - class FileWithBoolean + [Fact] + public void Serialize_Deserialize_ExtensibleObject_Without_Empty() { - public string Name { get; set; } + var json = "{\"name\":\"test\",\"extraProperties\":{}}"; + var extensibleObject = JsonSerializer.Deserialize(json); + extensibleObject.ExtraProperties.ShouldNotBeNull(); + extensibleObject.ExtraProperties.ShouldBeEmpty(); + } - public bool IsDeleted { get; set; } + [Fact] + public void Serialize_Deserialize_ExtensibleObject_Without_Null() + { + var json = "{\"name\":\"test\",\"extraProperties\":null}"; + var extensibleObject = JsonSerializer.Deserialize(json); + extensibleObject.ExtraProperties.ShouldNotBeNull(); + extensibleObject.ExtraProperties.ShouldBeEmpty(); } - class FileWithNullableBoolean + [Fact] + public void Serialize_Deserialize_With_Datetime() { - public string Name { get; set; } + var json = "{\"name\":\"abp\",\"creationTime\":\"2020-11-20T00:00:00\"}"; + var file = JsonSerializer.Deserialize(json); + file.CreationTime.Year.ShouldBe(2020); + file.CreationTime.Month.ShouldBe(11); + file.CreationTime.Day.ShouldBe(20); - public bool? IsDeleted { get; set; } + var newJson = JsonSerializer.Serialize(file); + newJson.ShouldBe(json); } - class FileWithEnum + [Fact] + public void Serialize_Deserialize_With_Nullable_Datetime() { - public string Name { get; set; } + var json = "{\"name\":\"abp\",\"creationTime\":null}"; + var file = JsonSerializer.Deserialize(json); + file.CreationTime.ShouldBeNull(); - public FileType Type { get; set; } + json = "{\"name\":\"abp\"}"; + file = JsonSerializer.Deserialize(json); + file.CreationTime.ShouldBeNull(); + + json = "{\"name\":\"abp\",\"creationTime\":\"2020-11-20T00:00:00\"}"; + file = JsonSerializer.Deserialize(json); + file.CreationTime.ShouldNotBeNull(); + + file.CreationTime.Value.Year.ShouldBe(2020); + file.CreationTime.Value.Month.ShouldBe(11); + file.CreationTime.Value.Day.ShouldBe(20); + + var newJson = JsonSerializer.Serialize(file); + newJson.ShouldBe(json); } + } - class FileWithNullableEnum + public class AbpSystemTextJsonSerializerProvider_DateTimeFormat_Tests : AbpSystemTextJsonSerializerProvider_TestBase + { + protected override void AfterAddApplication(IServiceCollection services) { - public string Name { get; set; } + services.Configure(options => + { + options.DefaultDateTimeFormat = "yyyy*MM*dd"; + }); + } - public FileType? Type { get; set; } + [Fact] + public void Serialize_Deserialize_With_Format_Datetime() + { + var json = "{\"name\":\"abp\",\"creationTime\":\"2020*11*20\"}"; + var file = JsonSerializer.Deserialize(json); + file.CreationTime.Year.ShouldBe(2020); + file.CreationTime.Month.ShouldBe(11); + file.CreationTime.Day.ShouldBe(20); + + var newJson = JsonSerializer.Serialize(file); + newJson.ShouldBe(json); } - enum FileType + [Fact] + public void Serialize_Deserialize_With_Nullable_Format_Datetime() { - Zip = 0, - Exe = 2 + var json = "{\"name\":\"abp\",\"creationTime\":null}"; + var file = JsonSerializer.Deserialize(json); + file.CreationTime.ShouldBeNull(); + + json = "{\"name\":\"abp\"}"; + file = JsonSerializer.Deserialize(json); + file.CreationTime.ShouldBeNull(); + + json = "{\"name\":\"abp\",\"creationTime\":\"2020*11*20\"}"; + file = JsonSerializer.Deserialize(json); + file.CreationTime.ShouldNotBeNull(); + + file.CreationTime.Value.Year.ShouldBe(2020); + file.CreationTime.Value.Month.ShouldBe(11); + file.CreationTime.Value.Day.ShouldBe(20); + + var newJson = JsonSerializer.Serialize(file); + newJson.ShouldBe(json); } } + + public abstract class AbpSystemTextJsonSerializerProvider_Datetime_Kind_Tests : AbpSystemTextJsonSerializerProvider_TestBase + { + protected DateTimeKind Kind { get; set; } = DateTimeKind.Unspecified; + + [Fact] + public void Serialize_Deserialize() + { + var json = "{\"name\":\"abp\",\"creationTime\":\"2020-11-20T00:00:00\"}"; + var file = JsonSerializer.Deserialize(json); + file.CreationTime.Kind.ShouldBe(Kind); + } + } + + public class AbpSystemTextJsonSerializerProvider_Datetime_Kind_UTC_Tests : AbpSystemTextJsonSerializerProvider_Datetime_Kind_Tests + { + protected override void AfterAddApplication(IServiceCollection services) + { + Kind = DateTimeKind.Utc; + services.Configure(x => x.Kind = Kind); + } + } + + public class AbpSystemTextJsonSerializerProvider_Datetime_Kind_Local_Tests : AbpSystemTextJsonSerializerProvider_Datetime_Kind_Tests + { + protected override void AfterAddApplication(IServiceCollection services) + { + Kind = DateTimeKind.Local; + services.Configure(x => x.Kind = Kind); + } + } + + public class AbpSystemTextJsonSerializerProvider_Datetime_Kind_Unspecified_Tests : AbpSystemTextJsonSerializerProvider_Datetime_Kind_Tests + { + + } } diff --git a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs index fbc222a46a..6d21074e92 100644 --- a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs +++ b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs @@ -6,21 +6,28 @@ using Volo.Abp.Domain.Entities; namespace Volo.Abp.MemoryDb.JsonConverters { public class EntityJsonConverter : JsonConverter - where TEntity : IEntity + where TEntity : Entity { public override TEntity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var jsonDocument = JsonDocument.ParseValue(ref reader); - var entity = (TEntity)JsonSerializer.Deserialize(jsonDocument.RootElement.GetRawText(), typeToConvert); - var idJsonElement = jsonDocument.RootElement.GetProperty(nameof(IEntity.Id)); - - var id = JsonSerializer.Deserialize(idJsonElement.GetRawText()); - if (id != null) + if (jsonDocument.RootElement.ValueKind == JsonValueKind.Object) { - EntityHelper.TrySetId(entity, () => id); + var entity = (TEntity)JsonSerializer.Deserialize(jsonDocument.RootElement.GetRawText(), typeToConvert); + + var idJsonElement = jsonDocument.RootElement.GetProperty(nameof(Entity.Id)); + if (idJsonElement.ValueKind != JsonValueKind.Undefined) + { + var id = JsonSerializer.Deserialize(idJsonElement.GetRawText()); + if (id != null) + { + EntityHelper.TrySetId(entity, () => id); + } + } + return entity; } - return entity; + throw new JsonException("RootElement's ValueKind is not Object!"); } public override void Write(Utf8JsonWriter writer, TEntity value, JsonSerializerOptions options) diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemSourceJsonConverter.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemSourceJsonConverter.cs index 3a05e3f63f..bae37dbff9 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemSourceJsonConverter.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemSourceJsonConverter.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; @@ -11,16 +10,22 @@ namespace Volo.Abp.FeatureManagement.JsonConverters { public override ISelectionStringValueItemSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - var newOptions = JsonSerializerOptionsHelper.Create(options, this); - var rootElement = JsonDocument.ParseValue(ref reader).RootElement; - var items = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(ISelectionStringValueItemSource.Items), StringComparison.OrdinalIgnoreCase)).Value.GetRawText(); + var itemsJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => + x.Name.Equals(nameof(ISelectionStringValueItemSource.Items), StringComparison.OrdinalIgnoreCase)); + + if (itemsJsonProperty.Value.ValueKind == JsonValueKind.Array) + { + var newOptions = JsonSerializerOptionsHelper.Create(options, this); + + var selectionStringValueItem = + JsonSerializer.Deserialize(itemsJsonProperty.Value.GetRawText(), newOptions) ?? + Array.Empty(); - var selectionStringValueItem = - JsonSerializer.Deserialize>(items, newOptions) ?? - new List(); + return new StaticSelectionStringValueItemSource(selectionStringValueItem.As()); + } - return new StaticSelectionStringValueItemSource(selectionStringValueItem.ToArray().As()); + throw new JsonException($"Can't to get the {nameof(ISelectionStringValueItemSource.Items)} property of {nameof(ISelectionStringValueItemSource)}!"); } public override void Write(Utf8JsonWriter writer, ISelectionStringValueItemSource value, JsonSerializerOptions options) diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs index 08ba6326b9..0d2196e911 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs @@ -11,15 +11,25 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public override IStringValueType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var rootElement = JsonDocument.ParseValue(ref reader).RootElement; - var name = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IStringValueType.Name), StringComparison.OrdinalIgnoreCase)).Value.GetString(); - var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ValueValidatorJsonConverter(), new SelectionStringValueItemSourceJsonConverter()); - return name switch + + var nameJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IStringValueType.Name), StringComparison.OrdinalIgnoreCase)); + if (nameJsonProperty.Value.ValueKind == JsonValueKind.String) { - "SelectionStringValueType" => JsonSerializer.Deserialize(rootElement.GetRawText(), newOptions), - "FreeTextStringValueType" => JsonSerializer.Deserialize(rootElement.GetRawText(), newOptions), - "ToggleStringValueType" => JsonSerializer.Deserialize(rootElement.GetRawText(), newOptions), - _ => throw new ArgumentException($"{nameof(IStringValueType)} named {name} was not found!") - }; + var name = nameJsonProperty.Value.GetString(); + + var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ValueValidatorJsonConverter(), + new SelectionStringValueItemSourceJsonConverter()); + + return name switch + { + "SelectionStringValueType" => JsonSerializer.Deserialize(rootElement.GetRawText(), newOptions), + "FreeTextStringValueType" => JsonSerializer.Deserialize(rootElement.GetRawText(), newOptions), + "ToggleStringValueType" => JsonSerializer.Deserialize(rootElement.GetRawText(), newOptions), + _ => throw new ArgumentException($"{nameof(IStringValueType)} named {name} was not found!") + }; + } + + throw new JsonException($"Can't to get the {nameof(IStringValueType.Name)} property of {nameof(IStringValueType)}!"); } public override void Write(Utf8JsonWriter writer, IStringValueType value, JsonSerializerOptions options) diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs index 98c1013c12..25bb603c1a 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs @@ -13,21 +13,30 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public override IValueValidator Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var rootElement = JsonDocument.ParseValue(ref reader).RootElement; - var name = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Name), StringComparison.OrdinalIgnoreCase)).Value.GetString(); - var valueValidator = CreateValueValidatorByName(name); - var propertiesRawText = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Properties), StringComparison.OrdinalIgnoreCase)).Value.GetRawText(); - var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ObjectToInferredTypesConverter()); - var properties = JsonSerializer.Deserialize>(propertiesRawText, newOptions); - if (properties != null && properties.Any()) + var nameJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Name), StringComparison.OrdinalIgnoreCase)); + if (nameJsonProperty.Value.ValueKind == JsonValueKind.String) { - foreach (var property in properties) + var valueValidator = CreateValueValidatorByName(nameJsonProperty.Value.GetString()); + + var propertiesJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Properties), StringComparison.OrdinalIgnoreCase)); + if (propertiesJsonProperty.Value.ValueKind == JsonValueKind.Object) { - valueValidator.Properties[property.Key] = property.Value; + var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ObjectToInferredTypesConverter()); + var properties = JsonSerializer.Deserialize>(propertiesJsonProperty.Value.GetRawText(), newOptions); + if (properties != null && properties.Any()) + { + foreach (var property in properties) + { + valueValidator.Properties[property.Key] = property.Value; + } + } } + + return valueValidator; } - return valueValidator; + throw new JsonException($"Can't to get the {nameof(IValueValidator.Name)} property of {nameof(IValueValidator)}!"); } public override void Write(Utf8JsonWriter writer, IValueValidator value, JsonSerializerOptions options) diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs index c72cbddffd..0a96027317 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs @@ -60,6 +60,14 @@ namespace Volo.Abp.FeatureManagement MinValue = 10 } } + }, + new FeatureDto + { + Provider = new FeatureProviderDto + { + Name = "FeatureName", + Key = "FeatureKey" + } } } } @@ -85,6 +93,9 @@ namespace Volo.Abp.FeatureManagement featureListDto2.Groups[0].Features[2].ValueType.Validator.ShouldBeOfType(); featureListDto2.Groups[0].Features[2].ValueType.Validator.As().MaxValue.ShouldBe(1000); featureListDto2.Groups[0].Features[2].ValueType.Validator.As().MinValue.ShouldBe(10); + + featureListDto2.Groups[0].Features[3].Provider.Name.ShouldBe("FeatureName"); + featureListDto2.Groups[0].Features[3].Provider.Key.ShouldBe("FeatureKey"); } } }