From 21174b42613438647d33adef5e6843e839919cbd Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 29 Nov 2021 17:13:03 +0800 Subject: [PATCH 1/7] Reuse JsonSerializerOptions instances. Resolve #10745 --- .../AbpHasExtraPropertiesJsonConverter.cs | 28 ++++++++----------- ...pHasExtraPropertiesJsonConverterFactory.cs | 5 ---- .../AbpStringToBooleanConverter.cs | 11 +++++--- .../AbpStringToEnumConverter.cs | 18 +++++++----- .../JsonConverters/EntityJsonConverter.cs | 6 ++-- ...ctionStringValueItemSourceJsonConverter.cs | 12 +++++--- .../StringValueTypeJsonConverter.cs | 17 ++++++----- .../ValueValidatorJsonConverter.cs | 12 +++++--- .../Pages/Identity/Users/index.js | 7 +++++ 9 files changed, 67 insertions(+), 49 deletions(-) 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 792b96144e..0d75a04eed 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 @@ -9,31 +9,27 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters public class AbpHasExtraPropertiesJsonConverter : JsonConverter where T : IHasExtraProperties { + private JsonSerializerOptions _readJsonSerializerOptions; + + private JsonSerializerOptions _writeJsonSerializerOptions; + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - var newOptions = JsonSerializerOptionsHelper.Create(options, x => x == this); - - var converterFactory = newOptions.Converters.FirstOrDefault(x => x is AbpHasExtraPropertiesJsonConverterFactory).As(); - var newConverterFactory = new AbpHasExtraPropertiesJsonConverterFactory(); - if (converterFactory != null) - { - newOptions.Converters.Remove(converterFactory); - newConverterFactory.AddExcludeTypes(converterFactory.GetExcludeTypes().ToArray()); - } - - newConverterFactory.AddExcludeTypes(typeToConvert); - newOptions.Converters.Add(newConverterFactory); + _readJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, x => x == this); + + var converterFactory = _readJsonSerializerOptions.Converters.FirstOrDefault(x => x is AbpHasExtraPropertiesJsonConverterFactory); + converterFactory?.As().AddExcludeTypes(typeToConvert); var rootElement = JsonDocument.ParseValue(ref reader).RootElement; if (rootElement.ValueKind == JsonValueKind.Object) { - var extensibleObject = rootElement.Deserialize(newOptions); + var extensibleObject = rootElement.Deserialize(_readJsonSerializerOptions); var extraPropertiesJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IHasExtraProperties.ExtraProperties), StringComparison.OrdinalIgnoreCase)); if (extraPropertiesJsonProperty.Value.ValueKind == JsonValueKind.Object) { - var extraPropertyDictionary = extraPropertiesJsonProperty.Value.Deserialize(typeof(ExtraPropertyDictionary), newOptions); + var extraPropertyDictionary = extraPropertiesJsonProperty.Value.Deserialize(typeof(ExtraPropertyDictionary), _readJsonSerializerOptions); ObjectHelper.TrySetProperty(extensibleObject, x => x.ExtraProperties, () => extraPropertyDictionary); } @@ -45,11 +41,11 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { - var newOptions = JsonSerializerOptionsHelper.Create(options, x => + _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, x => x == this || x.GetType() == typeof(AbpHasExtraPropertiesJsonConverterFactory)); - JsonSerializer.Serialize(writer, value, newOptions); + JsonSerializer.Serialize(writer, value, _writeJsonSerializerOptions); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs index dff25e00df..dfe95b85c9 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs @@ -21,11 +21,6 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters return this; } - public virtual IReadOnlyList GetExcludeTypes() - { - return _excludeTypes.ToImmutableList(); - } - public override bool CanConvert(Type typeToConvert) { if (_excludeTypes.Contains(typeToConvert)) diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs index cfd5c17653..2cfa03677c 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs @@ -7,7 +7,9 @@ using System.Text.Json.Serialization; namespace Volo.Abp.Json.SystemTextJson.JsonConverters { public class AbpStringToBooleanConverter : JsonConverter - { + { + private JsonSerializerOptions _writeJsonSerializerOptions; + public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String) @@ -29,9 +31,10 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options) { - var newOptions = JsonSerializerOptionsHelper.Create(options, this); - var entityConverter = (JsonConverter)newOptions.GetConverter(typeof(bool)); - entityConverter.Write(writer, value, newOptions); + _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this); + var entityConverter = (JsonConverter)_writeJsonSerializerOptions.GetConverter(typeof(bool)); + + entityConverter.Write(writer, value, _writeJsonSerializerOptions); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs index 6aad6dd8df..8b99b48301 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs @@ -10,6 +10,10 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters { private readonly JsonStringEnumConverter _innerJsonStringEnumConverter; + private JsonSerializerOptions _readJsonSerializerOptions; + + private JsonSerializerOptions _writeJsonSerializerOptions; + public AbpStringToEnumConverter() : this(namingPolicy: null, allowIntegerValues: true) { @@ -28,21 +32,21 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - var newOptions = JsonSerializerOptionsHelper.Create(options, x => - x == this || - x.GetType() == typeof(AbpStringToEnumFactory)); + _readJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, x => + x == this || + x.GetType() == typeof(AbpStringToEnumFactory), + _innerJsonStringEnumConverter.CreateConverter(typeToConvert, options)); - newOptions.Converters.Add(_innerJsonStringEnumConverter.CreateConverter(typeToConvert, newOptions)); - return JsonSerializer.Deserialize(ref reader, newOptions); + return JsonSerializer.Deserialize(ref reader, _readJsonSerializerOptions); } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { - var newOptions = JsonSerializerOptionsHelper.Create(options, x => + _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, x => x == this || x.GetType() == typeof(AbpStringToEnumFactory)); - JsonSerializer.Serialize(writer, value, newOptions); + JsonSerializer.Serialize(writer, value, _writeJsonSerializerOptions); } } } 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 2a26c6ee42..59e550dd92 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 @@ -8,6 +8,8 @@ namespace Volo.Abp.MemoryDb.JsonConverters public class EntityJsonConverter : JsonConverter where TEntity : Entity { + private JsonSerializerOptions _writeJsonSerializerOptions; + public override TEntity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var jsonDocument = JsonDocument.ParseValue(ref reader); @@ -32,8 +34,8 @@ namespace Volo.Abp.MemoryDb.JsonConverters public override void Write(Utf8JsonWriter writer, TEntity value, JsonSerializerOptions options) { - var newOptions = JsonSerializerOptionsHelper.Create(options, this); - JsonSerializer.Serialize(writer, value, newOptions); + _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this); + JsonSerializer.Serialize(writer, value, _writeJsonSerializerOptions); } } } 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 9d62f9952c..9ec2c47e36 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 @@ -8,6 +8,10 @@ namespace Volo.Abp.FeatureManagement.JsonConverters { public class SelectionStringValueItemSourceJsonConverter : JsonConverter { + private JsonSerializerOptions _readJsonSerializerOptions; + + private JsonSerializerOptions _writeJsonSerializerOptions; + public override ISelectionStringValueItemSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var rootElement = JsonDocument.ParseValue(ref reader).RootElement; @@ -16,10 +20,10 @@ namespace Volo.Abp.FeatureManagement.JsonConverters if (itemsJsonProperty.Value.ValueKind == JsonValueKind.Array) { - var newOptions = JsonSerializerOptionsHelper.Create(options, this); + _readJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this); var selectionStringValueItem = - itemsJsonProperty.Value.Deserialize(newOptions) ?? + itemsJsonProperty.Value.Deserialize(_readJsonSerializerOptions) ?? Array.Empty(); return new StaticSelectionStringValueItemSource(selectionStringValueItem.As()); @@ -30,8 +34,8 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public override void Write(Utf8JsonWriter writer, ISelectionStringValueItemSource value, JsonSerializerOptions options) { - var newOptions = JsonSerializerOptionsHelper.Create(options, this); - JsonSerializer.Serialize(writer, value, value.GetType(), newOptions); + _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this); + JsonSerializer.Serialize(writer, value, value.GetType(), _writeJsonSerializerOptions); } } } 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 408ef2f99b..4802f28474 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 @@ -8,6 +8,10 @@ namespace Volo.Abp.FeatureManagement.JsonConverters { public class StringValueTypeJsonConverter : JsonConverter { + private JsonSerializerOptions _readJsonSerializerOptions; + + private JsonSerializerOptions _writeJsonSerializerOptions; + public override IStringValueType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var rootElement = JsonDocument.ParseValue(ref reader).RootElement; @@ -17,14 +21,13 @@ namespace Volo.Abp.FeatureManagement.JsonConverters { var name = nameJsonProperty.Value.GetString(); - var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ValueValidatorJsonConverter(), - new SelectionStringValueItemSourceJsonConverter()); + _readJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this, new ValueValidatorJsonConverter(), new SelectionStringValueItemSourceJsonConverter()); return name switch { - "SelectionStringValueType" => rootElement.Deserialize(newOptions), - "FreeTextStringValueType" => rootElement.Deserialize(newOptions), - "ToggleStringValueType" => rootElement.Deserialize(newOptions), + "SelectionStringValueType" => rootElement.Deserialize(_readJsonSerializerOptions), + "FreeTextStringValueType" => rootElement.Deserialize(_readJsonSerializerOptions), + "ToggleStringValueType" => rootElement.Deserialize(_readJsonSerializerOptions), _ => throw new ArgumentException($"{nameof(IStringValueType)} named {name} was not found!") }; } @@ -34,8 +37,8 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public override void Write(Utf8JsonWriter writer, IStringValueType value, JsonSerializerOptions options) { - var newOptions = JsonSerializerOptionsHelper.Create(options, this); - JsonSerializer.Serialize(writer, value, value.GetType(), newOptions); + _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this); + JsonSerializer.Serialize(writer, value, value.GetType(), _writeJsonSerializerOptions); } } } 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 27f92cc0ec..d42265f2c5 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 @@ -10,6 +10,10 @@ namespace Volo.Abp.FeatureManagement.JsonConverters { public class ValueValidatorJsonConverter : JsonConverter { + private JsonSerializerOptions _readJsonSerializerOptions; + + private JsonSerializerOptions _writeJsonSerializerOptions; + public override IValueValidator Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var rootElement = JsonDocument.ParseValue(ref reader).RootElement; @@ -22,8 +26,8 @@ namespace Volo.Abp.FeatureManagement.JsonConverters var propertiesJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Properties), StringComparison.OrdinalIgnoreCase)); if (propertiesJsonProperty.Value.ValueKind == JsonValueKind.Object) { - var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ObjectToInferredTypesConverter()); - var properties = propertiesJsonProperty.Value.Deserialize>(newOptions); + _readJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this, new ObjectToInferredTypesConverter()); + var properties = propertiesJsonProperty.Value.Deserialize>(_readJsonSerializerOptions); if (properties != null && properties.Any()) { foreach (var property in properties) @@ -41,8 +45,8 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public override void Write(Utf8JsonWriter writer, IValueValidator value, JsonSerializerOptions options) { - var newOptions = JsonSerializerOptionsHelper.Create(options, this); - JsonSerializer.Serialize(writer, value, value.GetType(), newOptions); + _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this); + JsonSerializer.Serialize(writer, value, value.GetType(), _writeJsonSerializerOptions); } protected virtual IValueValidator CreateValueValidatorByName(string name) diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js index 96ee7e5361..52cbd03883 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js @@ -111,6 +111,13 @@ var _$table = _$wrapper.find('table'); _dataTable = _$table.DataTable( abp.libs.datatables.normalizeConfiguration({ + // "fnRowCallback": function( nRow, aData, iDisplayIndex ) { + // /* Append the grade to the default row class name */ + // if ( aData[4] == "A" ) + // { + // $('td:eq(4)', nRow).html( 'A' ); + // } + // }, order: [[1, 'asc']], processing: true, serverSide: true, From 6d2d2643f339fb5407f92b90acd4079b374d26a6 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 29 Nov 2021 17:33:34 +0800 Subject: [PATCH 2/7] Add some unit tests. --- .../Volo/Abp/Json/AbpStringToBoolean_Tests.cs | 54 ++++++++++++++++++ .../Volo/Abp/Json/AbpStringToEnum_Tests.cs | 55 +++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToBoolean_Tests.cs create mode 100644 framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToEnum_Tests.cs diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToBoolean_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToBoolean_Tests.cs new file mode 100644 index 0000000000..a013532e7a --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToBoolean_Tests.cs @@ -0,0 +1,54 @@ +using System.Text.Json; +using Shouldly; +using Volo.Abp.Json.SystemTextJson.JsonConverters; +using Xunit; + +namespace Volo.Abp.Json +{ + public class AbpStringToBoolean_Tests + { + [Fact] + public void Test_Read() + { + var options = new JsonSerializerOptions() + { + Converters = + { + new AbpStringToBooleanConverter() + } + }; + + var testClass = JsonSerializer.Deserialize("{\"Enabled\": \"TrUe\"}", options); + testClass.ShouldNotBeNull(); + testClass.Enabled.ShouldBe(true); + + testClass = JsonSerializer.Deserialize("{\"Enabled\": true}", options); + testClass.ShouldNotBeNull(); + testClass.Enabled.ShouldBe(true); + } + + [Fact] + public void Test_Write() + { + var options = new JsonSerializerOptions() + { + Converters = + { + new AbpStringToEnumFactory() + } + }; + + var testClassJson = JsonSerializer.Serialize(new TestClass() + { + Enabled = true + }); + + testClassJson.ShouldBe("{\"Enabled\":true}"); + } + + class TestClass + { + public bool Enabled { get; set; } + } + } +} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToEnum_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToEnum_Tests.cs new file mode 100644 index 0000000000..b7aa4de550 --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToEnum_Tests.cs @@ -0,0 +1,55 @@ +using System; +using System.Text.Json; +using Shouldly; +using Volo.Abp.Json.SystemTextJson.JsonConverters; +using Xunit; + +namespace Volo.Abp.Json +{ + public class AbpStringToEnum_Tests + { + [Fact] + public void Test_Read() + { + var options = new JsonSerializerOptions() + { + Converters = + { + new AbpStringToEnumFactory() + } + }; + + var testClass = JsonSerializer.Deserialize("{\"Day\": \"Monday\"}", options); + testClass.ShouldNotBeNull(); + testClass.Day.ShouldBe(DayOfWeek.Monday); + + testClass = JsonSerializer.Deserialize("{\"Day\": 1}", options); + testClass.ShouldNotBeNull(); + testClass.Day.ShouldBe(DayOfWeek.Monday); + } + + [Fact] + public void Test_Write() + { + var options = new JsonSerializerOptions() + { + Converters = + { + new AbpStringToEnumFactory() + } + }; + + var testClassJson = JsonSerializer.Serialize(new TestClass() + { + Day = DayOfWeek.Monday + }); + + testClassJson.ShouldBe("{\"Day\":1}"); + } + + class TestClass + { + public DayOfWeek Day { get; set; } + } + } +} From 7453381958df56c3a3aa764420cc778e0322c6a0 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 30 Nov 2021 14:14:38 +0800 Subject: [PATCH 3/7] Reuse more JsonSerializerOptions instances. --- .../ValueConverters/AbpJsonValueConverter.cs | 12 ++++++--- .../ExtraPropertiesValueConverter.cs | 15 +++++++---- .../DynamicProxying/ApiDescriptionFinder.cs | 10 ++++--- .../AbpSystemTextJsonSerializerProvider.cs | 26 ++++++++++++------- .../AbpHasExtraPropertiesJsonConverter.cs | 13 +++++++--- ...pHasExtraPropertiesJsonConverterFactory.cs | 19 +++++++++----- .../Json/JsonLocalizationDictionaryBuilder.cs | 18 ++++++------- 7 files changed, 71 insertions(+), 42 deletions(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs index 7378ab8eff..1718ba6419 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs @@ -19,11 +19,17 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters return JsonSerializer.Serialize(d); } + private static readonly JsonSerializerOptions DeserializeOptions = new JsonSerializerOptions() + { + Converters = + { + new ObjectToInferredTypesConverter() + } + }; + private static TPropertyType DeserializeObject(string s) { - var deserializeOptions = new JsonSerializerOptions(); - deserializeOptions.Converters.Add(new ObjectToInferredTypesConverter()); - return JsonSerializer.Deserialize(s, deserializeOptions); + return JsonSerializer.Deserialize(s, DeserializeOptions); } } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs index 2949437ad0..fd8ab43fd0 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs @@ -41,17 +41,22 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters return JsonSerializer.Serialize(copyDictionary); } + private static readonly JsonSerializerOptions DeserializeOptions = new JsonSerializerOptions() + { + Converters = + { + new ObjectToInferredTypesConverter() + } + }; + private static ExtraPropertyDictionary DeserializeObject(string extraPropertiesAsJson, Type entityType) { if (extraPropertiesAsJson.IsNullOrEmpty() || extraPropertiesAsJson == "{}") { return new ExtraPropertyDictionary(); } - - var deserializeOptions = new JsonSerializerOptions(); - deserializeOptions.Converters.Add(new ObjectToInferredTypesConverter()); - - var dictionary = JsonSerializer.Deserialize(extraPropertiesAsJson, deserializeOptions) ?? + + var dictionary = JsonSerializer.Deserialize(extraPropertiesAsJson, DeserializeOptions) ?? new ExtraPropertyDictionary(); if (entityType != null) diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs index cce91cb5d7..a70327b8e6 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs @@ -90,6 +90,11 @@ namespace Volo.Abp.Http.Client.DynamicProxying return await Cache.GetAsync(baseUrl, () => GetApiDescriptionFromServerAsync(client, baseUrl)); } + private static readonly JsonSerializerOptions DeserializeOptions = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + protected virtual async Task GetApiDescriptionFromServerAsync( HttpClient client, string baseUrl) @@ -113,10 +118,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying var content = await response.Content.ReadAsStringAsync(); - var result = JsonSerializer.Deserialize(content, new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }); + var result = JsonSerializer.Deserialize(content, DeserializeOptions); return result; } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs index 570d1c162c..217f40386a 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Text.Json; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; @@ -39,21 +40,26 @@ namespace Volo.Abp.Json.SystemTextJson return JsonSerializer.Deserialize(jsonString, type, CreateJsonSerializerOptions(camelCase)); } + private readonly ConcurrentDictionary JsonSerializerOptionsCache = new ConcurrentDictionary(); + protected virtual JsonSerializerOptions CreateJsonSerializerOptions(bool camelCase = true, bool indented = false) { - var settings = new JsonSerializerOptions(Options.JsonSerializerOptions); - - if (camelCase) + return JsonSerializerOptionsCache.GetOrAdd($"default{camelCase}{indented}", _ => { - settings.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; - } + var settings = new JsonSerializerOptions(Options.JsonSerializerOptions); - if (indented) - { - settings.WriteIndented = true; - } + if (camelCase) + { + settings.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + } + + if (indented) + { + settings.WriteIndented = true; + } - return settings; + return settings; + }); } } } 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 0d75a04eed..5b2eb5a15a 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 @@ -17,13 +17,18 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters { _readJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, x => x == this); - var converterFactory = _readJsonSerializerOptions.Converters.FirstOrDefault(x => x is AbpHasExtraPropertiesJsonConverterFactory); - converterFactory?.As().AddExcludeTypes(typeToConvert); - var rootElement = JsonDocument.ParseValue(ref reader).RootElement; if (rootElement.ValueKind == JsonValueKind.Object) { - var extensibleObject = rootElement.Deserialize(_readJsonSerializerOptions); + var converterFactory = _readJsonSerializerOptions.Converters + .FirstOrDefault(x => x is AbpHasExtraPropertiesJsonConverterFactory) + .As(); + + T extensibleObject; + using (converterFactory != null ? converterFactory.Exclude(typeToConvert) : NullDisposable.Instance) + { + extensibleObject = rootElement.Deserialize(_readJsonSerializerOptions); + } var extraPropertiesJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IHasExtraProperties.ExtraProperties), StringComparison.OrdinalIgnoreCase)); diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs index dfe95b85c9..e0d99bf8cb 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs @@ -1,10 +1,11 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Collections.Immutable; +using System.Linq; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; +using System.Threading; using Volo.Abp.Data; namespace Volo.Abp.Json.SystemTextJson.JsonConverters @@ -13,17 +14,21 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters { private static readonly ConcurrentDictionary CachedTypes = new ConcurrentDictionary(); - private readonly List _excludeTypes = new List(); + private readonly AsyncLocal> _excludeTypes = new AsyncLocal>(); - public virtual AbpHasExtraPropertiesJsonConverterFactory AddExcludeTypes(params Type[] excludeTypes) + public IDisposable Exclude(params Type[] excludeTypes) { - _excludeTypes.AddIfNotContains(excludeTypes); - return this; + var parent = _excludeTypes.Value; + _excludeTypes.Value = excludeTypes.ToList(); + return new DisposeAction(() => + { + _excludeTypes.Value = parent; + }); } - + public override bool CanConvert(Type typeToConvert) { - if (_excludeTypes.Contains(typeToConvert)) + if (_excludeTypes.Value != null && _excludeTypes.Value.Contains(typeToConvert)) { return false; } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationDictionaryBuilder.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationDictionaryBuilder.cs index 9ccc6738a6..79a8cb0ac4 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationDictionaryBuilder.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationDictionaryBuilder.cs @@ -24,6 +24,14 @@ namespace Volo.Abp.Localization.Json } } + private static readonly JsonSerializerOptions DeserializeOptions = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + DictionaryKeyPolicy = JsonNamingPolicy.CamelCase, + ReadCommentHandling = JsonCommentHandling.Skip, + AllowTrailingCommas = true + }; + /// /// Builds an from given json string. /// @@ -33,15 +41,7 @@ namespace Volo.Abp.Localization.Json JsonLocalizationFile jsonFile; try { - var options = new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true, - DictionaryKeyPolicy = JsonNamingPolicy.CamelCase, - ReadCommentHandling = JsonCommentHandling.Skip, - AllowTrailingCommas = true - }; - - jsonFile = JsonSerializer.Deserialize(jsonString, options); + jsonFile = JsonSerializer.Deserialize(jsonString, DeserializeOptions); } catch (JsonException ex) { From cb7f38e26f6e88917c3b60510cd5bf75d249fe9a Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 30 Nov 2021 14:52:37 +0800 Subject: [PATCH 4/7] Update index.js --- .../Volo.Abp.Identity.Web/Pages/Identity/Users/index.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js index 52cbd03883..96ee7e5361 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/index.js @@ -111,13 +111,6 @@ var _$table = _$wrapper.find('table'); _dataTable = _$table.DataTable( abp.libs.datatables.normalizeConfiguration({ - // "fnRowCallback": function( nRow, aData, iDisplayIndex ) { - // /* Append the grade to the default row class name */ - // if ( aData[4] == "A" ) - // { - // $('td:eq(4)', nRow).html( 'A' ); - // } - // }, order: [[1, 'asc']], processing: true, serverSide: true, From 220893ccffea5b331ce945f1dffb94432f4558b2 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 30 Nov 2021 16:00:44 +0800 Subject: [PATCH 5/7] Update AbpStringToBoolean_Tests.cs --- .../Volo/Abp/Json/AbpStringToBoolean_Tests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToBoolean_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToBoolean_Tests.cs index a013532e7a..2653fdb02c 100644 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToBoolean_Tests.cs +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToBoolean_Tests.cs @@ -34,7 +34,7 @@ namespace Volo.Abp.Json { Converters = { - new AbpStringToEnumFactory() + new AbpStringToBooleanConverter() } }; From dfe75c2a1d32846c7d830c96184403b5e430b488 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 1 Dec 2021 11:00:46 +0800 Subject: [PATCH 6/7] Add `JsonInclude` to `ExtensibleObject ` & Remove `AbpHasExtraPropertiesJsonConverter`. --- .../Mvc/Json/AbpJsonOptionsSetup.cs | 1 - ...AbpSystemTextJsonSerializerOptionsSetup.cs | 1 - .../AbpHasExtraPropertiesJsonConverter.cs | 56 ---------------- ...pHasExtraPropertiesJsonConverterFactory.cs | 65 ------------------- .../Abp/ObjectExtending/ExtensibleObject.cs | 2 + ...pSystemTextJsonSerializerProvider_Tests.cs | 3 +- ...ter_Tests.cs => ExtensibleObject_Tests.cs} | 45 +++++++++++-- 7 files changed, 44 insertions(+), 129 deletions(-) delete mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs delete mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs rename framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/{AbpHasExtraPropertiesJsonConverter_Tests.cs => ExtensibleObject_Tests.cs} (62%) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs index 43a9c04d32..077578413b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs @@ -29,7 +29,6 @@ namespace Volo.Abp.AspNetCore.Mvc.Json options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter()); options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter()); - options.JsonSerializerOptions.Converters.Add(new AbpHasExtraPropertiesJsonConverterFactory()); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs index 3c6357c92e..98b7fdbcb1 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs @@ -25,7 +25,6 @@ namespace Volo.Abp.Json.SystemTextJson options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter()); options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter()); - options.JsonSerializerOptions.Converters.Add(new AbpHasExtraPropertiesJsonConverterFactory()); // If the user hasn't explicitly configured the encoder, use the less strict encoder that does not encode all non-ASCII characters. options.JsonSerializerOptions.Encoder ??= JavaScriptEncoder.UnsafeRelaxedJsonEscaping; 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 deleted file mode 100644 index 5b2eb5a15a..0000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverter.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Linq; -using System.Text.Json; -using System.Text.Json.Serialization; -using Volo.Abp.Data; - -namespace Volo.Abp.Json.SystemTextJson.JsonConverters -{ - public class AbpHasExtraPropertiesJsonConverter : JsonConverter - where T : IHasExtraProperties - { - private JsonSerializerOptions _readJsonSerializerOptions; - - private JsonSerializerOptions _writeJsonSerializerOptions; - - public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - _readJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, x => x == this); - - var rootElement = JsonDocument.ParseValue(ref reader).RootElement; - if (rootElement.ValueKind == JsonValueKind.Object) - { - var converterFactory = _readJsonSerializerOptions.Converters - .FirstOrDefault(x => x is AbpHasExtraPropertiesJsonConverterFactory) - .As(); - - T extensibleObject; - using (converterFactory != null ? converterFactory.Exclude(typeToConvert) : NullDisposable.Instance) - { - extensibleObject = rootElement.Deserialize(_readJsonSerializerOptions); - } - - var extraPropertiesJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IHasExtraProperties.ExtraProperties), StringComparison.OrdinalIgnoreCase)); - - if (extraPropertiesJsonProperty.Value.ValueKind == JsonValueKind.Object) - { - var extraPropertyDictionary = extraPropertiesJsonProperty.Value.Deserialize(typeof(ExtraPropertyDictionary), _readJsonSerializerOptions); - ObjectHelper.TrySetProperty(extensibleObject, x => x.ExtraProperties, () => extraPropertyDictionary); - } - - return extensibleObject; - } - - throw new JsonException("RootElement's ValueKind is not Object!"); - } - - public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) - { - _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, x => - x == this || - x.GetType() == typeof(AbpHasExtraPropertiesJsonConverterFactory)); - - JsonSerializer.Serialize(writer, value, _writeJsonSerializerOptions); - } - } -} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs deleted file mode 100644 index e0d99bf8cb..0000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpHasExtraPropertiesJsonConverterFactory.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Threading; -using Volo.Abp.Data; - -namespace Volo.Abp.Json.SystemTextJson.JsonConverters -{ - public class AbpHasExtraPropertiesJsonConverterFactory : JsonConverterFactory - { - private static readonly ConcurrentDictionary CachedTypes = new ConcurrentDictionary(); - - private readonly AsyncLocal> _excludeTypes = new AsyncLocal>(); - - public IDisposable Exclude(params Type[] excludeTypes) - { - var parent = _excludeTypes.Value; - _excludeTypes.Value = excludeTypes.ToList(); - return new DisposeAction(() => - { - _excludeTypes.Value = parent; - }); - } - - public override bool CanConvert(Type typeToConvert) - { - if (_excludeTypes.Value != null && _excludeTypes.Value.Contains(typeToConvert)) - { - return false; - } - - //Only for private or protected ExtraProperties. - if (typeof(IHasExtraProperties).IsAssignableFrom(typeToConvert)) - { - return CachedTypes.GetOrAdd(typeToConvert, type => - { - var property = type.GetProperty(nameof(IHasExtraProperties.ExtraProperties)); - if (property != null) - { - var setMethod = property.GetSetMethod(true); - return setMethod != null && (setMethod.IsPrivate || setMethod.IsFamily); - } - - return false; - }); - } - - return false; - } - - public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) - { - return (JsonConverter) Activator.CreateInstance( - typeof(AbpHasExtraPropertiesJsonConverter<>).MakeGenericType(typeToConvert), - BindingFlags.Instance | BindingFlags.Public, - binder: null, - null, - culture: null)!; - } - } -} diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs index d068015581..1e87049ed7 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using Volo.Abp.Data; using Volo.Abp.DynamicProxy; @@ -9,6 +10,7 @@ namespace Volo.Abp.ObjectExtending [Serializable] public class ExtensibleObject : IHasExtraProperties, IValidatableObject { + [JsonInclude] public ExtraPropertyDictionary ExtraProperties { get; protected set; } public ExtensibleObject() 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 3f7ce5dc26..3ceca6a2c2 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 @@ -174,8 +174,7 @@ namespace Volo.Abp.Json { var json = "{\"name\":\"test\",\"extraProperties\":null}"; var extensibleObject = JsonSerializer.Deserialize(json); - extensibleObject.ExtraProperties.ShouldNotBeNull(); - extensibleObject.ExtraProperties.ShouldBeEmpty(); + extensibleObject.ExtraProperties.ShouldBeNull(); } [Fact] diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHasExtraPropertiesJsonConverter_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs similarity index 62% rename from framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHasExtraPropertiesJsonConverter_Tests.cs rename to framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs index c11e8f3cec..f3c6095922 100644 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHasExtraPropertiesJsonConverter_Tests.cs +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs @@ -7,11 +7,11 @@ using Xunit; namespace Volo.Abp.Json { - public class AbpHasExtraPropertiesJsonConverter_Tests: AbpJsonTestBase + public class ExtensibleObject_Tests: AbpJsonTestBase { private readonly IJsonSerializer _jsonSerializer; - public AbpHasExtraPropertiesJsonConverter_Tests() + public ExtensibleObject_Tests() { _jsonSerializer = GetRequiredService(); } @@ -60,17 +60,54 @@ namespace Volo.Abp.Json fooDto.BarDtos.First().Name.ShouldBe("new-bar-dto"); fooDto.BarDtos.First().GetProperty("bar").ShouldBe("new-bar-value"); } + + [Fact] + public void SelfReference_Test() + { + var parentNodeDto = new NodeDto + { + Name = "parentNode", + }; + parentNodeDto.SetProperty("node", "parent-value"); + + var nodeDto = new NodeDto + { + Name = "node", + Parent = parentNodeDto + }; + nodeDto.SetProperty("node", "node-value"); + + var json = _jsonSerializer.Serialize(nodeDto); + + nodeDto = _jsonSerializer.Deserialize(json); + nodeDto.ShouldNotBeNull(); + nodeDto.Name.ShouldBe("node"); + nodeDto.GetProperty("node").ShouldBe("node-value"); + + nodeDto.Parent.ShouldNotBeNull(); + nodeDto.Parent.Name.ShouldBe("parentNode"); + nodeDto.Parent.GetProperty("node").ShouldBe("parent-value"); + } } - public class FooDto : ExtensibleObject + class FooDto : ExtensibleObject { public string Name { get; set; } public List BarDtos { get; set; } } - public class BarDto : ExtensibleObject + class BarDto : ExtensibleObject + { + public string Name { get; set; } + + public FooDto FooDto { get; set; } + } + + class NodeDto : ExtensibleObject { public string Name { get; set; } + + public NodeDto Parent { get; set; } } } From 9f595cec96a4f1166127f870861a42aad498f6b7 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 1 Dec 2021 15:16:04 +0800 Subject: [PATCH 7/7] Remove empty lines. --- .../ValueConverters/AbpJsonValueConverter.cs | 2 +- .../ValueConverters/ExtraPropertiesValueConverter.cs | 4 ++-- .../Http/Client/DynamicProxying/ApiDescriptionFinder.cs | 2 +- .../SystemTextJson/AbpSystemTextJsonSerializerProvider.cs | 2 +- .../JsonConverters/AbpStringToBooleanConverter.cs | 6 +++--- .../JsonConverters/AbpStringToEnumConverter.cs | 4 ++-- .../Json/JsonLocalizationDictionaryBuilder.cs | 2 +- .../Volo/Abp/Json/AbpStringToBoolean_Tests.cs | 6 +++--- .../Volo/Abp/Json/AbpStringToEnum_Tests.cs | 6 +++--- .../Volo/Abp/Json/ExtensibleObject_Tests.cs | 8 ++++---- .../Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs | 2 +- .../SelectionStringValueItemSourceJsonConverter.cs | 2 +- .../JsonConverters/StringValueTypeJsonConverter.cs | 4 ++-- .../JsonConverters/ValueValidatorJsonConverter.cs | 4 ++-- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs index 1718ba6419..9e8ed9f3fc 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs @@ -26,7 +26,7 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters new ObjectToInferredTypesConverter() } }; - + private static TPropertyType DeserializeObject(string s) { return JsonSerializer.Deserialize(s, DeserializeOptions); diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs index fd8ab43fd0..9db5624ebf 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs @@ -48,14 +48,14 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters new ObjectToInferredTypesConverter() } }; - + private static ExtraPropertyDictionary DeserializeObject(string extraPropertiesAsJson, Type entityType) { if (extraPropertiesAsJson.IsNullOrEmpty() || extraPropertiesAsJson == "{}") { return new ExtraPropertyDictionary(); } - + var dictionary = JsonSerializer.Deserialize(extraPropertiesAsJson, DeserializeOptions) ?? new ExtraPropertyDictionary(); diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs index a70327b8e6..4d9d6ff4ff 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs @@ -94,7 +94,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; - + protected virtual async Task GetApiDescriptionFromServerAsync( HttpClient client, string baseUrl) diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs index 217f40386a..e136de347c 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs @@ -41,7 +41,7 @@ namespace Volo.Abp.Json.SystemTextJson } private readonly ConcurrentDictionary JsonSerializerOptionsCache = new ConcurrentDictionary(); - + protected virtual JsonSerializerOptions CreateJsonSerializerOptions(bool camelCase = true, bool indented = false) { return JsonSerializerOptionsCache.GetOrAdd($"default{camelCase}{indented}", _ => diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs index 2cfa03677c..8469f3a3ae 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs @@ -7,9 +7,9 @@ using System.Text.Json.Serialization; namespace Volo.Abp.Json.SystemTextJson.JsonConverters { public class AbpStringToBooleanConverter : JsonConverter - { + { private JsonSerializerOptions _writeJsonSerializerOptions; - + public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String) @@ -33,7 +33,7 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters { _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this); var entityConverter = (JsonConverter)_writeJsonSerializerOptions.GetConverter(typeof(bool)); - + entityConverter.Write(writer, value, _writeJsonSerializerOptions); } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs index 8b99b48301..247b7e2b04 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs @@ -11,9 +11,9 @@ namespace Volo.Abp.Json.SystemTextJson.JsonConverters private readonly JsonStringEnumConverter _innerJsonStringEnumConverter; private JsonSerializerOptions _readJsonSerializerOptions; - + private JsonSerializerOptions _writeJsonSerializerOptions; - + public AbpStringToEnumConverter() : this(namingPolicy: null, allowIntegerValues: true) { diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationDictionaryBuilder.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationDictionaryBuilder.cs index 79a8cb0ac4..6694c589cb 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationDictionaryBuilder.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationDictionaryBuilder.cs @@ -31,7 +31,7 @@ namespace Volo.Abp.Localization.Json ReadCommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true }; - + /// /// Builds an from given json string. /// diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToBoolean_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToBoolean_Tests.cs index 2653fdb02c..c46a616db0 100644 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToBoolean_Tests.cs +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToBoolean_Tests.cs @@ -21,12 +21,12 @@ namespace Volo.Abp.Json var testClass = JsonSerializer.Deserialize("{\"Enabled\": \"TrUe\"}", options); testClass.ShouldNotBeNull(); testClass.Enabled.ShouldBe(true); - + testClass = JsonSerializer.Deserialize("{\"Enabled\": true}", options); testClass.ShouldNotBeNull(); testClass.Enabled.ShouldBe(true); } - + [Fact] public void Test_Write() { @@ -42,7 +42,7 @@ namespace Volo.Abp.Json { Enabled = true }); - + testClassJson.ShouldBe("{\"Enabled\":true}"); } diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToEnum_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToEnum_Tests.cs index b7aa4de550..d3bba36534 100644 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToEnum_Tests.cs +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToEnum_Tests.cs @@ -22,12 +22,12 @@ namespace Volo.Abp.Json var testClass = JsonSerializer.Deserialize("{\"Day\": \"Monday\"}", options); testClass.ShouldNotBeNull(); testClass.Day.ShouldBe(DayOfWeek.Monday); - + testClass = JsonSerializer.Deserialize("{\"Day\": 1}", options); testClass.ShouldNotBeNull(); testClass.Day.ShouldBe(DayOfWeek.Monday); } - + [Fact] public void Test_Write() { @@ -43,7 +43,7 @@ namespace Volo.Abp.Json { Day = DayOfWeek.Monday }); - + testClassJson.ShouldBe("{\"Day\":1}"); } diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs index f3c6095922..9a88705282 100644 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs @@ -60,7 +60,7 @@ namespace Volo.Abp.Json fooDto.BarDtos.First().Name.ShouldBe("new-bar-dto"); fooDto.BarDtos.First().GetProperty("bar").ShouldBe("new-bar-value"); } - + [Fact] public void SelfReference_Test() { @@ -100,14 +100,14 @@ namespace Volo.Abp.Json class BarDto : ExtensibleObject { public string Name { get; set; } - + public FooDto FooDto { get; set; } } - + class NodeDto : ExtensibleObject { public string Name { get; set; } - + public NodeDto Parent { get; set; } } } 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 59e550dd92..4d1fb34b73 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 @@ -9,7 +9,7 @@ namespace Volo.Abp.MemoryDb.JsonConverters where TEntity : Entity { private JsonSerializerOptions _writeJsonSerializerOptions; - + public override TEntity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var jsonDocument = JsonDocument.ParseValue(ref reader); 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 9ec2c47e36..7229ecdd83 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 @@ -9,7 +9,7 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public class SelectionStringValueItemSourceJsonConverter : JsonConverter { private JsonSerializerOptions _readJsonSerializerOptions; - + private JsonSerializerOptions _writeJsonSerializerOptions; public override ISelectionStringValueItemSource Read(ref Utf8JsonReader reader, Type typeToConvert, 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 4802f28474..992ba4a183 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 @@ -9,9 +9,9 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public class StringValueTypeJsonConverter : JsonConverter { private JsonSerializerOptions _readJsonSerializerOptions; - + private JsonSerializerOptions _writeJsonSerializerOptions; - + public override IStringValueType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var rootElement = JsonDocument.ParseValue(ref reader).RootElement; 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 d42265f2c5..5cd51d09c4 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 @@ -11,9 +11,9 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public class ValueValidatorJsonConverter : JsonConverter { private JsonSerializerOptions _readJsonSerializerOptions; - + private JsonSerializerOptions _writeJsonSerializerOptions; - + public override IValueValidator Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var rootElement = JsonDocument.ParseValue(ref reader).RootElement;