From 7b06cfb5a2bc85f770cb1c708179ea0e9da7c61d Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 27 Oct 2020 11:44:39 +0800 Subject: [PATCH 01/17] Move to System.Text.Json Resolve #1198 --- framework/Volo.Abp.sln | 7 ++ .../Volo.Abp.AspNetCore.Mvc.csproj | 1 - .../AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs | 8 +- .../Mvc/Json/AbpJsonOptionsSetup.cs | 25 ++++++ .../Mvc/Json/AbpMvcJsonContractResolver.cs | 46 ---------- .../Abp/Auditing/AuditingContractResolver.cs | 39 -------- .../AuditingRuntimeIgnoreConverter.cs | 45 ++++++++++ .../Abp/Auditing/JsonNetAuditSerializer.cs | 29 ++---- .../Volo/Abp/Domain/Entities/EntityHelper.cs | 39 +++++++- .../Domain/Entities/EntityJsonConverter.cs | 29 ++++++ .../ValueConverters/AbpJsonValueConverter.cs | 12 +-- .../ExtraPropertiesValueConverter.cs | 15 ++-- .../DynamicProxying/ApiDescriptionFinder.cs | 15 ++-- .../Modeling/ActionApiDescriptionModel.cs | 4 +- .../ApplicationApiDescriptionModel.cs | 6 +- .../Modeling/ControllerApiDescriptionModel.cs | 4 +- .../ControllerInterfaceApiDescriptionModel.cs | 6 +- .../MethodParameterApiDescriptionModel.cs | 2 +- .../Modeling/ModuleApiDescriptionModel.cs | 14 +-- .../Modeling/ParameterApiDescriptionModel.cs | 2 +- .../ReturnValueApiDescriptionModel.cs | 2 +- .../Http/Modeling/TypeApiDescriptionModel.cs | 2 +- .../Volo.Abp.Json.Newtonsoft/FodyWeavers.xml | 3 + .../Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd | 30 +++++++ .../Volo.Abp.Json.Newtonsoft.csproj | 25 ++++++ .../Volo/Abp/Json/AbpJsonModule.cs | 21 +++++ .../Newtonsoft/AbpJsonIsoDateTimeConverter.cs | 0 .../AbpNewtonsoftJsonSerializerOptions.cs | 0 .../Newtonsoft/NewtonsoftJsonSerializer.cs | 1 + .../src/Volo.Abp.Json/Volo.Abp.Json.csproj | 4 - .../Volo/Abp/Json/AbpJsonModule.cs | 10 +-- .../Volo/Abp/Json/AbpJsonOptions.cs | 2 +- .../Abp/Json/Microsoft/AbpJsonSerializer.cs | 49 ++++++++++ .../Microsoft/AbpJsonSerializerOptions.cs | 18 ++++ .../AbpJsonSerializerOptionsSetup.cs | 23 +++++ .../JsonConverters/AbpDateTimeConverter.cs | 38 ++++++++ .../AbpNullableDateTimeConverter.cs | 50 +++++++++++ .../ObjectToInferredTypesConverter.cs | 54 +++++++++++ .../Volo.Abp.Localization.csproj | 4 - .../Json/JsonLocalizationDictionaryBuilder.cs | 19 ++-- .../Localization/Json/JsonLocalizationFile.cs | 4 +- .../MemoryDb/Utf8JsonMemoryDbSerializer.cs | 41 ++------- .../Utf8JsonMemoryDbSerializerOptions.cs | 14 +++ .../OAuth/Claims/MultipleClaimAction_Tests.cs | 1 - .../Abp/AspNetCore/AbpAspNetCoreTestBase.cs | 14 +-- .../Abp/MemoryDb/AbpMemoryDbTestModule.cs | 11 ++- .../Repository_Basic_Tests_With_Int_Pk.cs | 1 + .../Volo.Docs.Domain.Shared.csproj | 4 + ...ureManagementApplicationContractsModule.cs | 11 ++- .../LocalizableStringInfoJsonConverter.cs | 24 +++++ .../SelectionStringValueItemJsonConverter.cs | 36 ++++++++ ...ctionStringValueItemSourceJsonConverter.cs | 36 ++++++++ .../StringValueTypeJsonConverter.cs | 47 ++++++++++ .../ValueValidatorJsonConverter.cs | 68 ++++++++++++++ .../StringValueTypeJsonConverter.cs | 90 ------------------- .../StringValueJsonConverter_Tests.cs | 6 +- nupkg/common.ps1 | 1 + 57 files changed, 783 insertions(+), 329 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs delete mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs delete mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingContractResolver.cs create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingRuntimeIgnoreConverter.cs create mode 100644 framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityJsonConverter.cs create mode 100644 framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xml create mode 100644 framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd create mode 100644 framework/src/Volo.Abp.Json.Newtonsoft/Volo.Abp.Json.Newtonsoft.csproj create mode 100644 framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/AbpJsonModule.cs rename framework/src/{Volo.Abp.Json => Volo.Abp.Json.Newtonsoft}/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs (100%) rename framework/src/{Volo.Abp.Json => Volo.Abp.Json.Newtonsoft}/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs (100%) rename framework/src/{Volo.Abp.Json => Volo.Abp.Json.Newtonsoft}/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializer.cs (98%) create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializer.cs create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptions.cs create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptionsSetup.cs create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpDateTimeConverter.cs create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpNullableDateTimeConverter.cs create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/ObjectToInferredTypesConverter.cs create mode 100644 framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/Utf8JsonMemoryDbSerializerOptions.cs create mode 100644 modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/LocalizableStringInfoJsonConverter.cs create mode 100644 modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemJsonConverter.cs create mode 100644 modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemSourceJsonConverter.cs create mode 100644 modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs create mode 100644 modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs delete mode 100644 modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/StringValueTypeJsonConverter.cs diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 65cac6e7cd..fb59c91051 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -355,6 +355,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Compone EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Swashbuckle", "src\Volo.Abp.Swashbuckle\Volo.Abp.Swashbuckle.csproj", "{DD9519E0-5A68-48DC-A051-7BF2AC922F3E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Json.Newtonsoft", "src\Volo.Abp.Json.Newtonsoft\Volo.Abp.Json.Newtonsoft.csproj", "{B5DEA857-1A22-4479-8441-E871D1BCBAB2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1057,6 +1059,10 @@ Global {DD9519E0-5A68-48DC-A051-7BF2AC922F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU {DD9519E0-5A68-48DC-A051-7BF2AC922F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU {DD9519E0-5A68-48DC-A051-7BF2AC922F3E}.Release|Any CPU.Build.0 = Release|Any CPU + {B5DEA857-1A22-4479-8441-E871D1BCBAB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B5DEA857-1A22-4479-8441-E871D1BCBAB2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B5DEA857-1A22-4479-8441-E871D1BCBAB2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B5DEA857-1A22-4479-8441-E871D1BCBAB2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1236,6 +1242,7 @@ Global {B9D1ADCB-D552-4626-A1F1-78FF72C1E822} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {89840441-5A3A-4FD7-9CB4-E5B52FAEF72A} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {DD9519E0-5A68-48DC-A051-7BF2AC922F3E} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {B5DEA857-1A22-4479-8441-E871D1BCBAB2} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj index 3e691f57f3..fff97c83c3 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj @@ -29,7 +29,6 @@ - diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs index 3097a3c725..f35721c3c0 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs @@ -35,6 +35,7 @@ using Volo.Abp.Http; using Volo.Abp.DynamicProxy; using Volo.Abp.GlobalFeatures; using Volo.Abp.Http.Modeling; +using Volo.Abp.Json.Microsoft; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.UI; @@ -114,11 +115,6 @@ namespace Volo.Abp.AspNetCore.Mvc ); var mvcBuilder = context.Services.AddMvc() - .AddNewtonsoftJson(options => - { - options.SerializerSettings.ContractResolver = - new AbpMvcJsonContractResolver(context.Services); - }) .AddRazorRuntimeCompilation() .AddDataAnnotationsLocalization(options => { @@ -139,6 +135,8 @@ namespace Volo.Abp.AspNetCore.Mvc }) .AddViewLocalization(); //TODO: How to configure from the application? Also, consider to move to a UI module since APIs does not care about it. + context.Services.TryAddEnumerable(ServiceDescriptor.Transient, AbpJsonOptionsSetup>()); + Configure(options => { options.FileProviders.Add( 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 new file mode 100644 index 0000000000..f9d58a3918 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs @@ -0,0 +1,25 @@ +using System; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.Json.Microsoft; +using Volo.Abp.Json.Microsoft.JsonConverters; + +namespace Volo.Abp.AspNetCore.Mvc.Json +{ + public class AbpJsonOptionsSetup : IConfigureOptions + { + protected IServiceProvider ServiceProvider { get; } + + public AbpJsonOptionsSetup(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + public void Configure(JsonOptions options) + { + options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService()); + options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService()); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs deleted file mode 100644 index 695212f563..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using System; -using System.Reflection; -using Volo.Abp.Json.Newtonsoft; -using Volo.Abp.Reflection; -using Volo.Abp.Timing; - -namespace Volo.Abp.AspNetCore.Mvc.Json -{ - public class AbpMvcJsonContractResolver : DefaultContractResolver - { - private readonly Lazy _dateTimeConverter; - - public AbpMvcJsonContractResolver(IServiceCollection services) - { - _dateTimeConverter = services.GetServiceLazy(); - - NamingStrategy = new CamelCaseNamingStrategy(); - } - - protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) - { - JsonProperty property = base.CreateProperty(member, memberSerialization); - - ModifyProperty(member, property); - - return property; - } - - protected virtual void ModifyProperty(MemberInfo member, JsonProperty property) - { - if (property.PropertyType != typeof(DateTime) && property.PropertyType != typeof(DateTime?)) - { - return; - } - - if (ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(member) == null) - { - property.Converter = _dateTimeConverter.Value; - } - - } - } -} diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingContractResolver.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingContractResolver.cs deleted file mode 100644 index e6d03bf707..0000000000 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingContractResolver.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; - -namespace Volo.Abp.Auditing -{ - public class AuditingContractResolver : CamelCasePropertyNamesContractResolver - { - private readonly List _ignoredTypes; - - public AuditingContractResolver(List ignoredTypes) - { - _ignoredTypes = ignoredTypes; - } - - protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) - { - var property = base.CreateProperty(member, memberSerialization); - - if (member.IsDefined(typeof(DisableAuditingAttribute)) || member.IsDefined(typeof(JsonIgnoreAttribute))) - { - property.ShouldSerialize = instance => false; - } - - foreach (var ignoredType in _ignoredTypes) - { - if (ignoredType.GetTypeInfo().IsAssignableFrom(property.PropertyType)) - { - property.ShouldSerialize = instance => false; - break; - } - } - - return property; - } - } -} diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingRuntimeIgnoreConverter.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingRuntimeIgnoreConverter.cs new file mode 100644 index 0000000000..240b2581ab --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingRuntimeIgnoreConverter.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Volo.Abp.Auditing +{ + public class AuditingRuntimeIgnoreConverter : JsonConverter> + { + private readonly List _ignoredTypes; + + public AuditingRuntimeIgnoreConverter(List ignoredTypes) + { + _ignoredTypes = ignoredTypes; + } + + public override Dictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new JsonException(); + } + + public override void Write(Utf8JsonWriter writer, Dictionary value, JsonSerializerOptions options) + { + var newDictionary = new Dictionary(); + foreach (var item in value.Where(x => x.Value != null)) + { + if (item.GetType().IsDefined(typeof(DisableAuditingAttribute), true) || + item.GetType().IsDefined(typeof(JsonIgnoreAttribute), true)) + { + continue; + } + + if (_ignoredTypes.Any(x => x.IsInstanceOfType(item.Value))) + { + continue; + } + + newDictionary[item.Key] = item.Value; + } + + JsonSerializer.Serialize(writer, newDictionary); + } + } +} diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs index b86df6b6c8..d11886e5a7 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs @@ -1,5 +1,5 @@ +using System.Text.Json; using Microsoft.Extensions.Options; -using Newtonsoft.Json; using Volo.Abp.DependencyInjection; namespace Volo.Abp.Auditing @@ -16,29 +16,14 @@ namespace Volo.Abp.Auditing public string Serialize(object obj) { - return JsonConvert.SerializeObject(obj, GetSharedJsonSerializerSettings()); + return JsonSerializer.Serialize(obj, GetJsonSerializerOptions()); } - private static readonly object SyncObj = new object(); - private static JsonSerializerSettings _sharedJsonSerializerSettings; - - private JsonSerializerSettings GetSharedJsonSerializerSettings() + private JsonSerializerOptions GetJsonSerializerOptions() { - if (_sharedJsonSerializerSettings == null) - { - lock (SyncObj) - { - if (_sharedJsonSerializerSettings == null) - { - _sharedJsonSerializerSettings = new JsonSerializerSettings - { - ContractResolver = new AuditingContractResolver(Options.IgnoredTypes) - }; - } - } - } - - return _sharedJsonSerializerSettings; + var options = new JsonSerializerOptions(); + options.Converters.Add(new AuditingRuntimeIgnoreConverter(Options.IgnoredTypes)); + return options; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs index 65f2992257..b778ec2b67 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityHelper.cs @@ -77,7 +77,7 @@ namespace Volo.Abp.Domain.Entities { var entity1Key = entity1Keys[i]; var entity2Key = entity2Keys[i]; - + if (entity1Key == null) { if (entity2Key == null) @@ -89,13 +89,13 @@ namespace Volo.Abp.Domain.Entities //entity2Key is not null! return false; } - + if (entity2Key == null) { //entity1Key was not null! return false; } - + if (TypeHelper.IsDefaultValue(entity1Key) && TypeHelper.IsDefaultValue(entity2Key)) { return false; @@ -266,5 +266,36 @@ namespace Volo.Abp.Domain.Entities property?.SetValue(entity, idFactory()); } + + public static void TrySetId( + object entity, + TKey id, + bool checkForDisableIdGenerationAttribute = false) + { + var property = CachedIdProperties.GetOrAdd( + $"{entity.GetType().FullName}-{checkForDisableIdGenerationAttribute}", () => + { + var idProperty = entity + .GetType() + .GetProperties() + .FirstOrDefault(x => x.Name == nameof(IEntity.Id) && + x.GetSetMethod(true) != null); + + if (idProperty == null) + { + return null; + } + + if (checkForDisableIdGenerationAttribute && + idProperty.IsDefined(typeof(DisableIdGenerationAttribute), true)) + { + return null; + } + + return idProperty; + }); + + property?.SetValue(entity, id); + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityJsonConverter.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityJsonConverter.cs new file mode 100644 index 0000000000..d472fd36d0 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityJsonConverter.cs @@ -0,0 +1,29 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Volo.Abp.Domain.Entities +{ + public class EntityJsonConverter : JsonConverter + { + 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) + { + EntityHelper.TrySetId(entity, id); + } + + return entity; + } + + public override void Write(Utf8JsonWriter writer, TEntity value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value); + } + } +} 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 6ecf19fa98..4955a703b3 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 @@ -1,6 +1,6 @@ -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Newtonsoft.Json; -using Volo.Abp.Data; +using System.Text.Json; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.Json.Microsoft.JsonConverters; namespace Volo.Abp.EntityFrameworkCore.ValueConverters { @@ -16,12 +16,14 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters private static string SerializeObject(TPropertyType d) { - return JsonConvert.SerializeObject(d, Formatting.None); + return JsonSerializer.Serialize(d); } private static TPropertyType DeserializeObject(string s) { - return JsonConvert.DeserializeObject(s); + var deserializeOptions = new JsonSerializerOptions(); + deserializeOptions.Converters.Add(new ObjectToInferredTypesConverter()); + 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 2fa00e3caf..b94a433367 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 @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -using System.ComponentModel; +using System.Text.Json; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Newtonsoft.Json; +using Volo.Abp.Json.Microsoft.JsonConverters; using Volo.Abp.ObjectExtending; namespace Volo.Abp.EntityFrameworkCore.ValueConverters @@ -36,13 +36,14 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters } } - return JsonConvert.SerializeObject(copyDictionary, Formatting.None); + return JsonSerializer.Serialize(copyDictionary); } private static Dictionary DeserializeObject(string extraPropertiesAsJson, Type entityType) { - var dictionary = JsonConvert.DeserializeObject>(extraPropertiesAsJson); - + var deserializeOptions = new JsonSerializerOptions(); + deserializeOptions.Converters.Add(new ObjectToInferredTypesConverter()); + var dictionary = JsonSerializer.Deserialize>(extraPropertiesAsJson, deserializeOptions) ?? new Dictionary(); if (entityType != null) { var objectExtension = ObjectExtensionManager.Instance.GetOrNull(entityType); @@ -59,7 +60,7 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters } private static object GetNormalizedValue( - Dictionary dictionary, + Dictionary dictionary, ObjectExtensionPropertyInfo property) { var value = dictionary.GetOrDefault(property.Name); @@ -84,4 +85,4 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters } } } -} \ No newline at end of file +} 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 a9b51eca6a..9142118b97 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 @@ -2,9 +2,8 @@ using System.Linq; using System.Net.Http; using System.Reflection; +using System.Text.Json; using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Modeling; using Volo.Abp.Threading; @@ -17,11 +16,6 @@ namespace Volo.Abp.Http.Client.DynamicProxying protected IApiDescriptionCache Cache { get; } - private static readonly JsonSerializerSettings SharedJsonSerializerSettings = new JsonSerializerSettings - { - ContractResolver = new CamelCasePropertyNamesContractResolver() - }; - public ApiDescriptionFinder(IApiDescriptionCache cache) { Cache = cache; @@ -91,9 +85,10 @@ namespace Volo.Abp.Http.Client.DynamicProxying var content = await response.Content.ReadAsStringAsync(); - var result = JsonConvert.DeserializeObject( - content, - typeof(ApplicationApiDescriptionModel), SharedJsonSerializerSettings); + var result = JsonSerializer.Deserialize(content, new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }); return (ApplicationApiDescriptionModel)result; } diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs index 7e9d375d06..fffd9d14d5 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs @@ -26,7 +26,7 @@ namespace Volo.Abp.Http.Modeling public ReturnValueApiDescriptionModel ReturnValue { get; set; } - private ActionApiDescriptionModel() + public ActionApiDescriptionModel() { } @@ -71,4 +71,4 @@ namespace Volo.Abp.Http.Modeling return $"[ActionApiDescriptionModel {Name}]"; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs index cc09b7a153..77fb28eed5 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs @@ -12,9 +12,9 @@ namespace Volo.Abp.Http.Modeling public IDictionary Types { get; set; } - private ApplicationApiDescriptionModel() + public ApplicationApiDescriptionModel() { - + } public static ApplicationApiDescriptionModel Create() @@ -56,4 +56,4 @@ namespace Volo.Abp.Http.Modeling return subModel; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs index db5a5eb37a..3c4b1ee538 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs @@ -16,7 +16,7 @@ namespace Volo.Abp.Http.Modeling public Dictionary Actions { get; set; } - private ControllerApiDescriptionModel() + public ControllerApiDescriptionModel() { } @@ -79,4 +79,4 @@ namespace Volo.Abp.Http.Modeling return $"[ControllerApiDescriptionModel {ControllerName}]"; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs index 04b5ea1bc9..3515ee3129 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs @@ -7,9 +7,9 @@ namespace Volo.Abp.Http.Modeling { public string Type { get; set; } - private ControllerInterfaceApiDescriptionModel() + public ControllerInterfaceApiDescriptionModel() { - + } public static ControllerInterfaceApiDescriptionModel Create(Type type) @@ -20,4 +20,4 @@ namespace Volo.Abp.Http.Modeling }; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs index b4e272c2f3..49e51fed17 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.Http.Modeling public object DefaultValue { get; set; } - private MethodParameterApiDescriptionModel() + public MethodParameterApiDescriptionModel() { } diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs index b879b90135..5c7c53745c 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs @@ -11,22 +11,22 @@ namespace Volo.Abp.Http.Modeling /// /// "app". /// - public const string DefaultRootPath = "app"; + public const string DefaultRootPath = "app"; /// /// "Default". /// - public const string DefaultRemoteServiceName = "Default"; - + public const string DefaultRemoteServiceName = "Default"; + public string RootPath { get; set; } public string RemoteServiceName { get; set; } public IDictionary Controllers { get; set; } - private ModuleApiDescriptionModel() + public ModuleApiDescriptionModel() { - + } public static ModuleApiDescriptionModel Create(string rootPath, string remoteServiceName) @@ -53,7 +53,7 @@ namespace Volo.Abp.Http.Modeling { return Controllers.GetOrAdd(uniqueName, () => ControllerApiDescriptionModel.Create(name, type, ignoredInterfaces)); } - + public ModuleApiDescriptionModel CreateSubModel(string[] controllers, string[] actions) { var subModel = Create(RootPath, RemoteServiceName); @@ -69,4 +69,4 @@ namespace Volo.Abp.Http.Modeling return subModel; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs index 675ba8bf54..8bdead565e 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs @@ -24,7 +24,7 @@ namespace Volo.Abp.Http.Modeling public string DescriptorName { get; set; } - private ParameterApiDescriptionModel() + public ParameterApiDescriptionModel() { } diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs index 83fa4bb6be..291abf09ae 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs @@ -11,7 +11,7 @@ namespace Volo.Abp.Http.Modeling public string TypeSimple { get; set; } - private ReturnValueApiDescriptionModel() + public ReturnValueApiDescriptionModel() { } diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs index 4b0b0b870c..6114ed2ee6 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.Http.Modeling public PropertyApiDescriptionModel[] Properties { get; set; } - private TypeApiDescriptionModel() + public TypeApiDescriptionModel() { } diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xml b/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xml new file mode 100644 index 0000000000..bc5a74a236 --- /dev/null +++ b/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd b/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo.Abp.Json.Newtonsoft.csproj b/framework/src/Volo.Abp.Json.Newtonsoft/Volo.Abp.Json.Newtonsoft.csproj new file mode 100644 index 0000000000..dd6cdc06ae --- /dev/null +++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo.Abp.Json.Newtonsoft.csproj @@ -0,0 +1,25 @@ + + + + + + + netstandard2.0 + Volo.Abp.Json.Newtonsoft + Volo.Abp.Json.Newtonsoft + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + + + + + diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/AbpJsonModule.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/AbpJsonModule.cs new file mode 100644 index 0000000000..a502239e19 --- /dev/null +++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/AbpJsonModule.cs @@ -0,0 +1,21 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; +using Volo.Abp.Json.Microsoft; +using Volo.Abp.Json.Newtonsoft; +using Volo.Abp.Modularity; + +namespace Volo.Abp.Json +{ + [DependsOn(typeof(AbpJsonModule))] + public class AbpJsonNewtonsoftModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.Converters.Add(); + }); + } + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs similarity index 100% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs rename to framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs similarity index 100% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs rename to framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializer.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializer.cs similarity index 98% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializer.cs rename to framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializer.cs index 20e49ac817..e241484719 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializer.cs +++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializer.cs @@ -9,6 +9,7 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Json.Newtonsoft { + [Dependency(ReplaceServices = true)] public class NewtonsoftJsonSerializer : IJsonSerializer, ITransientDependency { private static readonly CamelCaseExceptDictionaryKeysResolver SharedCamelCaseExceptDictionaryKeysResolver = diff --git a/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj b/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj index 4e891a687d..ddf8cfba65 100644 --- a/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj +++ b/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj @@ -14,10 +14,6 @@ - - - - diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs index c3ea13da43..2899a8ed6b 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs @@ -1,4 +1,7 @@ -using Volo.Abp.Json.Newtonsoft; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; +using Volo.Abp.Json.Microsoft; using Volo.Abp.Modularity; using Volo.Abp.Timing; @@ -9,10 +12,7 @@ namespace Volo.Abp.Json { public override void ConfigureServices(ServiceConfigurationContext context) { - Configure(options => - { - options.Converters.Add(); - }); + context.Services.TryAddEnumerable(ServiceDescriptor.Transient, AbpJsonSerializerOptionsSetup>()); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonOptions.cs index 9449aa338d..239d7864cd 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonOptions.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonOptions.cs @@ -7,4 +7,4 @@ /// public string DefaultDateTimeFormat { get; set; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializer.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializer.cs new file mode 100644 index 0000000000..55adc67ad4 --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializer.cs @@ -0,0 +1,49 @@ +using System; +using System.Text.Json; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Json.Microsoft +{ + public class AbpJsonSerializer : IJsonSerializer, ITransientDependency + { + protected AbpJsonSerializerOptions Options { get; } + + public AbpJsonSerializer(IOptions options) + { + Options = options.Value; + } + + public string Serialize(object obj, bool camelCase = true, bool indented = false) + { + return JsonSerializer.Serialize(obj, CreateJsonSerializerOptions(camelCase, indented)); + } + + public T Deserialize(string jsonString, bool camelCase = true) + { + return JsonSerializer.Deserialize(jsonString, CreateJsonSerializerOptions(camelCase)); + } + + public object Deserialize(Type type, string jsonString, bool camelCase = true) + { + return JsonSerializer.Deserialize(jsonString, type, CreateJsonSerializerOptions(camelCase)); + } + + protected virtual JsonSerializerOptions CreateJsonSerializerOptions(bool camelCase = true, bool indented = false) + { + var settings = new JsonSerializerOptions(Options.JsonSerializerOptions); + + if (camelCase) + { + settings.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + } + + if (indented) + { + settings.WriteIndented = true; + } + + return settings; + } + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptions.cs new file mode 100644 index 0000000000..bbf92c77f4 --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptions.cs @@ -0,0 +1,18 @@ +using System.Text.Json; + +namespace Volo.Abp.Json.Microsoft +{ + public class AbpJsonSerializerOptions + { + public JsonSerializerOptions JsonSerializerOptions { get; } + + public AbpJsonSerializerOptions() + { + //TODO:Defaults? + //https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.Core/src/JsonOptions.cs#L18 + //https://github.com/dotnet/runtime/blob/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerDefaults.cs + + JsonSerializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); + } + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptionsSetup.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptionsSetup.cs new file mode 100644 index 0000000000..b06e884d4c --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptionsSetup.cs @@ -0,0 +1,23 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.Json.Microsoft.JsonConverters; + +namespace Volo.Abp.Json.Microsoft +{ + public class AbpJsonSerializerOptionsSetup : IConfigureOptions + { + protected IServiceProvider ServiceProvider { get; } + + public AbpJsonSerializerOptionsSetup(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + public void Configure(AbpJsonSerializerOptions options) + { + options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService()); + options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService()); + } + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpDateTimeConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpDateTimeConverter.cs new file mode 100644 index 0000000000..e563ee8aac --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpDateTimeConverter.cs @@ -0,0 +1,38 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Timing; + +namespace Volo.Abp.Json.Microsoft.JsonConverters +{ + public class AbpDateTimeConverter : JsonConverter, ITransientDependency + { + private readonly IClock _clock; + private readonly AbpJsonOptions _options; + + public AbpDateTimeConverter(IClock clock, IOptions abpJsonOptions) + { + _clock = clock; + _options = abpJsonOptions.Value; + } + + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return _clock.Normalize(reader.GetDateTime()); + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + if (_options.DefaultDateTimeFormat.IsNullOrWhiteSpace()) + { + writer.WriteStringValue(_clock.Normalize(value)); + } + else + { + writer.WriteStringValue(_clock.Normalize(value).ToString(_options.DefaultDateTimeFormat)); + } + } + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpNullableDateTimeConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpNullableDateTimeConverter.cs new file mode 100644 index 0000000000..a072d1426c --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpNullableDateTimeConverter.cs @@ -0,0 +1,50 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Timing; + +namespace Volo.Abp.Json.Microsoft.JsonConverters +{ + public class AbpNullableDateTimeConverter : JsonConverter, ITransientDependency + { + private readonly IClock _clock; + private readonly AbpJsonOptions _options; + + public AbpNullableDateTimeConverter(IClock clock, IOptions abpJsonOptions) + { + _clock = clock; + _options = abpJsonOptions.Value; + } + + public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TryGetDateTime(out var dateTime)) + { + return _clock.Normalize(dateTime); + } + + return null; + } + + public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) + { + if (value == null) + { + writer.WriteNullValue(); + } + else + { + if (_options.DefaultDateTimeFormat.IsNullOrWhiteSpace()) + { + writer.WriteStringValue(_clock.Normalize(value.Value)); + } + else + { + writer.WriteStringValue(_clock.Normalize(value.Value).ToString(_options.DefaultDateTimeFormat)); + } + } + } + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/ObjectToInferredTypesConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/ObjectToInferredTypesConverter.cs new file mode 100644 index 0000000000..af29e55a3a --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/ObjectToInferredTypesConverter.cs @@ -0,0 +1,54 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Volo.Abp.Json.Microsoft.JsonConverters +{ + public class ObjectToInferredTypesConverter : JsonConverter + { + public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.True) + { + return true; + } + + if (reader.TokenType == JsonTokenType.False) + { + return false; + } + + if (reader.TokenType == JsonTokenType.Number) + { + if (reader.TryGetInt64(out var l)) + { + return l; + } + + return reader.GetDouble(); + } + + if (reader.TokenType == JsonTokenType.String) + { + if (reader.TryGetDateTime(out var datetime)) + { + return datetime; + } + + return reader.GetString(); + } + + // Use JsonElement as fallback. + // Newtonsoft uses JArray or JObject. + using (var document = JsonDocument.ParseValue(ref reader)) + { + return document.RootElement.Clone(); + } + } + + public override void Write(Utf8JsonWriter writer, object objectToWrite, JsonSerializerOptions options) + { + throw new InvalidOperationException("Should not get here."); + } + } +} diff --git a/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj b/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj index df04ab95df..64352257f3 100644 --- a/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj +++ b/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj @@ -19,10 +19,6 @@ - - - - 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 9b1f1617f6..c13fb643bd 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 @@ -1,19 +1,13 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text.Json; using Microsoft.Extensions.Localization; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; namespace Volo.Abp.Localization.Json { public static class JsonLocalizationDictionaryBuilder { - private static readonly JsonSerializerSettings SharedJsonSerializerSettings = new JsonSerializerSettings - { - ContractResolver = new CamelCasePropertyNamesContractResolver() - }; - /// /// Builds an from given file. /// @@ -39,8 +33,13 @@ namespace Volo.Abp.Localization.Json JsonLocalizationFile jsonFile; try { - jsonFile = JsonConvert.DeserializeObject( - jsonString, SharedJsonSerializerSettings); + var options = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + DictionaryKeyPolicy = JsonNamingPolicy.CamelCase + }; + + jsonFile = JsonSerializer.Deserialize(jsonString, options); } catch (JsonException ex) { @@ -80,4 +79,4 @@ namespace Volo.Abp.Localization.Json return new StaticLocalizationDictionary(cultureCode, dictionary); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationFile.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationFile.cs index c2dc911532..2af738221a 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationFile.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Json/JsonLocalizationFile.cs @@ -9,11 +9,11 @@ namespace Volo.Abp.Localization.Json /// public string Culture { get; set; } - public Dictionary Texts { get; } + public Dictionary Texts { get; set; } public JsonLocalizationFile() { Texts = new Dictionary(); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/Utf8JsonMemoryDbSerializer.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/Utf8JsonMemoryDbSerializer.cs index e68b4b6f37..e0040a678d 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/Utf8JsonMemoryDbSerializer.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/Utf8JsonMemoryDbSerializer.cs @@ -1,52 +1,27 @@ using System; -using System.Reflection; -using System.Text; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; +using System.Text.Json; +using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; -using Volo.Abp.Json; namespace Volo.Abp.Domain.Repositories.MemoryDb { public class Utf8JsonMemoryDbSerializer : IMemoryDbSerializer, ITransientDependency { - private static readonly JsonSerializerSettings MemoryDbSerializerSettings; + protected Utf8JsonMemoryDbSerializerOptions Options { get; } - static Utf8JsonMemoryDbSerializer() + public Utf8JsonMemoryDbSerializer(IOptions options) { - MemoryDbSerializerSettings = new JsonSerializerSettings - { - ContractResolver = new ResolverWithPrivateSetters(), - ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor - }; + Options = options.Value; } byte[] IMemoryDbSerializer.Serialize(object obj) { - var jsonString = JsonConvert.SerializeObject(obj, MemoryDbSerializerSettings); - return Encoding.UTF8.GetBytes(jsonString); + return JsonSerializer.SerializeToUtf8Bytes(obj, Options.JsonSerializerOptions); } public object Deserialize(byte[] value, Type type) { - var jsonString = Encoding.UTF8.GetString(value); - return JsonConvert.DeserializeObject(jsonString, type, MemoryDbSerializerSettings); - } - - public class ResolverWithPrivateSetters : DefaultContractResolver - { - protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) - { - var prop = base.CreateProperty(member, memberSerialization); - if (prop.Writable) - { - return prop; - } - - prop.Writable = member.As()?.GetSetMethod(true) != null; - - return prop; - } + return JsonSerializer.Deserialize(value, type, Options.JsonSerializerOptions); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/Utf8JsonMemoryDbSerializerOptions.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/Utf8JsonMemoryDbSerializerOptions.cs new file mode 100644 index 0000000000..a31e9d5eff --- /dev/null +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/Utf8JsonMemoryDbSerializerOptions.cs @@ -0,0 +1,14 @@ +using System.Text.Json; + +namespace Volo.Abp.Domain.Repositories.MemoryDb +{ + public class Utf8JsonMemoryDbSerializerOptions + { + public JsonSerializerOptions JsonSerializerOptions { get; } + + public Utf8JsonMemoryDbSerializerOptions() + { + JsonSerializerOptions = new JsonSerializerOptions(); + } + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Authentication.OAuth.Tests/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Authentication.OAuth.Tests/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction_Tests.cs index bf869fc809..dd53e82167 100644 --- a/framework/test/Volo.Abp.AspNetCore.Authentication.OAuth.Tests/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Authentication.OAuth.Tests/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction_Tests.cs @@ -1,7 +1,6 @@ using System.Linq; using System.Security.Claims; using System.Text.Json; -using Newtonsoft.Json.Linq; using Shouldly; using Volo.Abp.Security.Claims; using Xunit; diff --git a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpAspNetCoreTestBase.cs b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpAspNetCoreTestBase.cs index dd5edff807..3c5571f115 100644 --- a/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpAspNetCoreTestBase.cs +++ b/framework/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AbpAspNetCoreTestBase.cs @@ -1,10 +1,8 @@ using System.Globalization; using System.Net; using System.Net.Http; -using System.Net.Http.Headers; +using System.Text.Json; using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; using Shouldly; using Volo.Abp.AspNetCore.TestBase; @@ -18,16 +16,10 @@ namespace Volo.Abp.AspNetCore public abstract class AbpAspNetCoreTestBase : AbpAspNetCoreIntegratedTestBase where TStartup : class { - private static readonly JsonSerializerSettings SharedJsonSerializerSettings = - new JsonSerializerSettings - { - ContractResolver = new CamelCasePropertyNamesContractResolver() - }; - protected virtual async Task GetResponseAsObjectAsync(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) { var strResponse = await GetResponseAsStringAsync(url, expectedStatusCode); - return JsonConvert.DeserializeObject(strResponse, SharedJsonSerializerSettings); + return JsonSerializer.Deserialize(strResponse, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); } protected virtual async Task GetResponseAsStringAsync(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) @@ -49,4 +41,4 @@ namespace Volo.Abp.AspNetCore } } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/AbpMemoryDbTestModule.cs b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/AbpMemoryDbTestModule.cs index 7e5d9fcb6b..05839d5c8e 100644 --- a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/AbpMemoryDbTestModule.cs +++ b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/AbpMemoryDbTestModule.cs @@ -4,14 +4,16 @@ using Volo.Abp.Modularity; using Volo.Abp.TestApp.MemoryDb; using Volo.Abp.Data; using Volo.Abp.Autofac; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Repositories.MemoryDb; using Volo.Abp.TestApp; using Volo.Abp.TestApp.Domain; namespace Volo.Abp.MemoryDb { [DependsOn( - typeof(TestAppModule), - typeof(AbpMemoryDbModule), + typeof(TestAppModule), + typeof(AbpMemoryDbModule), typeof(AbpAutofacModule))] public class AbpMemoryDbTestModule : AbpModule { @@ -29,6 +31,11 @@ namespace Volo.Abp.MemoryDb options.AddDefaultRepositories(); options.AddRepository(); }); + + Configure(options => + { + options.JsonSerializerOptions.Converters.Add(new EntityJsonConverter()); + }); } } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests_With_Int_Pk.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests_With_Int_Pk.cs index f873fe4265..821a80492b 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests_With_Int_Pk.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/Repository_Basic_Tests_With_Int_Pk.cs @@ -1,4 +1,5 @@ using System.Linq; +using System.Text.Json; using System.Threading.Tasks; using Shouldly; using Volo.Abp.Domain.Repositories; diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo.Docs.Domain.Shared.csproj b/modules/docs/src/Volo.Docs.Domain.Shared/Volo.Docs.Domain.Shared.csproj index 99066c0b9b..d655e05df0 100644 --- a/modules/docs/src/Volo.Docs.Domain.Shared/Volo.Docs.Domain.Shared.csproj +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo.Docs.Domain.Shared.csproj @@ -13,5 +13,9 @@ + + + + diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs index 37b49f2d8a..add06e1e14 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs @@ -1,5 +1,7 @@ using Volo.Abp.Application; -using Volo.Abp.Json.Newtonsoft; +using Volo.Abp.FeatureManagement.JsonConverters; +using Volo.Abp.Json; +using Volo.Abp.Json.Microsoft; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; @@ -7,7 +9,8 @@ namespace Volo.Abp.FeatureManagement { [DependsOn( typeof(AbpFeatureManagementDomainSharedModule), - typeof(AbpDddApplicationModule) + typeof(AbpDddApplicationModule), + typeof(AbpJsonModule) )] public class AbpFeatureManagementApplicationContractsModule : AbpModule { @@ -18,9 +21,9 @@ namespace Volo.Abp.FeatureManagement options.FileSets.AddEmbedded(); }); - Configure(options => + Configure(options => { - options.Converters.Add(); + options.JsonSerializerOptions.Converters.Add(new StringValueTypeJsonConverter()); }); } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/LocalizableStringInfoJsonConverter.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/LocalizableStringInfoJsonConverter.cs new file mode 100644 index 0000000000..e9f5cf599c --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/LocalizableStringInfoJsonConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Volo.Abp.Validation.StringValues; + +namespace Volo.Abp.FeatureManagement.JsonConverters +{ + public class LocalizableStringInfoJsonConverter : JsonConverter + { + public override LocalizableStringInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var rootElement = JsonDocument.ParseValue(ref reader).RootElement; + return new LocalizableStringInfo( + rootElement.GetProperty("ResourceName").GetString(), + rootElement.GetProperty("Name").GetString() + ); + } + + public override void Write(Utf8JsonWriter writer, LocalizableStringInfo value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value); + } + } +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemJsonConverter.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemJsonConverter.cs new file mode 100644 index 0000000000..59b2f77c6b --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemJsonConverter.cs @@ -0,0 +1,36 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Volo.Abp.Validation.StringValues; + +namespace Volo.Abp.FeatureManagement.JsonConverters +{ + public class SelectionStringValueItemJsonConverter : JsonConverter + { + public override ISelectionStringValueItem Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var rootElement = JsonDocument.ParseValue(ref reader).RootElement; + + var jsonSerializerOptions = new JsonSerializerOptions(); + jsonSerializerOptions.Converters.Add(new LocalizableStringInfoJsonConverter()); + + return new LocalizableSelectionStringValueItem + { + Value = rootElement.GetProperty("Value").GetString(), + DisplayText = JsonSerializer.Deserialize(rootElement.GetProperty("DisplayText").GetRawText(), jsonSerializerOptions) + }; + } + + public override void Write(Utf8JsonWriter writer, ISelectionStringValueItem value, JsonSerializerOptions options) + { + if (value.GetType() == typeof(LocalizableStringInfo)) + { + JsonSerializer.Serialize(writer, (LocalizableSelectionStringValueItem)value); + } + else + { + throw new JsonException("Unknown ISelectionStringValueItem type!"); + } + } + } +} 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 new file mode 100644 index 0000000000..b523dba20b --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemSourceJsonConverter.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; +using Volo.Abp.Validation.StringValues; + +namespace Volo.Abp.FeatureManagement.JsonConverters +{ + public class SelectionStringValueItemSourceJsonConverter : JsonConverter + { + public override ISelectionStringValueItemSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var rootElement = JsonDocument.ParseValue(ref reader).RootElement; + var jsonSerializerOptions = new JsonSerializerOptions(); + jsonSerializerOptions.Converters.Add(new SelectionStringValueItemJsonConverter()); + + var selectionStringValueItem = + JsonSerializer.Deserialize>(rootElement.GetProperty("Items").GetRawText(), jsonSerializerOptions) ?? + new List(); + + return new StaticSelectionStringValueItemSource(selectionStringValueItem.ToArray()); + } + + public override void Write(Utf8JsonWriter writer, ISelectionStringValueItemSource value, JsonSerializerOptions options) + { + if (value.GetType() == typeof(StaticSelectionStringValueItemSource)) + { + JsonSerializer.Serialize(writer, (StaticSelectionStringValueItemSource)value); + } + else + { + throw new JsonException("Unknown ISelectionStringValueItemSource type!"); + } + } + } +} 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 new file mode 100644 index 0000000000..5cdaf352bb --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs @@ -0,0 +1,47 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Volo.Abp.Validation.StringValues; + +namespace Volo.Abp.FeatureManagement.JsonConverters +{ + public class StringValueTypeJsonConverter : JsonConverter + { + public override IStringValueType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var rootElement = JsonDocument.ParseValue(ref reader).RootElement; + var jsonSerializerOptions = new JsonSerializerOptions(); + jsonSerializerOptions.Converters.Add(new ValueValidatorJsonConverter()); + jsonSerializerOptions.Converters.Add(new SelectionStringValueItemSourceJsonConverter()); + + var name = rootElement.GetProperty("Name").GetString(); + return name switch + { + "SelectionStringValueType" => JsonSerializer.Deserialize(rootElement.GetRawText(), jsonSerializerOptions), + "FreeTextStringValueType" => JsonSerializer.Deserialize(rootElement.GetRawText(), jsonSerializerOptions), + "ToggleStringValueType" => JsonSerializer.Deserialize(rootElement.GetRawText(), jsonSerializerOptions), + _ => throw new ArgumentException($"{nameof(IStringValueType)} named {name} was not found!") + }; + } + + public override void Write(Utf8JsonWriter writer, IStringValueType value, JsonSerializerOptions options) + { + if (value.GetType() == typeof(FreeTextStringValueType)) + { + JsonSerializer.Serialize(writer, (FreeTextStringValueType)value); + } + else if (value.GetType() == typeof(SelectionStringValueType)) + { + JsonSerializer.Serialize(writer, (SelectionStringValueType)value); + } + else if (value.GetType() == typeof(ToggleStringValueType)) + { + JsonSerializer.Serialize(writer, (ToggleStringValueType)value); + } + else + { + throw new JsonException("Unknown IStringValueType type!"); + } + } + } +} 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 new file mode 100644 index 0000000000..cefa97a6aa --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using Volo.Abp.Json.Microsoft.JsonConverters; +using Volo.Abp.Validation.StringValues; + +namespace Volo.Abp.FeatureManagement.JsonConverters +{ + public class ValueValidatorJsonConverter : JsonConverter + { + public override IValueValidator Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var rootElement = JsonDocument.ParseValue(ref reader).RootElement; + var valueValidator = CreateValueValidatorByName(rootElement.GetProperty("Name").GetString()); + + var deserializeOptions = new JsonSerializerOptions(); + deserializeOptions.Converters.Add(new ObjectToInferredTypesConverter()); + var properties = JsonSerializer.Deserialize>(rootElement.GetProperty("Properties").GetRawText(), deserializeOptions); + if (properties != null && properties.Any()) + { + foreach (var property in properties) + { + valueValidator.Properties[property.Key] = property.Value; + } + } + + return valueValidator; + } + + public override void Write(Utf8JsonWriter writer, IValueValidator value, JsonSerializerOptions options) + { + if (value.GetType() == typeof(AlwaysValidValueValidator)) + { + JsonSerializer.Serialize(writer, (AlwaysValidValueValidator)value); + } + else if (value.GetType() == typeof(BooleanValueValidator)) + { + JsonSerializer.Serialize(writer, (BooleanValueValidator)value); + } + else if (value.GetType() == typeof(NumericValueValidator)) + { + JsonSerializer.Serialize(writer, (NumericValueValidator)value); + } + else if (value.GetType() == typeof(StringValueValidator)) + { + JsonSerializer.Serialize(writer, (StringValueValidator)value); + } + else + { + throw new JsonException("Unknown IValueValidator type!"); + } + } + + protected virtual IValueValidator CreateValueValidatorByName(string name) + { + return name switch + { + "NULL" => new AlwaysValidValueValidator(), + "BOOLEAN" => new BooleanValueValidator(), + "NUMERIC" => new NumericValueValidator(), + "STRING" => new StringValueValidator(), + _ => throw new ArgumentException($"{nameof(IValueValidator)} named {name} was not found!") + }; + } + } +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/StringValueTypeJsonConverter.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/StringValueTypeJsonConverter.cs deleted file mode 100644 index 0ee276cce1..0000000000 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/StringValueTypeJsonConverter.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Validation.StringValues; - -namespace Volo.Abp.FeatureManagement -{ - public class StringValueTypeJsonConverter : JsonConverter, ITransientDependency - { - public override bool CanWrite => false; - - public override bool CanConvert(Type objectType) - { - return objectType == typeof(IStringValueType); - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new NotImplementedException("This method should not be called to write (since CanWrite is false)."); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - if (reader.TokenType != JsonToken.StartObject) - { - return null; - } - - var jsonObject = JObject.Load(reader); - - var stringValue = CreateStringValueTypeByName(jsonObject, jsonObject["name"].ToString()); - foreach (var o in serializer.Deserialize>( - new JsonTextReader(new StringReader(jsonObject["properties"].ToString())))) - { - stringValue[o.Key] = o.Value; - } - - stringValue.Validator = CreateValueValidatorByName(jsonObject["validator"], jsonObject["validator"]["name"].ToString()); - foreach (var o in serializer.Deserialize>( - new JsonTextReader(new StringReader(jsonObject["validator"]["properties"].ToString())))) - { - stringValue.Validator[o.Key] = o.Value; - } - - return stringValue; - } - - protected virtual IStringValueType CreateStringValueTypeByName(JObject jObject, string name) - { - if (name == "SelectionStringValueType") - { - var selectionStringValueType = new SelectionStringValueType(); - if (jObject["itemSource"].HasValues) - { - selectionStringValueType.ItemSource = new StaticSelectionStringValueItemSource(jObject["itemSource"]["items"] - .Select(item => new LocalizableSelectionStringValueItem() - { - Value = item["value"].ToString(), - DisplayText = new LocalizableStringInfo(item["displayText"]["resourceName"].ToString(), item["displayText"]["name"].ToString()) - }).ToArray()); - } - - return selectionStringValueType; - } - - return name switch - { - "FreeTextStringValueType" => new FreeTextStringValueType(), - "ToggleStringValueType" => new ToggleStringValueType(), - _ => throw new ArgumentException($"{nameof(IStringValueType)} named {name} was not found!") - }; - } - - protected virtual IValueValidator CreateValueValidatorByName(JToken jObject, string name) - { - return name switch - { - "NULL" => new AlwaysValidValueValidator(), - "BOOLEAN" => new BooleanValueValidator(), - "NUMERIC" => new NumericValueValidator(), - "STRING" => new StringValueValidator(), - _ => throw new ArgumentException($"{nameof(IValueValidator)} named {name} was not found!") - }; - } - } -} 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 1b7553b773..4e5d4b20a3 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 @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json; using Shouldly; using Volo.Abp.Json; using Volo.Abp.Validation.StringValues; @@ -66,9 +66,11 @@ namespace Volo.Abp.FeatureManagement } }; - var serialized = _jsonSerializer.Serialize(featureListDto, indented: true); + var serialized = _jsonSerializer.Serialize(featureListDto); + var featureListDto2 = _jsonSerializer.Deserialize(serialized); + featureListDto2.ShouldNotBeNull(); featureListDto2.Groups[0].Features[0].ValueType.ShouldBeOfType(); featureListDto2.Groups[0].Features[0].ValueType.Validator.ShouldBeOfType(); diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index 29cb13d9f3..3df9140805 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -109,6 +109,7 @@ $projects = ( "framework/src/Volo.Abp.Http", "framework/src/Volo.Abp.IdentityModel", "framework/src/Volo.Abp.Json", + "framework/src/Volo.Abp.Json.Newtonsoft", "framework/src/Volo.Abp.Ldap", "framework/src/Volo.Abp.Localization.Abstractions", "framework/src/Volo.Abp.MailKit", From 0bde769e116d578e0499770f81a038446f8a61ff Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 27 Oct 2020 14:48:54 +0800 Subject: [PATCH 02/17] Revert to use Newtonsoft for IAuditSerializer. Add JsonNetAuditSerializer_Test. --- .../Volo.Abp.Auditing.csproj | 4 ++ .../Abp/Auditing/AuditingContractResolver.cs | 43 ++++++++++++ .../AuditingRuntimeIgnoreConverter.cs | 45 ------------- .../Abp/Auditing/JsonNetAuditSerializer.cs | 27 ++++++-- .../Auditing/JsonNetAuditSerializer_Test.cs | 67 +++++++++++++++++++ 5 files changed, 135 insertions(+), 51 deletions(-) create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingContractResolver.cs delete mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingRuntimeIgnoreConverter.cs create mode 100644 framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/JsonNetAuditSerializer_Test.cs diff --git a/framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj b/framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj index 4ac2420c8f..b3548a949b 100644 --- a/framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj +++ b/framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj @@ -22,5 +22,9 @@ + + + + diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingContractResolver.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingContractResolver.cs new file mode 100644 index 0000000000..a88de55aea --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingContractResolver.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace Volo.Abp.Auditing +{ + public class AuditingContractResolver : CamelCasePropertyNamesContractResolver + { + private readonly List _ignoredTypes; + + public AuditingContractResolver(List ignoredTypes) + { + _ignoredTypes = ignoredTypes; + } + + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + var property = base.CreateProperty(member, memberSerialization); + + if (_ignoredTypes.Any(ignoredType => ignoredType.GetTypeInfo().IsAssignableFrom(property.PropertyType))) + { + property.ShouldSerialize = instance => false; + return property; + } + + if (member.DeclaringType != null && (member.DeclaringType.IsDefined(typeof(DisableAuditingAttribute)) || member.DeclaringType.IsDefined(typeof(JsonIgnoreAttribute)))) + { + property.ShouldSerialize = instance => false; + return property; + } + + if (member.IsDefined(typeof(DisableAuditingAttribute)) || member.IsDefined(typeof(JsonIgnoreAttribute))) + { + property.ShouldSerialize = instance => false; + } + + return property; + } + } +} diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingRuntimeIgnoreConverter.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingRuntimeIgnoreConverter.cs deleted file mode 100644 index 240b2581ab..0000000000 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingRuntimeIgnoreConverter.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Volo.Abp.Auditing -{ - public class AuditingRuntimeIgnoreConverter : JsonConverter> - { - private readonly List _ignoredTypes; - - public AuditingRuntimeIgnoreConverter(List ignoredTypes) - { - _ignoredTypes = ignoredTypes; - } - - public override Dictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - throw new JsonException(); - } - - public override void Write(Utf8JsonWriter writer, Dictionary value, JsonSerializerOptions options) - { - var newDictionary = new Dictionary(); - foreach (var item in value.Where(x => x.Value != null)) - { - if (item.GetType().IsDefined(typeof(DisableAuditingAttribute), true) || - item.GetType().IsDefined(typeof(JsonIgnoreAttribute), true)) - { - continue; - } - - if (_ignoredTypes.Any(x => x.IsInstanceOfType(item.Value))) - { - continue; - } - - newDictionary[item.Key] = item.Value; - } - - JsonSerializer.Serialize(writer, newDictionary); - } - } -} diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs index d11886e5a7..b1ce95675b 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs @@ -1,5 +1,5 @@ -using System.Text.Json; using Microsoft.Extensions.Options; +using Newtonsoft.Json; using Volo.Abp.DependencyInjection; namespace Volo.Abp.Auditing @@ -16,14 +16,29 @@ namespace Volo.Abp.Auditing public string Serialize(object obj) { - return JsonSerializer.Serialize(obj, GetJsonSerializerOptions()); + return JsonConvert.SerializeObject(obj, GetSharedJsonSerializerSettings()); } - private JsonSerializerOptions GetJsonSerializerOptions() + private static readonly object SyncObj = new object(); + private static JsonSerializerSettings _sharedJsonSerializerSettings; + + private JsonSerializerSettings GetSharedJsonSerializerSettings() { - var options = new JsonSerializerOptions(); - options.Converters.Add(new AuditingRuntimeIgnoreConverter(Options.IgnoredTypes)); - return options; + if (_sharedJsonSerializerSettings == null) + { + lock (SyncObj) + { + if (_sharedJsonSerializerSettings == null) + { + _sharedJsonSerializerSettings = new JsonSerializerSettings + { + ContractResolver = new AuditingContractResolver(Options.IgnoredTypes) + }; + } + } + } + + return _sharedJsonSerializerSettings; } } } diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/JsonNetAuditSerializer_Test.cs b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/JsonNetAuditSerializer_Test.cs new file mode 100644 index 0000000000..da98f49bd6 --- /dev/null +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/JsonNetAuditSerializer_Test.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Xunit; + +namespace Volo.Abp.Auditing +{ + public class JsonNetAuditSerializer_Test : AbpAuditingTestBase + { + private readonly JsonNetAuditSerializer _jsonNetAuditSerializer; + + public JsonNetAuditSerializer_Test() + { + _jsonNetAuditSerializer = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + services.Configure(options => + { + options.IgnoredTypes.Add(typeof(DateTime)); + }); + + base.AfterAddApplication(services); + } + + [Fact] + public void Serialize_Test() + { + var arguments = new Dictionary + { + {"input", new InputDto {PersonData = "IdCard:123123"}}, + {"input2", new Input2Dto {UserName = "admin", Password = "1q2w3E*", Birthday = DateTime.Now}} + }; + + var str = _jsonNetAuditSerializer.Serialize(arguments); + + str.ShouldNotContain("IdCard"); + str.ShouldNotContain("1q2w3E*"); + str.ShouldNotContain("Birthday"); + + str.ShouldContain("UserName"); + str.ShouldContain("admin"); + } + + + [DisableAuditing] + class InputDto + { + public string PersonData { get; set; } + } + + class Input2Dto + { + public string UserName { get; set; } + + [DisableAuditing] + public string Password { get; set; } + + [Newtonsoft.Json.JsonIgnore] + public string PrivateEmail { get; set; } + + public DateTime Birthday { get; set; } + } + } +} From 0778e380be9488bec56607776889e57498b29da7 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 27 Oct 2020 15:24:23 +0800 Subject: [PATCH 03/17] Rename namespaces. --- .../Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs | 2 +- .../Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs | 4 ++-- .../ValueConverters/AbpJsonValueConverter.cs | 2 +- .../ValueConverters/ExtraPropertiesValueConverter.cs | 2 +- .../Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/AbpJsonModule.cs | 2 +- framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs | 1 - .../Volo/Abp/Json/{Microsoft => }/AbpJsonSerializer.cs | 2 +- .../Abp/Json/{Microsoft => }/AbpJsonSerializerOptions.cs | 2 +- .../Json/{Microsoft => }/AbpJsonSerializerOptionsSetup.cs | 5 +++-- .../{Microsoft => }/JsonConverters/AbpDateTimeConverter.cs | 2 +- .../JsonConverters/AbpNullableDateTimeConverter.cs | 2 +- .../JsonConverters/ObjectToInferredTypesConverter.cs | 2 +- .../Volo/Abp/MemoryDb/AbpMemoryDbTestModule.cs | 1 + .../Volo/Abp/MemoryDb/JsonConverters}/EntityJsonConverter.cs | 3 ++- .../AbpFeatureManagementApplicationContractsModule.cs | 2 +- .../JsonConverters/ValueValidatorJsonConverter.cs | 2 +- 16 files changed, 19 insertions(+), 17 deletions(-) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/{Microsoft => }/AbpJsonSerializer.cs (97%) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/{Microsoft => }/AbpJsonSerializerOptions.cs (94%) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/{Microsoft => }/AbpJsonSerializerOptionsSetup.cs (90%) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/{Microsoft => }/JsonConverters/AbpDateTimeConverter.cs (96%) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/{Microsoft => }/JsonConverters/AbpNullableDateTimeConverter.cs (96%) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/{Microsoft => }/JsonConverters/ObjectToInferredTypesConverter.cs (96%) rename framework/{src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities => test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters}/EntityJsonConverter.cs (92%) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs index f35721c3c0..0897c69ed3 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs @@ -35,7 +35,7 @@ using Volo.Abp.Http; using Volo.Abp.DynamicProxy; using Volo.Abp.GlobalFeatures; using Volo.Abp.Http.Modeling; -using Volo.Abp.Json.Microsoft; +using Volo.Abp.Json; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.UI; 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 f9d58a3918..821b2c9218 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 @@ -2,8 +2,8 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Volo.Abp.Json.Microsoft; -using Volo.Abp.Json.Microsoft.JsonConverters; +using Volo.Abp.Json.JsonConverters; +using Volo.Abp.Json; namespace Volo.Abp.AspNetCore.Mvc.Json { 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 4955a703b3..afce924d59 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 @@ -1,6 +1,6 @@ using System.Text.Json; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Volo.Abp.Json.Microsoft.JsonConverters; +using Volo.Abp.Json.JsonConverters; namespace Volo.Abp.EntityFrameworkCore.ValueConverters { 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 b94a433367..00ce8459a6 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 @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text.Json; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Volo.Abp.Json.Microsoft.JsonConverters; +using Volo.Abp.Json.JsonConverters; using Volo.Abp.ObjectExtending; namespace Volo.Abp.EntityFrameworkCore.ValueConverters diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/AbpJsonModule.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/AbpJsonModule.cs index a502239e19..b040f1afbb 100644 --- a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/AbpJsonModule.cs +++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/AbpJsonModule.cs @@ -1,7 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; -using Volo.Abp.Json.Microsoft; +using Volo.Abp.Json; using Volo.Abp.Json.Newtonsoft; using Volo.Abp.Modularity; diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs index 2899a8ed6b..c5376d0f05 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs @@ -1,7 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; -using Volo.Abp.Json.Microsoft; using Volo.Abp.Modularity; using Volo.Abp.Timing; diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializer.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializer.cs similarity index 97% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializer.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializer.cs index 55adc67ad4..250111fee2 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializer.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializer.cs @@ -3,7 +3,7 @@ using System.Text.Json; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; -namespace Volo.Abp.Json.Microsoft +namespace Volo.Abp.Json { public class AbpJsonSerializer : IJsonSerializer, ITransientDependency { diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptions.cs similarity index 94% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptions.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptions.cs index bbf92c77f4..c1289ce159 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptions.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptions.cs @@ -1,6 +1,6 @@ using System.Text.Json; -namespace Volo.Abp.Json.Microsoft +namespace Volo.Abp.Json { public class AbpJsonSerializerOptions { diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptionsSetup.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptionsSetup.cs similarity index 90% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptionsSetup.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptionsSetup.cs index b06e884d4c..c4b9981199 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/AbpJsonSerializerOptionsSetup.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptionsSetup.cs @@ -1,9 +1,10 @@ using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Volo.Abp.Json.Microsoft.JsonConverters; +using Volo.Abp.Json.JsonConverters; +using Volo.Abp.Json; -namespace Volo.Abp.Json.Microsoft +namespace Volo.Abp.Json { public class AbpJsonSerializerOptionsSetup : IConfigureOptions { diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpDateTimeConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpDateTimeConverter.cs similarity index 96% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpDateTimeConverter.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpDateTimeConverter.cs index e563ee8aac..7523f1e4d9 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpDateTimeConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpDateTimeConverter.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; using Volo.Abp.Timing; -namespace Volo.Abp.Json.Microsoft.JsonConverters +namespace Volo.Abp.Json.JsonConverters { public class AbpDateTimeConverter : JsonConverter, ITransientDependency { diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpNullableDateTimeConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpNullableDateTimeConverter.cs similarity index 96% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpNullableDateTimeConverter.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpNullableDateTimeConverter.cs index a072d1426c..0e1e20bedc 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/AbpNullableDateTimeConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpNullableDateTimeConverter.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; using Volo.Abp.Timing; -namespace Volo.Abp.Json.Microsoft.JsonConverters +namespace Volo.Abp.Json.JsonConverters { public class AbpNullableDateTimeConverter : JsonConverter, ITransientDependency { diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/ObjectToInferredTypesConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/ObjectToInferredTypesConverter.cs similarity index 96% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/ObjectToInferredTypesConverter.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/ObjectToInferredTypesConverter.cs index af29e55a3a..4a3cd5e8df 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Microsoft/JsonConverters/ObjectToInferredTypesConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/ObjectToInferredTypesConverter.cs @@ -2,7 +2,7 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace Volo.Abp.Json.Microsoft.JsonConverters +namespace Volo.Abp.Json.JsonConverters { public class ObjectToInferredTypesConverter : JsonConverter { diff --git a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/AbpMemoryDbTestModule.cs b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/AbpMemoryDbTestModule.cs index 05839d5c8e..6f5d7a3718 100644 --- a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/AbpMemoryDbTestModule.cs +++ b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/AbpMemoryDbTestModule.cs @@ -6,6 +6,7 @@ using Volo.Abp.Data; using Volo.Abp.Autofac; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories.MemoryDb; +using Volo.Abp.MemoryDb.JsonConverters; using Volo.Abp.TestApp; using Volo.Abp.TestApp.Domain; diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityJsonConverter.cs b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs similarity index 92% rename from framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityJsonConverter.cs rename to framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs index d472fd36d0..9a41fd4045 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/EntityJsonConverter.cs +++ b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs @@ -1,8 +1,9 @@ using System; using System.Text.Json; using System.Text.Json.Serialization; +using Volo.Abp.Domain.Entities; -namespace Volo.Abp.Domain.Entities +namespace Volo.Abp.MemoryDb.JsonConverters { public class EntityJsonConverter : JsonConverter { diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs index add06e1e14..3c9303f968 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs @@ -1,7 +1,7 @@ using Volo.Abp.Application; using Volo.Abp.FeatureManagement.JsonConverters; using Volo.Abp.Json; -using Volo.Abp.Json.Microsoft; +using Volo.Abp.Json; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; 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 cefa97a6aa..b525651d73 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 @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; -using Volo.Abp.Json.Microsoft.JsonConverters; +using Volo.Abp.Json.JsonConverters; using Volo.Abp.Validation.StringValues; namespace Volo.Abp.FeatureManagement.JsonConverters From 1e888c241faa4affe2e378327cdf23a00fa20902 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 27 Oct 2020 20:35:33 +0800 Subject: [PATCH 04/17] Refactor. --- .../Abp/Json/AbpJsonSerializerOptionsSetup.cs | 1 - ...ureManagementApplicationContractsModule.cs | 6 ++-- .../JsonSerializerOptionsHelper.cs | 17 +++++++++ .../LocalizableStringInfoJsonConverter.cs | 24 ------------- .../SelectionStringValueItemJsonConverter.cs | 36 ------------------- ...ctionStringValueItemSourceJsonConverter.cs | 12 ++++--- .../StringValueTypeJsonConverter.cs | 22 ++++++------ .../ValueValidatorJsonConverter.cs | 19 +++++----- .../AbpFeatureManagementHttpApiModule.cs | 10 +++++- .../StringValueJsonConverter_Tests.cs | 2 +- 10 files changed, 60 insertions(+), 89 deletions(-) create mode 100644 modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/JsonSerializerOptionsHelper.cs delete mode 100644 modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/LocalizableStringInfoJsonConverter.cs delete mode 100644 modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemJsonConverter.cs diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptionsSetup.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptionsSetup.cs index c4b9981199..16e8119731 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptionsSetup.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptionsSetup.cs @@ -2,7 +2,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.Json.JsonConverters; -using Volo.Abp.Json; namespace Volo.Abp.Json { diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs index 3c9303f968..c3ca6c2adc 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs @@ -1,7 +1,7 @@ -using Volo.Abp.Application; +using System.Collections.Generic; +using Volo.Abp.Application; using Volo.Abp.FeatureManagement.JsonConverters; using Volo.Abp.Json; -using Volo.Abp.Json; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; @@ -23,7 +23,7 @@ namespace Volo.Abp.FeatureManagement Configure(options => { - options.JsonSerializerOptions.Converters.Add(new StringValueTypeJsonConverter()); + options.JsonSerializerOptions.Converters.AddIfNotContains(new StringValueTypeJsonConverter()); }); } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/JsonSerializerOptionsHelper.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/JsonSerializerOptionsHelper.cs new file mode 100644 index 0000000000..26927f59fe --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/JsonSerializerOptionsHelper.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Volo.Abp.FeatureManagement.JsonConverters +{ + internal static class JsonSerializerOptionsHelper + { + public static JsonSerializerOptions Create(JsonSerializerOptions baseOptions, JsonConverter removeConverter, params JsonConverter[] addConverters) + { + var options = new JsonSerializerOptions(baseOptions); + options.Converters.RemoveAll(x => x == removeConverter); + options.Converters.AddIfNotContains(addConverters); + return options; + } + } +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/LocalizableStringInfoJsonConverter.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/LocalizableStringInfoJsonConverter.cs deleted file mode 100644 index e9f5cf599c..0000000000 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/LocalizableStringInfoJsonConverter.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Text.Json; -using System.Text.Json.Serialization; -using Volo.Abp.Validation.StringValues; - -namespace Volo.Abp.FeatureManagement.JsonConverters -{ - public class LocalizableStringInfoJsonConverter : JsonConverter - { - public override LocalizableStringInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var rootElement = JsonDocument.ParseValue(ref reader).RootElement; - return new LocalizableStringInfo( - rootElement.GetProperty("ResourceName").GetString(), - rootElement.GetProperty("Name").GetString() - ); - } - - public override void Write(Utf8JsonWriter writer, LocalizableStringInfo value, JsonSerializerOptions options) - { - JsonSerializer.Serialize(writer, value); - } - } -} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemJsonConverter.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemJsonConverter.cs deleted file mode 100644 index 59b2f77c6b..0000000000 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemJsonConverter.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Text.Json; -using System.Text.Json.Serialization; -using Volo.Abp.Validation.StringValues; - -namespace Volo.Abp.FeatureManagement.JsonConverters -{ - public class SelectionStringValueItemJsonConverter : JsonConverter - { - public override ISelectionStringValueItem Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var rootElement = JsonDocument.ParseValue(ref reader).RootElement; - - var jsonSerializerOptions = new JsonSerializerOptions(); - jsonSerializerOptions.Converters.Add(new LocalizableStringInfoJsonConverter()); - - return new LocalizableSelectionStringValueItem - { - Value = rootElement.GetProperty("Value").GetString(), - DisplayText = JsonSerializer.Deserialize(rootElement.GetProperty("DisplayText").GetRawText(), jsonSerializerOptions) - }; - } - - public override void Write(Utf8JsonWriter writer, ISelectionStringValueItem value, JsonSerializerOptions options) - { - if (value.GetType() == typeof(LocalizableStringInfo)) - { - JsonSerializer.Serialize(writer, (LocalizableSelectionStringValueItem)value); - } - else - { - throw new JsonException("Unknown ISelectionStringValueItem type!"); - } - } - } -} 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 b523dba20b..0812fcc59f 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,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using Volo.Abp.Validation.StringValues; @@ -10,12 +11,13 @@ 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 jsonSerializerOptions = new JsonSerializerOptions(); - jsonSerializerOptions.Converters.Add(new SelectionStringValueItemJsonConverter()); + var items = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("Items", StringComparison.InvariantCultureIgnoreCase)).Value.GetRawText(); var selectionStringValueItem = - JsonSerializer.Deserialize>(rootElement.GetProperty("Items").GetRawText(), jsonSerializerOptions) ?? + JsonSerializer.Deserialize>(items, newOptions) ?? new List(); return new StaticSelectionStringValueItemSource(selectionStringValueItem.ToArray()); @@ -23,9 +25,11 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public override void Write(Utf8JsonWriter writer, ISelectionStringValueItemSource value, JsonSerializerOptions options) { + var newOptions = JsonSerializerOptionsHelper.Create(options, this); + if (value.GetType() == typeof(StaticSelectionStringValueItemSource)) { - JsonSerializer.Serialize(writer, (StaticSelectionStringValueItemSource)value); + JsonSerializer.Serialize(writer, (StaticSelectionStringValueItemSource)value, newOptions); } else { 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 5cdaf352bb..9ca037d001 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 @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using Volo.Abp.Validation.StringValues; @@ -10,33 +11,32 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public override IStringValueType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var rootElement = JsonDocument.ParseValue(ref reader).RootElement; - var jsonSerializerOptions = new JsonSerializerOptions(); - jsonSerializerOptions.Converters.Add(new ValueValidatorJsonConverter()); - jsonSerializerOptions.Converters.Add(new SelectionStringValueItemSourceJsonConverter()); - - var name = rootElement.GetProperty("Name").GetString(); + var name = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("Name", StringComparison.InvariantCultureIgnoreCase)).Value.GetString(); + var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ValueValidatorJsonConverter(), new SelectionStringValueItemSourceJsonConverter()); return name switch { - "SelectionStringValueType" => JsonSerializer.Deserialize(rootElement.GetRawText(), jsonSerializerOptions), - "FreeTextStringValueType" => JsonSerializer.Deserialize(rootElement.GetRawText(), jsonSerializerOptions), - "ToggleStringValueType" => JsonSerializer.Deserialize(rootElement.GetRawText(), jsonSerializerOptions), + "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!") }; } public override void Write(Utf8JsonWriter writer, IStringValueType value, JsonSerializerOptions options) { + var newOptions = JsonSerializerOptionsHelper.Create(options, this); + if (value.GetType() == typeof(FreeTextStringValueType)) { - JsonSerializer.Serialize(writer, (FreeTextStringValueType)value); + JsonSerializer.Serialize(writer, (FreeTextStringValueType)value, newOptions); } else if (value.GetType() == typeof(SelectionStringValueType)) { - JsonSerializer.Serialize(writer, (SelectionStringValueType)value); + JsonSerializer.Serialize(writer, (SelectionStringValueType)value, newOptions); } else if (value.GetType() == typeof(ToggleStringValueType)) { - JsonSerializer.Serialize(writer, (ToggleStringValueType)value); + JsonSerializer.Serialize(writer, (ToggleStringValueType)value, newOptions); } else { 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 b525651d73..bfea58b078 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,11 +13,12 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public override IValueValidator Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var rootElement = JsonDocument.ParseValue(ref reader).RootElement; - var valueValidator = CreateValueValidatorByName(rootElement.GetProperty("Name").GetString()); + var name = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("Name", StringComparison.InvariantCultureIgnoreCase)).Value.GetString(); + var valueValidator = CreateValueValidatorByName(name); - var deserializeOptions = new JsonSerializerOptions(); - deserializeOptions.Converters.Add(new ObjectToInferredTypesConverter()); - var properties = JsonSerializer.Deserialize>(rootElement.GetProperty("Properties").GetRawText(), deserializeOptions); + var propertiesRawText = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("Properties", StringComparison.InvariantCultureIgnoreCase)).Value.GetRawText(); + var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ObjectToInferredTypesConverter()); + var properties = JsonSerializer.Deserialize>(propertiesRawText, newOptions); if (properties != null && properties.Any()) { foreach (var property in properties) @@ -31,21 +32,23 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public override void Write(Utf8JsonWriter writer, IValueValidator value, JsonSerializerOptions options) { + var newOptions = JsonSerializerOptionsHelper.Create(options, this); + if (value.GetType() == typeof(AlwaysValidValueValidator)) { - JsonSerializer.Serialize(writer, (AlwaysValidValueValidator)value); + JsonSerializer.Serialize(writer, (AlwaysValidValueValidator)value, newOptions); } else if (value.GetType() == typeof(BooleanValueValidator)) { - JsonSerializer.Serialize(writer, (BooleanValueValidator)value); + JsonSerializer.Serialize(writer, (BooleanValueValidator)value, newOptions); } else if (value.GetType() == typeof(NumericValueValidator)) { - JsonSerializer.Serialize(writer, (NumericValueValidator)value); + JsonSerializer.Serialize(writer, (NumericValueValidator)value, newOptions); } else if (value.GetType() == typeof(StringValueValidator)) { - JsonSerializer.Serialize(writer, (StringValueValidator)value); + JsonSerializer.Serialize(writer, (StringValueValidator)value, newOptions); } else { diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs index 5146061c3b..f062317d66 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs @@ -1,9 +1,12 @@ -using Localization.Resources.AbpUi; +using System.Collections.Generic; +using Localization.Resources.AbpUi; +using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.FeatureManagement.Localization; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.FeatureManagement.JsonConverters; namespace Volo.Abp.FeatureManagement { @@ -28,6 +31,11 @@ namespace Volo.Abp.FeatureManagement .Get() .AddBaseTypes(typeof(AbpUiResource)); }); + + Configure(options => + { + options.JsonSerializerOptions.Converters.AddIfNotContains(new StringValueTypeJsonConverter()); + }); } } } 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 4e5d4b20a3..c72cbddffd 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 @@ -66,7 +66,7 @@ namespace Volo.Abp.FeatureManagement } }; - var serialized = _jsonSerializer.Serialize(featureListDto); + var serialized = _jsonSerializer.Serialize(featureListDto, indented: true); var featureListDto2 = _jsonSerializer.Deserialize(serialized); From 97f383ebcd26c590fe67d773caeb7e031dd13f19 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 27 Oct 2020 22:18:14 +0800 Subject: [PATCH 05/17] Update MyProjectNameWebTestBase.cs --- .../MyProjectNameWebTestBase.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestBase.cs b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestBase.cs index ec29900d07..7c3f6330c8 100644 --- a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestBase.cs +++ b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestBase.cs @@ -1,10 +1,8 @@ using System.Net; using System.Net.Http; +using System.Text.Json; using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; using Shouldly; using Volo.Abp.AspNetCore.TestBase; @@ -22,10 +20,7 @@ namespace MyCompanyName.MyProjectName protected virtual async Task GetResponseAsObjectAsync(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) { var strResponse = await GetResponseAsStringAsync(url, expectedStatusCode); - return JsonConvert.DeserializeObject(strResponse, new JsonSerializerSettings - { - ContractResolver = new CamelCasePropertyNamesContractResolver() - }); + return JsonSerializer.Deserialize(strResponse, new JsonSerializerOptions(JsonSerializerDefaults.Web)); } protected virtual async Task GetResponseAsStringAsync(string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) From f7ebd426f48ec15bc3f4245e83a4a07d1342b4f8 Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 29 Oct 2020 17:22:59 +0800 Subject: [PATCH 06/17] Refactor. --- .../Volo/Abp/Json/JsonConverters/AbpDateTimeConverter.cs | 4 ++-- .../Abp/Json/JsonConverters/AbpNullableDateTimeConverter.cs | 4 ++-- .../Json/JsonConverters/ObjectToInferredTypesConverter.cs | 3 +++ .../Volo/Abp/MemoryDb/JsonConverters/EntityJsonConverter.cs | 5 ++++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpDateTimeConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpDateTimeConverter.cs index 7523f1e4d9..29e99f285e 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpDateTimeConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpDateTimeConverter.cs @@ -27,11 +27,11 @@ namespace Volo.Abp.Json.JsonConverters { if (_options.DefaultDateTimeFormat.IsNullOrWhiteSpace()) { - writer.WriteStringValue(_clock.Normalize(value)); + writer.WriteStringValue(value); } else { - writer.WriteStringValue(_clock.Normalize(value).ToString(_options.DefaultDateTimeFormat)); + writer.WriteStringValue(value.ToString(_options.DefaultDateTimeFormat)); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpNullableDateTimeConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpNullableDateTimeConverter.cs index 0e1e20bedc..f061b94cf5 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpNullableDateTimeConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpNullableDateTimeConverter.cs @@ -38,11 +38,11 @@ namespace Volo.Abp.Json.JsonConverters { if (_options.DefaultDateTimeFormat.IsNullOrWhiteSpace()) { - writer.WriteStringValue(_clock.Normalize(value.Value)); + writer.WriteStringValue(value.Value); } else { - writer.WriteStringValue(_clock.Normalize(value.Value).ToString(_options.DefaultDateTimeFormat)); + writer.WriteStringValue(value.Value.ToString(_options.DefaultDateTimeFormat)); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/ObjectToInferredTypesConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/ObjectToInferredTypesConverter.cs index 4a3cd5e8df..c7497cfa60 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/ObjectToInferredTypesConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/ObjectToInferredTypesConverter.cs @@ -4,6 +4,9 @@ using System.Text.Json.Serialization; namespace Volo.Abp.Json.JsonConverters { + /// + /// https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to#deserialize-inferred-types-to-object-properties + /// public class ObjectToInferredTypesConverter : JsonConverter { public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 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 9a41fd4045..8723ce8958 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 @@ -24,7 +24,10 @@ namespace Volo.Abp.MemoryDb.JsonConverters public override void Write(Utf8JsonWriter writer, TEntity value, JsonSerializerOptions options) { - JsonSerializer.Serialize(writer, value); + var newOptions = new JsonSerializerOptions(options); + newOptions.Converters.Remove(this); + var entityConverter = (JsonConverter)newOptions.GetConverter(typeof(TEntity)); + entityConverter.Write(writer, value, newOptions); } } } From 8c28ee1dd220160a38f2df3b90c4cc93f47f40ef Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 30 Oct 2020 16:44:14 +0800 Subject: [PATCH 07/17] Add AbpHybridJsonSerializer, AbpHybridJsonInputFormatter, AbpHybridJsonOutputFormatter. --- framework/Volo.Abp.sln | 12 +-- .../Volo.Abp.AspNetCore.Mvc.csproj | 1 + .../AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs | 2 +- .../Mvc/Json/AbpHybridJsonInputFormatter.cs | 38 +++++++++ .../Mvc/Json/AbpHybridJsonOutputFormatter.cs | 35 ++++++++ .../Mvc/Json/AbpJsonOptionsSetup.cs | 3 +- .../Mvc/Json/AbpMvcJsonContractResolver.cs | 45 ++++++++++ .../Json/AbpMvcNewtonsoftJsonOptionsSetup.cs | 22 +++++ .../Mvc/Json/MediaTypeHeaderValues.cs | 22 +++++ .../Mvc/Json/MvcCoreBuilderExtensions.cs | 82 +++++++++++++++++++ .../ValueConverters/AbpJsonValueConverter.cs | 2 +- .../ExtraPropertiesValueConverter.cs | 2 +- .../Volo.Abp.Json.Newtonsoft/FodyWeavers.xml | 3 - .../Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd | 30 ------- .../Volo.Abp.Json.Newtonsoft.csproj | 25 ------ .../Volo/Abp/Json/AbpJsonModule.cs | 21 ----- .../src/Volo.Abp.Json/Volo.Abp.Json.csproj | 1 + .../Volo/Abp/Json/AbpHybridJsonSerializer.cs | 55 +++++++++++++ .../Volo/Abp/Json/AbpJsonModule.cs | 17 +++- .../Volo/Abp/Json/AbpJsonOptions.cs | 11 ++- .../Volo/Abp/Json/IJsonSerializerProvider.cs | 15 ++++ .../Newtonsoft/AbpJsonIsoDateTimeConverter.cs | 0 .../AbpNewtonsoftJsonSerializerOptions.cs | 0 .../NewtonsoftJsonSerializerProvider.cs} | 10 ++- .../AbpSystemTextJsonSerializerOptions.cs} | 6 +- ...bpSystemTextJsonSerializerOptionsSetup.cs} | 9 +- .../JsonConverters/AbpDateTimeConverter.cs | 6 +- .../AbpNullableDateTimeConverter.cs | 6 +- .../ObjectToInferredTypesConverter.cs | 2 +- .../SystemTextJsonSerializerProvider.cs} | 15 +++- .../SystemTextJsonSupportTypes.cs | 62 ++++++++++++++ .../SystemTextJsonSupportTypesOptions.cs | 15 ++++ .../Volo.Abp.Json.Tests.csproj | 16 ++++ .../Volo/Abp/Json/AbpJsonTestBase.cs | 12 +++ .../Volo/Abp/Json/AbpJsonTestModule.cs | 15 ++++ .../Json/SystemTextJsonSupportTypes_Tests.cs | 65 +++++++++++++++ ...ureManagementApplicationContractsModule.cs | 3 +- .../ValueValidatorJsonConverter.cs | 2 +- nupkg/common.ps1 | 1 - 39 files changed, 574 insertions(+), 115 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcNewtonsoftJsonOptionsSetup.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MediaTypeHeaderValues.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs delete mode 100644 framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xml delete mode 100644 framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd delete mode 100644 framework/src/Volo.Abp.Json.Newtonsoft/Volo.Abp.Json.Newtonsoft.csproj delete mode 100644 framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/AbpJsonModule.cs create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/IJsonSerializerProvider.cs rename framework/src/{Volo.Abp.Json.Newtonsoft => Volo.Abp.Json}/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs (100%) rename framework/src/{Volo.Abp.Json.Newtonsoft => Volo.Abp.Json}/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs (100%) rename framework/src/{Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializer.cs => Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializerProvider.cs} (91%) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/{AbpJsonSerializerOptions.cs => SystemTextJson/AbpSystemTextJsonSerializerOptions.cs} (78%) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/{AbpJsonSerializerOptionsSetup.cs => SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs} (59%) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/{ => SystemTextJson}/JsonConverters/AbpDateTimeConverter.cs (81%) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/{ => SystemTextJson}/JsonConverters/AbpNullableDateTimeConverter.cs (84%) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/{ => SystemTextJson}/JsonConverters/ObjectToInferredTypesConverter.cs (96%) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/{AbpJsonSerializer.cs => SystemTextJson/SystemTextJsonSerializerProvider.cs} (67%) create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypes.cs create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypesOptions.cs create mode 100644 framework/test/Volo.Abp.Json.Tests/Volo.Abp.Json.Tests.csproj create mode 100644 framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestBase.cs create mode 100644 framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestModule.cs create mode 100644 framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypes_Tests.cs diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index fb59c91051..6957eb2baf 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -355,7 +355,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Compone EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Swashbuckle", "src\Volo.Abp.Swashbuckle\Volo.Abp.Swashbuckle.csproj", "{DD9519E0-5A68-48DC-A051-7BF2AC922F3E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Json.Newtonsoft", "src\Volo.Abp.Json.Newtonsoft\Volo.Abp.Json.Newtonsoft.csproj", "{B5DEA857-1A22-4479-8441-E871D1BCBAB2}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Json.Tests", "test\Volo.Abp.Json.Tests\Volo.Abp.Json.Tests.csproj", "{00D07595-993C-40FC-BD90-0DD6331414D3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -1059,10 +1059,10 @@ Global {DD9519E0-5A68-48DC-A051-7BF2AC922F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU {DD9519E0-5A68-48DC-A051-7BF2AC922F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU {DD9519E0-5A68-48DC-A051-7BF2AC922F3E}.Release|Any CPU.Build.0 = Release|Any CPU - {B5DEA857-1A22-4479-8441-E871D1BCBAB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B5DEA857-1A22-4479-8441-E871D1BCBAB2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B5DEA857-1A22-4479-8441-E871D1BCBAB2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B5DEA857-1A22-4479-8441-E871D1BCBAB2}.Release|Any CPU.Build.0 = Release|Any CPU + {00D07595-993C-40FC-BD90-0DD6331414D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00D07595-993C-40FC-BD90-0DD6331414D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00D07595-993C-40FC-BD90-0DD6331414D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00D07595-993C-40FC-BD90-0DD6331414D3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1242,7 +1242,7 @@ Global {B9D1ADCB-D552-4626-A1F1-78FF72C1E822} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {89840441-5A3A-4FD7-9CB4-E5B52FAEF72A} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {DD9519E0-5A68-48DC-A051-7BF2AC922F3E} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} - {B5DEA857-1A22-4479-8441-E871D1BCBAB2} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {00D07595-993C-40FC-BD90-0DD6331414D3} = {447C8A77-E5F0-4538-8687-7383196D04EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj index fff97c83c3..a018dbbffd 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj @@ -28,6 +28,7 @@ + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs index 11a6ae9442..61d73cb48b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs @@ -136,7 +136,7 @@ namespace Volo.Abp.AspNetCore.Mvc }) .AddViewLocalization(); //TODO: How to configure from the application? Also, consider to move to a UI module since APIs does not care about it. - context.Services.TryAddEnumerable(ServiceDescriptor.Transient, AbpJsonOptionsSetup>()); + mvcCoreBuilder.AddAbpHybridJson(); Configure(options => { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs new file mode 100644 index 0000000000..4ad90bcad2 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs @@ -0,0 +1,38 @@ +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Json.SystemTextJson; + +namespace Volo.Abp.AspNetCore.Mvc.Json +{ + public class AbpHybridJsonInputFormatter : TextInputFormatter, IInputFormatterExceptionPolicy + { + public AbpHybridJsonInputFormatter() + { + SupportedEncodings.Add(UTF8EncodingWithoutBOM); + SupportedEncodings.Add(UTF16EncodingLittleEndian); + + SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJson); + SupportedMediaTypes.Add(MediaTypeHeaderValues.TextJson); + SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax); + } + + public async override Task ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding) + { + return await GetTextInputFormatter(context).ReadRequestBodyAsync(context, encoding); + } + + private TextInputFormatter GetTextInputFormatter(InputFormatterContext context) + { + if (context.HttpContext.RequestServices.GetRequiredService().CanHandle(context.ModelType)) + { + return context.HttpContext.RequestServices.GetRequiredService(); + } + + return context.HttpContext.RequestServices.GetRequiredService(); + } + + public InputFormatterExceptionPolicy ExceptionPolicy => InputFormatterExceptionPolicy.MalformedInputExceptions; + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs new file mode 100644 index 0000000000..7cf991be96 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs @@ -0,0 +1,35 @@ +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Json.SystemTextJson; + +namespace Volo.Abp.AspNetCore.Mvc.Json +{ + public class AbpHybridJsonOutputFormatter : TextOutputFormatter + { + public AbpHybridJsonOutputFormatter() + { + SupportedEncodings.Add(Encoding.UTF8); + SupportedEncodings.Add(Encoding.Unicode); + SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJson); + SupportedMediaTypes.Add(MediaTypeHeaderValues.TextJson); + SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax); + } + + public async override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) + { + await GetTextInputFormatter(context).WriteResponseBodyAsync(context, selectedEncoding); + } + + private TextOutputFormatter GetTextInputFormatter(OutputFormatterWriteContext context) + { + if (context.HttpContext.RequestServices.GetRequiredService().CanHandle(context.ObjectType)) + { + return context.HttpContext.RequestServices.GetRequiredService(); + } + + return context.HttpContext.RequestServices.GetRequiredService(); + } + } +} 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 821b2c9218..b456204ed8 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 @@ -2,8 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Volo.Abp.Json.JsonConverters; -using Volo.Abp.Json; +using Volo.Abp.Json.SystemTextJson.JsonConverters; namespace Volo.Abp.AspNetCore.Mvc.Json { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs new file mode 100644 index 0000000000..2db8bc3f06 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs @@ -0,0 +1,45 @@ +using System; +using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Json.Newtonsoft; +using Volo.Abp.Reflection; +using Volo.Abp.Timing; + +namespace Volo.Abp.AspNetCore.Mvc.Json +{ + public class AbpMvcJsonContractResolver : DefaultContractResolver, ITransientDependency + { + private readonly AbpJsonIsoDateTimeConverter _dateTimeConverter; + + public AbpMvcJsonContractResolver(AbpJsonIsoDateTimeConverter dateTimeConverter) + { + _dateTimeConverter = dateTimeConverter; + + NamingStrategy = new CamelCaseNamingStrategy(); + } + + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + var property = base.CreateProperty(member, memberSerialization); + + ModifyProperty(member, property); + + return property; + } + + protected virtual void ModifyProperty(MemberInfo member, JsonProperty property) + { + if (property.PropertyType != typeof(DateTime) && property.PropertyType != typeof(DateTime?)) + { + return; + } + + if (ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(member) == null) + { + property.Converter = _dateTimeConverter; + } + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcNewtonsoftJsonOptionsSetup.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcNewtonsoftJsonOptionsSetup.cs new file mode 100644 index 0000000000..48a09e2426 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcNewtonsoftJsonOptionsSetup.cs @@ -0,0 +1,22 @@ +using System; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace Volo.Abp.AspNetCore.Mvc.Json +{ + public class AbpMvcNewtonsoftJsonOptionsSetup : IConfigureOptions + { + protected IServiceProvider ServiceProvider { get; } + + public AbpMvcNewtonsoftJsonOptionsSetup(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + public void Configure(MvcNewtonsoftJsonOptions options) + { + options.SerializerSettings.ContractResolver = ServiceProvider.GetRequiredService(); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MediaTypeHeaderValues.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MediaTypeHeaderValues.cs new file mode 100644 index 0000000000..d1f1b34b1a --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MediaTypeHeaderValues.cs @@ -0,0 +1,22 @@ +using Microsoft.Net.Http.Headers; + +namespace Volo.Abp.AspNetCore.Mvc.Json +{ + /// + /// https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.NewtonsoftJson/src/MediaTypeHeaderValues.cs + /// + internal static class MediaTypeHeaderValues + { + public static readonly MediaTypeHeaderValue ApplicationJson = MediaTypeHeaderValue.Parse("application/json").CopyAsReadOnly(); + + public static readonly MediaTypeHeaderValue TextJson = MediaTypeHeaderValue.Parse("text/json").CopyAsReadOnly(); + + public static readonly MediaTypeHeaderValue ApplicationAnyJsonSyntax = MediaTypeHeaderValue.Parse("application/*+json").CopyAsReadOnly(); + + public static readonly MediaTypeHeaderValue ApplicationXml = MediaTypeHeaderValue.Parse("application/xml").CopyAsReadOnly(); + + public static readonly MediaTypeHeaderValue TextXml = MediaTypeHeaderValue.Parse("text/xml").CopyAsReadOnly(); + + public static readonly MediaTypeHeaderValue ApplicationAnyXmlSyntax = MediaTypeHeaderValue.Parse("application/*+xml").CopyAsReadOnly(); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs new file mode 100644 index 0000000000..9eaa0c826a --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs @@ -0,0 +1,82 @@ +using System.Buffers; +using System.Text.Json; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; +using System.Text.Encodings.Web; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ObjectPool; + +namespace Volo.Abp.AspNetCore.Mvc.Json +{ + public static class MvcCoreBuilderExtensions + { + public static IMvcCoreBuilder AddAbpHybridJson(this IMvcCoreBuilder builder) + { + //SystemTextJsonInputFormatter + builder.Services.AddTransient(provider => + { + var jsonOptions = provider.GetRequiredService>(); + var logger = provider.GetRequiredService().CreateLogger(); + return new SystemTextJsonInputFormatter(jsonOptions.Value, logger); + }); + + //NewtonsoftJsonInputFormatter + builder.Services.AddTransient(provider => + { + var jsonOptions = provider.GetRequiredService>().Value; + + return new NewtonsoftJsonInputFormatter( + provider.GetRequiredService().CreateLogger(), + jsonOptions.SerializerSettings, + provider.GetRequiredService>(), + provider.GetRequiredService(), + provider.GetRequiredService>().Value, + jsonOptions); + }); + + //SystemTextJsonOutputFormatter + builder.Services.AddTransient(provider => + { + var jsonSerializerOptions = provider.GetRequiredService>().Value.JsonSerializerOptions; + if (jsonSerializerOptions.Encoder is null) + { + // If the user hasn't explicitly configured the encoder, use the less strict encoder that does not encode all non-ASCII characters. + jsonSerializerOptions = new JsonSerializerOptions(jsonSerializerOptions) + { + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + }; + } + return new SystemTextJsonOutputFormatter(jsonSerializerOptions); + }); + + //NewtonsoftJsonOutputFormatter + builder.Services.AddTransient(provider => + { + var jsonOptions = provider.GetRequiredService>().Value; + return new NewtonsoftJsonOutputFormatter( + jsonOptions.SerializerSettings, + provider.GetRequiredService>(), + provider.GetRequiredService>().Value); + }); + + builder.Services.TryAddEnumerable(ServiceDescriptor.Transient, AbpJsonOptionsSetup>()); + builder.Services.TryAddEnumerable(ServiceDescriptor.Transient, AbpMvcNewtonsoftJsonOptionsSetup>()); + + builder.Services.Configure(options => + { + options.InputFormatters.RemoveType(); + options.InputFormatters.RemoveType(); + options.InputFormatters.Add(new AbpHybridJsonInputFormatter()); + + options.OutputFormatters.RemoveType(); + options.OutputFormatters.RemoveType(); + options.OutputFormatters.Add(new AbpHybridJsonOutputFormatter()); + }); + + return builder; + } + } +} 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 afce924d59..7378ab8eff 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 @@ -1,6 +1,6 @@ using System.Text.Json; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Volo.Abp.Json.JsonConverters; +using Volo.Abp.Json.SystemTextJson.JsonConverters; namespace Volo.Abp.EntityFrameworkCore.ValueConverters { 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 00ce8459a6..661da95a19 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 @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text.Json; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Volo.Abp.Json.JsonConverters; +using Volo.Abp.Json.SystemTextJson.JsonConverters; using Volo.Abp.ObjectExtending; namespace Volo.Abp.EntityFrameworkCore.ValueConverters diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xml b/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xml deleted file mode 100644 index bc5a74a236..0000000000 --- a/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd b/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd deleted file mode 100644 index 3f3946e282..0000000000 --- a/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. - - - - - A comma-separated list of error codes that can be safely ignored in assembly verification. - - - - - 'false' to turn off automatic generation of the XML Schema file. - - - - - \ No newline at end of file diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo.Abp.Json.Newtonsoft.csproj b/framework/src/Volo.Abp.Json.Newtonsoft/Volo.Abp.Json.Newtonsoft.csproj deleted file mode 100644 index dd6cdc06ae..0000000000 --- a/framework/src/Volo.Abp.Json.Newtonsoft/Volo.Abp.Json.Newtonsoft.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - netstandard2.0 - Volo.Abp.Json.Newtonsoft - Volo.Abp.Json.Newtonsoft - $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; - false - false - false - - - - - - - - - - - - diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/AbpJsonModule.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/AbpJsonModule.cs deleted file mode 100644 index b040f1afbb..0000000000 --- a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/AbpJsonModule.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Options; -using Volo.Abp.Json; -using Volo.Abp.Json.Newtonsoft; -using Volo.Abp.Modularity; - -namespace Volo.Abp.Json -{ - [DependsOn(typeof(AbpJsonModule))] - public class AbpJsonNewtonsoftModule : AbpModule - { - public override void ConfigureServices(ServiceConfigurationContext context) - { - Configure(options => - { - options.Converters.Add(); - }); - } - } -} diff --git a/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj b/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj index ddf8cfba65..1ef71853fa 100644 --- a/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj +++ b/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj @@ -16,6 +16,7 @@ + diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs new file mode 100644 index 0000000000..6621ac8640 --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Json +{ + public class AbpHybridJsonSerializer : IJsonSerializer, ISingletonDependency + { + private readonly Lazy> _lazyProviders; + public List Providers => _lazyProviders.Value; + + public AbpHybridJsonSerializer(IOptions options, IServiceProvider serviceProvider) + { + _lazyProviders = new Lazy>( + () => options.Value + .Providers + .Select(c => serviceProvider.GetRequiredService(c) as IJsonSerializerProvider) + .Reverse() + .ToList(), + true + ); + } + + public string Serialize(object obj, bool camelCase = true, bool indented = false) + { + var provider = GetSerializerProvider(obj.GetType()); + return provider.Serialize(obj, camelCase, indented); + } + + public T Deserialize(string jsonString, bool camelCase = true) + { + var provider = GetSerializerProvider(typeof(T)); + return provider.Deserialize(jsonString, camelCase); + } + + public object Deserialize(Type type, string jsonString, bool camelCase = true) + { + var provider = GetSerializerProvider(type); + return provider.Deserialize(type, jsonString, camelCase); + } + + protected virtual IJsonSerializerProvider GetSerializerProvider(Type type) + { + foreach (var provider in Providers.Where(provider => provider.CanHandle(type))) + { + return provider; + } + + throw new AbpException($"There is no IJsonSerializerProvider that can handle {type.GetFullNameWithAssemblyName()} types!"); + } + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs index c5376d0f05..747f01732a 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs @@ -1,6 +1,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; +using Volo.Abp.Json.Newtonsoft; +using Volo.Abp.Json.SystemTextJson; using Volo.Abp.Modularity; using Volo.Abp.Timing; @@ -11,7 +13,20 @@ namespace Volo.Abp.Json { public override void ConfigureServices(ServiceConfigurationContext context) { - context.Services.TryAddEnumerable(ServiceDescriptor.Transient, AbpJsonSerializerOptionsSetup>()); + context.Services.TryAddEnumerable(ServiceDescriptor + .Transient, + AbpSystemTextJsonSerializerOptionsSetup>()); + + Configure(options => + { + options.Providers.Add(); + options.Providers.Add(); + }); + + Configure(options => + { + options.IgnoreAttributes.Add(); + }); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonOptions.cs index 239d7864cd..55a4683e26 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonOptions.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonOptions.cs @@ -1,4 +1,6 @@ -namespace Volo.Abp.Json +using Volo.Abp.Collections; + +namespace Volo.Abp.Json { public class AbpJsonOptions { @@ -6,5 +8,12 @@ /// Used to set default value for the DateTimeFormat. /// public string DefaultDateTimeFormat { get; set; } + + public ITypeList Providers { get; } + + public AbpJsonOptions() + { + Providers = new TypeList(); + } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/IJsonSerializerProvider.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/IJsonSerializerProvider.cs new file mode 100644 index 0000000000..f844dc5fd0 --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/IJsonSerializerProvider.cs @@ -0,0 +1,15 @@ +using System; + +namespace Volo.Abp.Json +{ + public interface IJsonSerializerProvider + { + bool CanHandle(Type type); + + string Serialize(object obj, bool camelCase = true, bool indented = false); + + T Deserialize(string jsonString, bool camelCase = true); + + object Deserialize(Type type, string jsonString, bool camelCase = true); + } +} diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs similarity index 100% rename from framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs similarity index 100% rename from framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializer.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializerProvider.cs similarity index 91% rename from framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializer.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializerProvider.cs index e241484719..e33f9b155f 100644 --- a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializer.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializerProvider.cs @@ -9,15 +9,14 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Json.Newtonsoft { - [Dependency(ReplaceServices = true)] - public class NewtonsoftJsonSerializer : IJsonSerializer, ITransientDependency + public class NewtonsoftJsonSerializerProvider : IJsonSerializerProvider, ITransientDependency { private static readonly CamelCaseExceptDictionaryKeysResolver SharedCamelCaseExceptDictionaryKeysResolver = new CamelCaseExceptDictionaryKeysResolver(); protected List Converters { get; } - public NewtonsoftJsonSerializer( + public NewtonsoftJsonSerializerProvider( IOptions options, IServiceProvider serviceProvider) { @@ -27,6 +26,11 @@ namespace Volo.Abp.Json.Newtonsoft .ToList(); } + public bool CanHandle(Type type) + { + return true; + } + public string Serialize(object obj, bool camelCase = true, bool indented = false) { return JsonConvert.SerializeObject(obj, CreateSerializerSettings(camelCase, indented)); diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs similarity index 78% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptions.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs index c1289ce159..1f986e688b 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptions.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs @@ -1,12 +1,12 @@ using System.Text.Json; -namespace Volo.Abp.Json +namespace Volo.Abp.Json.SystemTextJson { - public class AbpJsonSerializerOptions + public class AbpSystemTextJsonSerializerOptions { public JsonSerializerOptions JsonSerializerOptions { get; } - public AbpJsonSerializerOptions() + public AbpSystemTextJsonSerializerOptions() { //TODO:Defaults? //https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.Core/src/JsonOptions.cs#L18 diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptionsSetup.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs similarity index 59% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptionsSetup.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs index 16e8119731..4b56997d47 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializerOptionsSetup.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs @@ -1,20 +1,21 @@ using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Volo.Abp.Json.JsonConverters; +using Volo.Abp.Json.SystemTextJson; +using Volo.Abp.Json.SystemTextJson.JsonConverters; namespace Volo.Abp.Json { - public class AbpJsonSerializerOptionsSetup : IConfigureOptions + public class AbpSystemTextJsonSerializerOptionsSetup : IConfigureOptions { protected IServiceProvider ServiceProvider { get; } - public AbpJsonSerializerOptionsSetup(IServiceProvider serviceProvider) + public AbpSystemTextJsonSerializerOptionsSetup(IServiceProvider serviceProvider) { ServiceProvider = serviceProvider; } - public void Configure(AbpJsonSerializerOptions options) + public void Configure(AbpSystemTextJsonSerializerOptions options) { options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService()); options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService()); diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpDateTimeConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs similarity index 81% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpDateTimeConverter.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs index 29e99f285e..a87add029e 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpDateTimeConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; using Volo.Abp.Timing; -namespace Volo.Abp.Json.JsonConverters +namespace Volo.Abp.Json.SystemTextJson.JsonConverters { public class AbpDateTimeConverter : JsonConverter, ITransientDependency { @@ -27,11 +27,11 @@ namespace Volo.Abp.Json.JsonConverters { if (_options.DefaultDateTimeFormat.IsNullOrWhiteSpace()) { - writer.WriteStringValue(value); + writer.WriteStringValue(_clock.Normalize(value)); } else { - writer.WriteStringValue(value.ToString(_options.DefaultDateTimeFormat)); + writer.WriteStringValue(_clock.Normalize(value).ToString(_options.DefaultDateTimeFormat)); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpNullableDateTimeConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs similarity index 84% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpNullableDateTimeConverter.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs index f061b94cf5..bad650b4d8 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/AbpNullableDateTimeConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; using Volo.Abp.Timing; -namespace Volo.Abp.Json.JsonConverters +namespace Volo.Abp.Json.SystemTextJson.JsonConverters { public class AbpNullableDateTimeConverter : JsonConverter, ITransientDependency { @@ -38,11 +38,11 @@ namespace Volo.Abp.Json.JsonConverters { if (_options.DefaultDateTimeFormat.IsNullOrWhiteSpace()) { - writer.WriteStringValue(value.Value); + writer.WriteStringValue(_clock.Normalize(value.Value)); } else { - writer.WriteStringValue(value.Value.ToString(_options.DefaultDateTimeFormat)); + writer.WriteStringValue(_clock.Normalize(value.Value).ToString(_options.DefaultDateTimeFormat)); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/ObjectToInferredTypesConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs similarity index 96% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/ObjectToInferredTypesConverter.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs index c7497cfa60..02fa9bbaff 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/JsonConverters/ObjectToInferredTypesConverter.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs @@ -2,7 +2,7 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace Volo.Abp.Json.JsonConverters +namespace Volo.Abp.Json.SystemTextJson.JsonConverters { /// /// https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to#deserialize-inferred-types-to-object-properties diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializer.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSerializerProvider.cs similarity index 67% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializer.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSerializerProvider.cs index 250111fee2..5a3429bff1 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonSerializer.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSerializerProvider.cs @@ -2,18 +2,27 @@ using System.Text.Json; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; +using Volo.Abp.Json.SystemTextJson; namespace Volo.Abp.Json { - public class AbpJsonSerializer : IJsonSerializer, ITransientDependency + public class SystemTextJsonSerializerProvider : IJsonSerializerProvider, ITransientDependency { - protected AbpJsonSerializerOptions Options { get; } + protected AbpSystemTextJsonSerializerOptions Options { get; } - public AbpJsonSerializer(IOptions options) + protected SystemTextJsonSupportTypes SystemTextJsonSupportTypes { get; } + + public SystemTextJsonSerializerProvider(IOptions options, SystemTextJsonSupportTypes systemTextJsonSupportTypes) { + SystemTextJsonSupportTypes = systemTextJsonSupportTypes; Options = options.Value; } + public bool CanHandle(Type type) + { + return SystemTextJsonSupportTypes.CanHandle(type); + } + public string Serialize(object obj, bool camelCase = true, bool indented = false) { return JsonSerializer.Serialize(obj, CreateJsonSerializerOptions(camelCase, indented)); diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypes.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypes.cs new file mode 100644 index 0000000000..c2061e5b27 --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypes.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Reflection; +using Volo.Abp.Timing; + +namespace Volo.Abp.Json.SystemTextJson +{ + public class SystemTextJsonSupportTypes : ITransientDependency + { + private static readonly List CacheTypes = new List(); + + private readonly SystemTextJsonSupportTypesOptions Options; + + public SystemTextJsonSupportTypes(IOptions options) + { + Options = options.Value; + } + + public bool CanHandle(Type type) + { + if (CacheTypes.Any(x => x == type)) + { + return false; + } + + if (type.GetCustomAttributes(true).Any(x => Options.IgnoreAttributes.Any(a => a == x.GetType()))) + { + CacheTypes.Add(type); + return false; + } + + if (type.DeclaringType != null && type.DeclaringType.GetCustomAttributes(true).Any(x => Options.IgnoreAttributes.Any(a => a == x.GetType()))) + { + CacheTypes.Add(type.DeclaringType); + return false; + } + + foreach (var propertyInfo in type.GetProperties()) + { + if (propertyInfo.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true)) + { + CacheTypes.Add(propertyInfo.GetType()); + return false; + } + + if (!TypeHelper.IsPrimitiveExtended(type)) + { + if (!CanHandle(propertyInfo.PropertyType)) + { + CacheTypes.Add(propertyInfo.PropertyType); + return false; + } + } + } + + return true; + } + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypesOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypesOptions.cs new file mode 100644 index 0000000000..33ad53b997 --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypesOptions.cs @@ -0,0 +1,15 @@ +using System; +using Volo.Abp.Collections; + +namespace Volo.Abp.Json.SystemTextJson +{ + public class SystemTextJsonSupportTypesOptions + { + public ITypeList IgnoreAttributes; + + public SystemTextJsonSupportTypesOptions() + { + IgnoreAttributes = new TypeList(); + } + } +} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo.Abp.Json.Tests.csproj b/framework/test/Volo.Abp.Json.Tests/Volo.Abp.Json.Tests.csproj new file mode 100644 index 0000000000..fbc56e6ac2 --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo.Abp.Json.Tests.csproj @@ -0,0 +1,16 @@ + + + + + + net5.0 + + + + + + + + + + diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestBase.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestBase.cs new file mode 100644 index 0000000000..5c9065ad80 --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestBase.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Testing; + +namespace Volo.Abp.Json +{ + public abstract class AbpJsonTestBase : AbpIntegratedTest + { + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + } +} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestModule.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestModule.cs new file mode 100644 index 0000000000..ddbc08ac3f --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestModule.cs @@ -0,0 +1,15 @@ +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; + +namespace Volo.Abp.Json +{ + [DependsOn( + typeof(AbpAutofacModule), + typeof(AbpJsonModule), + typeof(AbpTestBaseModule) + )] + public class AbpJsonTestModule : AbpModule + { + + } +} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypes_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypes_Tests.cs new file mode 100644 index 0000000000..b21cb94653 --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypes_Tests.cs @@ -0,0 +1,65 @@ +using System; +using Shouldly; +using Volo.Abp.Json.SystemTextJson; +using Volo.Abp.Timing; +using Xunit; + +namespace Volo.Abp.Json +{ + public class SystemTextJsonSupportTypes_Tests : AbpJsonTestBase + { + private readonly SystemTextJsonSupportTypes _systemTextJsonSupportTypes; + + public SystemTextJsonSupportTypes_Tests() + { + _systemTextJsonSupportTypes = GetRequiredService(); + } + + [Fact] + public void Test() + { + _systemTextJsonSupportTypes.CanHandle(typeof(MyClass)).ShouldBeFalse(); + _systemTextJsonSupportTypes.CanHandle(typeof(MyClass2)).ShouldBeFalse(); + _systemTextJsonSupportTypes.CanHandle(typeof(MyClass3)).ShouldBeFalse(); + _systemTextJsonSupportTypes.CanHandle(typeof(MyClass4)).ShouldBeFalse(); + + _systemTextJsonSupportTypes.CanHandle(typeof(MyClass5)).ShouldBeTrue(); + _systemTextJsonSupportTypes.CanHandle(typeof(MyClass6)).ShouldBeTrue(); + } + + [DisableDateTimeNormalization] + class MyClass + { + public DateTime Prop1 { get; set; } + } + + class MyClass2 + { + [DisableDateTimeNormalization] + public DateTime Prop1 { get; set; } + } + + class MyClass3 + { + public MyClass4 Prop1 { get; set; } + } + + class MyClass4 + { + [DisableDateTimeNormalization] + public DateTime Prop1 { get; set; } + } + + class MyClass5 + { + public DateTime Prop1 { get; set; } + + public MyClass6 Prop2 { get; set; } + } + + class MyClass6 + { + public DateTime Prop1 { get; set; } + } + } +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs index c3ca6c2adc..32939a2430 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs @@ -2,6 +2,7 @@ using Volo.Abp.Application; using Volo.Abp.FeatureManagement.JsonConverters; using Volo.Abp.Json; +using Volo.Abp.Json.SystemTextJson; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; @@ -21,7 +22,7 @@ namespace Volo.Abp.FeatureManagement options.FileSets.AddEmbedded(); }); - Configure(options => + Configure(options => { options.JsonSerializerOptions.Converters.AddIfNotContains(new StringValueTypeJsonConverter()); }); 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 bfea58b078..9d94cf8b55 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 @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; -using Volo.Abp.Json.JsonConverters; +using Volo.Abp.Json.SystemTextJson.JsonConverters; using Volo.Abp.Validation.StringValues; namespace Volo.Abp.FeatureManagement.JsonConverters diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index 3df9140805..29cb13d9f3 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -109,7 +109,6 @@ $projects = ( "framework/src/Volo.Abp.Http", "framework/src/Volo.Abp.IdentityModel", "framework/src/Volo.Abp.Json", - "framework/src/Volo.Abp.Json.Newtonsoft", "framework/src/Volo.Abp.Ldap", "framework/src/Volo.Abp.Localization.Abstractions", "framework/src/Volo.Abp.MailKit", From bffccb8f66e8ac6944f5fb2c22ed5fd551293055 Mon Sep 17 00:00:00 2001 From: maliming Date: Sun, 1 Nov 2020 21:52:50 +0800 Subject: [PATCH 08/17] Refactor. --- .../Mvc/Json/AbpHybridJsonInputFormatter.cs | 3 +- .../Mvc/Json/AbpHybridJsonOutputFormatter.cs | 4 +- .../Volo.Abp.Auditing.csproj | 2 +- .../Volo/Abp/Json/AbpHybridJsonSerializer.cs | 28 +++---- .../Volo/Abp/Json/AbpJsonModule.cs | 4 +- .../SystemTextJsonSerializerProvider.cs | 13 +-- .../SystemTextJsonSupportTypeMatcher.cs | 66 +++++++++++++++ ...SystemTextJsonSupportTypeMatcherOptions.cs | 18 ++++ .../SystemTextJsonSupportTypes.cs | 62 -------------- .../SystemTextJsonSupportTypesOptions.cs | 15 ---- .../SystemTextJsonSupportTypeMatcher_Tests.cs | 83 +++++++++++++++++++ .../Json/SystemTextJsonSupportTypes_Tests.cs | 65 --------------- 12 files changed, 195 insertions(+), 168 deletions(-) create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcher.cs create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcherOptions.cs delete mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypes.cs delete mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypesOptions.cs create mode 100644 framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypeMatcher_Tests.cs delete mode 100644 framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypes_Tests.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs index 4ad90bcad2..52cd0c8d63 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs @@ -25,7 +25,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Json private TextInputFormatter GetTextInputFormatter(InputFormatterContext context) { - if (context.HttpContext.RequestServices.GetRequiredService().CanHandle(context.ModelType)) + var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); + if (typesMatcher.Match(context.ModelType)) { return context.HttpContext.RequestServices.GetRequiredService(); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs index 7cf991be96..e0537664da 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs @@ -12,6 +12,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Json { SupportedEncodings.Add(Encoding.UTF8); SupportedEncodings.Add(Encoding.Unicode); + SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJson); SupportedMediaTypes.Add(MediaTypeHeaderValues.TextJson); SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax); @@ -24,7 +25,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Json private TextOutputFormatter GetTextInputFormatter(OutputFormatterWriteContext context) { - if (context.HttpContext.RequestServices.GetRequiredService().CanHandle(context.ObjectType)) + var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); + if (typesMatcher.Match(context.ObjectType)) { return context.HttpContext.RequestServices.GetRequiredService(); } diff --git a/framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj b/framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj index b3548a949b..2685236a89 100644 --- a/framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj +++ b/framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj @@ -22,7 +22,7 @@ - + diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs index 6621ac8640..9980689760 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -7,21 +6,16 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Json { - public class AbpHybridJsonSerializer : IJsonSerializer, ISingletonDependency + public class AbpHybridJsonSerializer : IJsonSerializer, ITransientDependency { - private readonly Lazy> _lazyProviders; - public List Providers => _lazyProviders.Value; + protected AbpJsonOptions Options { get; } + + protected IServiceProvider ServiceProvider { get; } public AbpHybridJsonSerializer(IOptions options, IServiceProvider serviceProvider) { - _lazyProviders = new Lazy>( - () => options.Value - .Providers - .Select(c => serviceProvider.GetRequiredService(c) as IJsonSerializerProvider) - .Reverse() - .ToList(), - true - ); + Options = options.Value; + ServiceProvider = serviceProvider; } public string Serialize(object obj, bool camelCase = true, bool indented = false) @@ -44,12 +38,16 @@ namespace Volo.Abp.Json protected virtual IJsonSerializerProvider GetSerializerProvider(Type type) { - foreach (var provider in Providers.Where(provider => provider.CanHandle(type))) + foreach (var providerType in Options.Providers.Reverse()) { - return provider; + var provider = ServiceProvider.GetRequiredService(providerType) as IJsonSerializerProvider; + if (provider.CanHandle(type)) + { + return provider; + } } - throw new AbpException($"There is no IJsonSerializerProvider that can handle {type.GetFullNameWithAssemblyName()} types!"); + throw new AbpException($"There is no IJsonSerializerProvider that can handle '{type.GetFullNameWithAssemblyName()}'!"); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs index 747f01732a..21d5b67241 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs @@ -23,9 +23,9 @@ namespace Volo.Abp.Json options.Providers.Add(); }); - Configure(options => + Configure(options => { - options.IgnoreAttributes.Add(); + options.UnsupportedAttributes.Add(); }); } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSerializerProvider.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSerializerProvider.cs index 5a3429bff1..623d290fc0 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSerializerProvider.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSerializerProvider.cs @@ -2,25 +2,26 @@ using System.Text.Json; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; -using Volo.Abp.Json.SystemTextJson; -namespace Volo.Abp.Json +namespace Volo.Abp.Json.SystemTextJson { public class SystemTextJsonSerializerProvider : IJsonSerializerProvider, ITransientDependency { protected AbpSystemTextJsonSerializerOptions Options { get; } - protected SystemTextJsonSupportTypes SystemTextJsonSupportTypes { get; } + protected SystemTextJsonSupportTypeMatcher SystemTextJsonSupportTypeMatcher { get; } - public SystemTextJsonSerializerProvider(IOptions options, SystemTextJsonSupportTypes systemTextJsonSupportTypes) + public SystemTextJsonSerializerProvider( + IOptions options, + SystemTextJsonSupportTypeMatcher systemTextJsonSupportTypeMatcher) { - SystemTextJsonSupportTypes = systemTextJsonSupportTypes; + SystemTextJsonSupportTypeMatcher = systemTextJsonSupportTypeMatcher; Options = options.Value; } public bool CanHandle(Type type) { - return SystemTextJsonSupportTypes.CanHandle(type); + return SystemTextJsonSupportTypeMatcher.Match(type); } public string Serialize(object obj, bool camelCase = true, bool indented = false) diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcher.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcher.cs new file mode 100644 index 0000000000..440d453c37 --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcher.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Concurrent; +using System.Linq; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Reflection; +using Volo.Abp.Timing; + +namespace Volo.Abp.Json.SystemTextJson +{ + public class SystemTextJsonSupportTypeMatcher : ITransientDependency + { + private static readonly ConcurrentBag CacheTypes = new ConcurrentBag(); + + private readonly SystemTextJsonSupportTypeMatcherOptions _options; + + public SystemTextJsonSupportTypeMatcher(IOptions options) + { + _options = options.Value; + } + + public bool Match(Type type) + { + if (_options.UnsupportedTypes.Any(x => x == type)) + { + return false; + } + + if (CacheTypes.Contains(type)) + { + return false; + } + + if (type.GetCustomAttributes(true).Any(x => _options.UnsupportedAttributes.Any(a => a == x.GetType()))) + { + CacheTypes.Add(type); + return false; + } + + if (type.DeclaringType != null && type.DeclaringType.GetCustomAttributes(true).Any(x => _options.UnsupportedAttributes.Any(a => a == x.GetType()))) + { + CacheTypes.Add(type); + return false; + } + + foreach (var propertyInfo in type.GetProperties()) + { + if (propertyInfo.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true)) + { + CacheTypes.Add(type); + return false; + } + + if (!TypeHelper.IsPrimitiveExtended(type, includeNullables: true, includeEnums: true)) + { + if (!Match(propertyInfo.PropertyType)) + { + return false; + } + } + } + + return true; + } + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcherOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcherOptions.cs new file mode 100644 index 0000000000..fcf63c7509 --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcherOptions.cs @@ -0,0 +1,18 @@ +using System; +using Volo.Abp.Collections; + +namespace Volo.Abp.Json.SystemTextJson +{ + public class SystemTextJsonSupportTypeMatcherOptions + { + public ITypeList UnsupportedAttributes { get; } + + public ITypeList UnsupportedTypes { get; } + + public SystemTextJsonSupportTypeMatcherOptions() + { + UnsupportedAttributes = new TypeList(); + UnsupportedTypes = new TypeList(); + } + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypes.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypes.cs deleted file mode 100644 index c2061e5b27..0000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypes.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Extensions.Options; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Reflection; -using Volo.Abp.Timing; - -namespace Volo.Abp.Json.SystemTextJson -{ - public class SystemTextJsonSupportTypes : ITransientDependency - { - private static readonly List CacheTypes = new List(); - - private readonly SystemTextJsonSupportTypesOptions Options; - - public SystemTextJsonSupportTypes(IOptions options) - { - Options = options.Value; - } - - public bool CanHandle(Type type) - { - if (CacheTypes.Any(x => x == type)) - { - return false; - } - - if (type.GetCustomAttributes(true).Any(x => Options.IgnoreAttributes.Any(a => a == x.GetType()))) - { - CacheTypes.Add(type); - return false; - } - - if (type.DeclaringType != null && type.DeclaringType.GetCustomAttributes(true).Any(x => Options.IgnoreAttributes.Any(a => a == x.GetType()))) - { - CacheTypes.Add(type.DeclaringType); - return false; - } - - foreach (var propertyInfo in type.GetProperties()) - { - if (propertyInfo.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true)) - { - CacheTypes.Add(propertyInfo.GetType()); - return false; - } - - if (!TypeHelper.IsPrimitiveExtended(type)) - { - if (!CanHandle(propertyInfo.PropertyType)) - { - CacheTypes.Add(propertyInfo.PropertyType); - return false; - } - } - } - - return true; - } - } -} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypesOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypesOptions.cs deleted file mode 100644 index 33ad53b997..0000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypesOptions.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using Volo.Abp.Collections; - -namespace Volo.Abp.Json.SystemTextJson -{ - public class SystemTextJsonSupportTypesOptions - { - public ITypeList IgnoreAttributes; - - public SystemTextJsonSupportTypesOptions() - { - IgnoreAttributes = new TypeList(); - } - } -} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypeMatcher_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypeMatcher_Tests.cs new file mode 100644 index 0000000000..f67431a026 --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypeMatcher_Tests.cs @@ -0,0 +1,83 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Json.SystemTextJson; +using Volo.Abp.Timing; +using Xunit; + +namespace Volo.Abp.Json +{ + public class SystemTextJsonSupportTypeMatcher_Tests : AbpJsonTestBase + { + private readonly SystemTextJsonSupportTypeMatcher _systemTextJsonSupportTypeMatcher; + + protected override void AfterAddApplication(IServiceCollection services) + { + services.Configure(options => + { + options.UnsupportedTypes.Add(); + }); + + base.AfterAddApplication(services); + } + + public SystemTextJsonSupportTypeMatcher_Tests() + { + _systemTextJsonSupportTypeMatcher = GetRequiredService(); + } + + [Fact] + public void CanHandle_Test() + { + _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass)).ShouldBeFalse(); + _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass2)).ShouldBeFalse(); + _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass3)).ShouldBeFalse(); + _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass4)).ShouldBeFalse(); + + _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass5)).ShouldBeTrue(); + _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass6)).ShouldBeTrue(); + + _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass7)).ShouldBeFalse(); + } + + [DisableDateTimeNormalization] + class MyClass + { + public DateTime Prop1 { get; set; } + } + + class MyClass2 + { + [DisableDateTimeNormalization] + public DateTime Prop1 { get; set; } + } + + class MyClass3 + { + public MyClass4 Prop1 { get; set; } + } + + class MyClass4 + { + [DisableDateTimeNormalization] + public DateTime Prop1 { get; set; } + } + + class MyClass5 + { + public DateTime Prop1 { get; set; } + + public MyClass6 Prop2 { get; set; } + } + + class MyClass6 + { + public DateTime Prop1 { get; set; } + } + + class MyClass7 + { + public DateTime Prop1 { get; set; } + } + } +} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypes_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypes_Tests.cs deleted file mode 100644 index b21cb94653..0000000000 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypes_Tests.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using Shouldly; -using Volo.Abp.Json.SystemTextJson; -using Volo.Abp.Timing; -using Xunit; - -namespace Volo.Abp.Json -{ - public class SystemTextJsonSupportTypes_Tests : AbpJsonTestBase - { - private readonly SystemTextJsonSupportTypes _systemTextJsonSupportTypes; - - public SystemTextJsonSupportTypes_Tests() - { - _systemTextJsonSupportTypes = GetRequiredService(); - } - - [Fact] - public void Test() - { - _systemTextJsonSupportTypes.CanHandle(typeof(MyClass)).ShouldBeFalse(); - _systemTextJsonSupportTypes.CanHandle(typeof(MyClass2)).ShouldBeFalse(); - _systemTextJsonSupportTypes.CanHandle(typeof(MyClass3)).ShouldBeFalse(); - _systemTextJsonSupportTypes.CanHandle(typeof(MyClass4)).ShouldBeFalse(); - - _systemTextJsonSupportTypes.CanHandle(typeof(MyClass5)).ShouldBeTrue(); - _systemTextJsonSupportTypes.CanHandle(typeof(MyClass6)).ShouldBeTrue(); - } - - [DisableDateTimeNormalization] - class MyClass - { - public DateTime Prop1 { get; set; } - } - - class MyClass2 - { - [DisableDateTimeNormalization] - public DateTime Prop1 { get; set; } - } - - class MyClass3 - { - public MyClass4 Prop1 { get; set; } - } - - class MyClass4 - { - [DisableDateTimeNormalization] - public DateTime Prop1 { get; set; } - } - - class MyClass5 - { - public DateTime Prop1 { get; set; } - - public MyClass6 Prop2 { get; set; } - } - - class MyClass6 - { - public DateTime Prop1 { get; set; } - } - } -} From e0204e9576a7b402fc4a98a467e9b31f09b0dfcd Mon Sep 17 00:00:00 2001 From: maliming Date: Sun, 1 Nov 2020 22:11:59 +0800 Subject: [PATCH 09/17] Add AbpJsonIsoDateTimeConverter to AbpNewtonsoftJsonSerializerOptions. --- .../Mvc/Json/AbpHybridJsonInputFormatter.cs | 4 ++-- .../Mvc/Json/AbpHybridJsonOutputFormatter.cs | 2 +- .../Mvc/Json/AbpMvcJsonContractResolver.cs | 12 ++++++++---- .../src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs | 5 +++++ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs index 52cd0c8d63..ce6036f71f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Json return await GetTextInputFormatter(context).ReadRequestBodyAsync(context, encoding); } - private TextInputFormatter GetTextInputFormatter(InputFormatterContext context) + protected virtual TextInputFormatter GetTextInputFormatter(InputFormatterContext context) { var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); if (typesMatcher.Match(context.ModelType)) @@ -34,6 +34,6 @@ namespace Volo.Abp.AspNetCore.Mvc.Json return context.HttpContext.RequestServices.GetRequiredService(); } - public InputFormatterExceptionPolicy ExceptionPolicy => InputFormatterExceptionPolicy.MalformedInputExceptions; + public virtual InputFormatterExceptionPolicy ExceptionPolicy => InputFormatterExceptionPolicy.MalformedInputExceptions; } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs index e0537664da..d4f1d67f22 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Json await GetTextInputFormatter(context).WriteResponseBodyAsync(context, selectedEncoding); } - private TextOutputFormatter GetTextInputFormatter(OutputFormatterWriteContext context) + protected virtual TextOutputFormatter GetTextInputFormatter(OutputFormatterWriteContext context) { var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); if (typesMatcher.Match(context.ObjectType)) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs index 2db8bc3f06..2021afd492 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs @@ -1,5 +1,6 @@ using System; using System.Reflection; +using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Volo.Abp.DependencyInjection; @@ -11,11 +12,14 @@ namespace Volo.Abp.AspNetCore.Mvc.Json { public class AbpMvcJsonContractResolver : DefaultContractResolver, ITransientDependency { - private readonly AbpJsonIsoDateTimeConverter _dateTimeConverter; + private readonly Lazy _dateTimeConverter; - public AbpMvcJsonContractResolver(AbpJsonIsoDateTimeConverter dateTimeConverter) + public AbpMvcJsonContractResolver(IServiceProvider serviceProvider) { - _dateTimeConverter = dateTimeConverter; + _dateTimeConverter = new Lazy( + serviceProvider.GetRequiredService, + true + ); NamingStrategy = new CamelCaseNamingStrategy(); } @@ -38,7 +42,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Json if (ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(member) == null) { - property.Converter = _dateTimeConverter; + property.Converter = _dateTimeConverter.Value; } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs index 21d5b67241..8eb683c515 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs @@ -27,6 +27,11 @@ namespace Volo.Abp.Json { options.UnsupportedAttributes.Add(); }); + + Configure(options => + { + options.Converters.Add(); + }); } } } From dee8f22055c70620694cbf5ca8a926c4d20b7161 Mon Sep 17 00:00:00 2001 From: maliming Date: Sun, 1 Nov 2020 23:13:56 +0800 Subject: [PATCH 10/17] Enhanced SystemTextJsonSupportTypeMatcher. --- .../SystemTextJsonSupportTypeMatcher.cs | 130 +++++++++++++++++- .../SystemTextJsonSupportTypeMatcher_Tests.cs | 30 ++++ 2 files changed, 153 insertions(+), 7 deletions(-) diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcher.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcher.cs index 440d453c37..9ac2f16f78 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcher.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcher.cs @@ -10,7 +10,8 @@ namespace Volo.Abp.Json.SystemTextJson { public class SystemTextJsonSupportTypeMatcher : ITransientDependency { - private static readonly ConcurrentBag CacheTypes = new ConcurrentBag(); + private static readonly ConcurrentBag SupportedTypesCache = new ConcurrentBag(); + private static readonly ConcurrentBag UnsupportedTypesCache = new ConcurrentBag(); private readonly SystemTextJsonSupportTypeMatcherOptions _options; @@ -21,25 +22,83 @@ namespace Volo.Abp.Json.SystemTextJson public bool Match(Type type) { - if (_options.UnsupportedTypes.Any(x => x == type)) + if (UnsupportedTypesCache.Contains(type)) { return false; } - if (CacheTypes.Contains(type)) + if (SupportedTypesCache.Contains(type)) { + return true; + } + + if (_options.UnsupportedTypes.Any(x => x == type)) + { + UnsupportedTypesCache.Add(type); return false; } + if (type.IsGenericType) + { + foreach (var genericArgument in type.GetGenericArguments()) + { + if (!TypeHelper.IsPrimitiveExtended(genericArgument, includeNullables: true, includeEnums: true)) + { + if (!Match(genericArgument)) + { + return false; + } + } + else + { + if (_options.UnsupportedTypes.Any(x => x == genericArgument)) + { + UnsupportedTypesCache.Add(genericArgument); + return false; + } + } + } + + return true; + } + + if (type.IsArray) + { + var elementType = type.GetElementType(); + if (!TypeHelper.IsPrimitiveExtended(elementType, includeNullables: true, includeEnums: true)) + { + if (!Match(elementType)) + { + return false; + } + } + else + { + if (_options.UnsupportedTypes.Any(x => x == elementType)) + { + UnsupportedTypesCache.Add(elementType); + return false; + } + } + + return true; + } + + + if (TypeHelper.IsPrimitiveExtended(type, includeNullables: true, includeEnums: true)) + { + return true; + } + if (type.GetCustomAttributes(true).Any(x => _options.UnsupportedAttributes.Any(a => a == x.GetType()))) { - CacheTypes.Add(type); + UnsupportedTypesCache.Add(type); return false; } if (type.DeclaringType != null && type.DeclaringType.GetCustomAttributes(true).Any(x => _options.UnsupportedAttributes.Any(a => a == x.GetType()))) { - CacheTypes.Add(type); + UnsupportedTypesCache.Add(type); return false; } @@ -47,19 +106,76 @@ namespace Volo.Abp.Json.SystemTextJson { if (propertyInfo.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true)) { - CacheTypes.Add(type); + UnsupportedTypesCache.Add(type); + return false; + } + + if (_options.UnsupportedTypes.Any(x => x == propertyInfo.PropertyType)) + { + UnsupportedTypesCache.Add(propertyInfo.PropertyType); return false; } - if (!TypeHelper.IsPrimitiveExtended(type, includeNullables: true, includeEnums: true)) + if (propertyInfo.PropertyType.IsGenericType) + { + foreach (var genericArgument in propertyInfo.PropertyType.GetGenericArguments()) + { + if (!TypeHelper.IsPrimitiveExtended(genericArgument, includeNullables: true, includeEnums: true)) + { + if (!Match(genericArgument)) + { + return false; + } + } + else + { + if (_options.UnsupportedTypes.Any(x => x == genericArgument)) + { + UnsupportedTypesCache.Add(genericArgument); + return false; + } + } + } + } + + if (propertyInfo.PropertyType.IsArray) + { + var elementType = propertyInfo.PropertyType.GetElementType(); + if (!TypeHelper.IsPrimitiveExtended(elementType, includeNullables: true, includeEnums: true)) + { + if (!Match(elementType)) + { + return false; + } + } + else + { + if (_options.UnsupportedTypes.Any(x => x == elementType)) + { + UnsupportedTypesCache.Add(elementType); + return false; + } + } + } + + if (!TypeHelper.IsPrimitiveExtended(propertyInfo.PropertyType, includeNullables: true, includeEnums: true)) { if (!Match(propertyInfo.PropertyType)) { return false; } } + else + { + if (_options.UnsupportedTypes.Any(x => x == propertyInfo.PropertyType)) + { + UnsupportedTypesCache.Add(propertyInfo.PropertyType); + return false; + } + } } + SupportedTypesCache.Add(type); return true; } } diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypeMatcher_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypeMatcher_Tests.cs index f67431a026..6fdc6fcb94 100644 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypeMatcher_Tests.cs +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypeMatcher_Tests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.Json.SystemTextJson; @@ -16,6 +17,7 @@ namespace Volo.Abp.Json services.Configure(options => { options.UnsupportedTypes.Add(); + options.UnsupportedTypes.Add(); }); base.AfterAddApplication(services); @@ -38,6 +40,18 @@ namespace Volo.Abp.Json _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass6)).ShouldBeTrue(); _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass7)).ShouldBeFalse(); + + _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass8)).ShouldBeFalse(); + _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass9)).ShouldBeFalse(); + + _systemTextJsonSupportTypeMatcher.Match(typeof(string)).ShouldBeTrue(); + _systemTextJsonSupportTypeMatcher.Match(typeof(string[])).ShouldBeTrue(); + + _systemTextJsonSupportTypeMatcher.Match(typeof(int)).ShouldBeTrue(); + + _systemTextJsonSupportTypeMatcher.Match(typeof(byte)).ShouldBeFalse(); + _systemTextJsonSupportTypeMatcher.Match(typeof(Dictionary)).ShouldBeFalse(); + _systemTextJsonSupportTypeMatcher.Match(typeof(Dictionary)).ShouldBeFalse(); } [DisableDateTimeNormalization] @@ -79,5 +93,21 @@ namespace Volo.Abp.Json { public DateTime Prop1 { get; set; } } + + class MyClass8 + { + public MyClass10[] Prop1 { get; set; } + } + + class MyClass9 + { + public Dictionary Prop1 { get; set; } + } + + class MyClass10 + { + [DisableDateTimeNormalization] + public DateTime Prop1 { get; set; } + } } } From 74affe2a749ae748ca786d0f4746cf37aff446e7 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 2 Nov 2020 10:29:58 +0800 Subject: [PATCH 11/17] Refactor & add more unit tests. --- .../Mvc/Json/AbpHybridJsonInputFormatter.cs | 2 +- .../Mvc/Json/AbpHybridJsonOutputFormatter.cs | 2 +- .../Mvc/Json/MvcCoreBuilderExtensions.cs | 1 + .../Volo/Abp/Json/AbpJsonModule.cs | 9 +- ...=> AbpNewtonsoftJsonSerializerProvider.cs} | 4 +- ...=> AbpSystemTextJsonSerializerProvider.cs} | 12 +- .../AbpSystemTextJsonSupportTypeMatcher.cs | 21 ++ ...SystemTextJsonSupportTypeMatcherOptions.cs | 14 ++ .../SystemTextJsonSupportTypeMatcher.cs | 182 ------------------ ...SystemTextJsonSupportTypeMatcherOptions.cs | 18 -- .../ModelBinding/ModelBindingController.cs | 10 + .../ModelBindingController_Tests.cs | 43 ++++- ...pSystemTextJsonSupportTypeMatcher_Tests.cs | 66 +++++++ .../SystemTextJsonSupportTypeMatcher_Tests.cs | 113 ----------- 14 files changed, 165 insertions(+), 332 deletions(-) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/{NewtonsoftJsonSerializerProvider.cs => AbpNewtonsoftJsonSerializerProvider.cs} (94%) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/{SystemTextJsonSerializerProvider.cs => AbpSystemTextJsonSerializerProvider.cs} (75%) create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcher.cs create mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcherOptions.cs delete mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcher.cs delete mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcherOptions.cs create mode 100644 framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSupportTypeMatcher_Tests.cs delete mode 100644 framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypeMatcher_Tests.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs index ce6036f71f..43d59c4e3d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Json protected virtual TextInputFormatter GetTextInputFormatter(InputFormatterContext context) { - var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); + var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); if (typesMatcher.Match(context.ModelType)) { return context.HttpContext.RequestServices.GetRequiredService(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs index d4f1d67f22..54039abf1a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Json protected virtual TextOutputFormatter GetTextInputFormatter(OutputFormatterWriteContext context) { - var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); + var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); if (typesMatcher.Match(context.ObjectType)) { return context.HttpContext.RequestServices.GetRequiredService(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs index 9eaa0c826a..5a01cafb22 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs @@ -23,6 +23,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Json return new SystemTextJsonInputFormatter(jsonOptions.Value, logger); }); + builder.Services.AddTransient(); //NewtonsoftJsonInputFormatter builder.Services.AddTransient(provider => { diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs index 8eb683c515..c5f102f9c9 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs @@ -19,13 +19,8 @@ namespace Volo.Abp.Json Configure(options => { - options.Providers.Add(); - options.Providers.Add(); - }); - - Configure(options => - { - options.UnsupportedAttributes.Add(); + options.Providers.Add(); + options.Providers.Add(); }); Configure(options => diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializerProvider.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerProvider.cs similarity index 94% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializerProvider.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerProvider.cs index e33f9b155f..2d288459cf 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializerProvider.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerProvider.cs @@ -9,14 +9,14 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Json.Newtonsoft { - public class NewtonsoftJsonSerializerProvider : IJsonSerializerProvider, ITransientDependency + public class AbpNewtonsoftJsonSerializerProvider : IJsonSerializerProvider, ITransientDependency { private static readonly CamelCaseExceptDictionaryKeysResolver SharedCamelCaseExceptDictionaryKeysResolver = new CamelCaseExceptDictionaryKeysResolver(); protected List Converters { get; } - public NewtonsoftJsonSerializerProvider( + public AbpNewtonsoftJsonSerializerProvider( IOptions options, IServiceProvider serviceProvider) { diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSerializerProvider.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs similarity index 75% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSerializerProvider.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs index 623d290fc0..1bf5f214d6 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSerializerProvider.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs @@ -5,23 +5,23 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Json.SystemTextJson { - public class SystemTextJsonSerializerProvider : IJsonSerializerProvider, ITransientDependency + public class AbpSystemTextJsonSerializerProvider : IJsonSerializerProvider, ITransientDependency { protected AbpSystemTextJsonSerializerOptions Options { get; } - protected SystemTextJsonSupportTypeMatcher SystemTextJsonSupportTypeMatcher { get; } + protected AbpSystemTextJsonSupportTypeMatcher AbpSystemTextJsonSupportTypeMatcher { get; } - public SystemTextJsonSerializerProvider( + public AbpSystemTextJsonSerializerProvider( IOptions options, - SystemTextJsonSupportTypeMatcher systemTextJsonSupportTypeMatcher) + AbpSystemTextJsonSupportTypeMatcher abpSystemTextJsonSupportTypeMatcher) { - SystemTextJsonSupportTypeMatcher = systemTextJsonSupportTypeMatcher; + AbpSystemTextJsonSupportTypeMatcher = abpSystemTextJsonSupportTypeMatcher; Options = options.Value; } public bool CanHandle(Type type) { - return SystemTextJsonSupportTypeMatcher.Match(type); + return AbpSystemTextJsonSupportTypeMatcher.Match(type); } public string Serialize(object obj, bool camelCase = true, bool indented = false) diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcher.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcher.cs new file mode 100644 index 0000000000..e53a4a1b1e --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcher.cs @@ -0,0 +1,21 @@ +using System; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Json.SystemTextJson +{ + public class AbpSystemTextJsonSupportTypeMatcher : ITransientDependency + { + protected AbpSystemTextJsonSupportTypeMatcherOptions Options { get; } + + public AbpSystemTextJsonSupportTypeMatcher(IOptions options) + { + Options = options.Value; + } + + public virtual bool Match(Type type) + { + return !Options.UnsupportedTypes.Contains(type); + } + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcherOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcherOptions.cs new file mode 100644 index 0000000000..be9b62352f --- /dev/null +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcherOptions.cs @@ -0,0 +1,14 @@ +using Volo.Abp.Collections; + +namespace Volo.Abp.Json.SystemTextJson +{ + public class AbpSystemTextJsonSupportTypeMatcherOptions + { + public ITypeList UnsupportedTypes { get; } + + public AbpSystemTextJsonSupportTypeMatcherOptions() + { + UnsupportedTypes = new TypeList(); + } + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcher.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcher.cs deleted file mode 100644 index 9ac2f16f78..0000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcher.cs +++ /dev/null @@ -1,182 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Linq; -using Microsoft.Extensions.Options; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Reflection; -using Volo.Abp.Timing; - -namespace Volo.Abp.Json.SystemTextJson -{ - public class SystemTextJsonSupportTypeMatcher : ITransientDependency - { - private static readonly ConcurrentBag SupportedTypesCache = new ConcurrentBag(); - private static readonly ConcurrentBag UnsupportedTypesCache = new ConcurrentBag(); - - private readonly SystemTextJsonSupportTypeMatcherOptions _options; - - public SystemTextJsonSupportTypeMatcher(IOptions options) - { - _options = options.Value; - } - - public bool Match(Type type) - { - if (UnsupportedTypesCache.Contains(type)) - { - return false; - } - - if (SupportedTypesCache.Contains(type)) - { - return true; - } - - if (_options.UnsupportedTypes.Any(x => x == type)) - { - UnsupportedTypesCache.Add(type); - return false; - } - - if (type.IsGenericType) - { - foreach (var genericArgument in type.GetGenericArguments()) - { - if (!TypeHelper.IsPrimitiveExtended(genericArgument, includeNullables: true, includeEnums: true)) - { - if (!Match(genericArgument)) - { - return false; - } - } - else - { - if (_options.UnsupportedTypes.Any(x => x == genericArgument)) - { - UnsupportedTypesCache.Add(genericArgument); - return false; - } - } - } - - return true; - } - - if (type.IsArray) - { - var elementType = type.GetElementType(); - if (!TypeHelper.IsPrimitiveExtended(elementType, includeNullables: true, includeEnums: true)) - { - if (!Match(elementType)) - { - return false; - } - } - else - { - if (_options.UnsupportedTypes.Any(x => x == elementType)) - { - UnsupportedTypesCache.Add(elementType); - return false; - } - } - - return true; - } - - - if (TypeHelper.IsPrimitiveExtended(type, includeNullables: true, includeEnums: true)) - { - return true; - } - - if (type.GetCustomAttributes(true).Any(x => _options.UnsupportedAttributes.Any(a => a == x.GetType()))) - { - UnsupportedTypesCache.Add(type); - return false; - } - - if (type.DeclaringType != null && type.DeclaringType.GetCustomAttributes(true).Any(x => _options.UnsupportedAttributes.Any(a => a == x.GetType()))) - { - UnsupportedTypesCache.Add(type); - return false; - } - - foreach (var propertyInfo in type.GetProperties()) - { - if (propertyInfo.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true)) - { - UnsupportedTypesCache.Add(type); - return false; - } - - if (_options.UnsupportedTypes.Any(x => x == propertyInfo.PropertyType)) - { - UnsupportedTypesCache.Add(propertyInfo.PropertyType); - return false; - } - - if (propertyInfo.PropertyType.IsGenericType) - { - foreach (var genericArgument in propertyInfo.PropertyType.GetGenericArguments()) - { - if (!TypeHelper.IsPrimitiveExtended(genericArgument, includeNullables: true, includeEnums: true)) - { - if (!Match(genericArgument)) - { - return false; - } - } - else - { - if (_options.UnsupportedTypes.Any(x => x == genericArgument)) - { - UnsupportedTypesCache.Add(genericArgument); - return false; - } - } - } - } - - if (propertyInfo.PropertyType.IsArray) - { - var elementType = propertyInfo.PropertyType.GetElementType(); - if (!TypeHelper.IsPrimitiveExtended(elementType, includeNullables: true, includeEnums: true)) - { - if (!Match(elementType)) - { - return false; - } - } - else - { - if (_options.UnsupportedTypes.Any(x => x == elementType)) - { - UnsupportedTypesCache.Add(elementType); - return false; - } - } - } - - if (!TypeHelper.IsPrimitiveExtended(propertyInfo.PropertyType, includeNullables: true, includeEnums: true)) - { - if (!Match(propertyInfo.PropertyType)) - { - return false; - } - } - else - { - if (_options.UnsupportedTypes.Any(x => x == propertyInfo.PropertyType)) - { - UnsupportedTypesCache.Add(propertyInfo.PropertyType); - return false; - } - } - } - - SupportedTypesCache.Add(type); - return true; - } - } -} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcherOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcherOptions.cs deleted file mode 100644 index fcf63c7509..0000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/SystemTextJsonSupportTypeMatcherOptions.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using Volo.Abp.Collections; - -namespace Volo.Abp.Json.SystemTextJson -{ - public class SystemTextJsonSupportTypeMatcherOptions - { - public ITypeList UnsupportedAttributes { get; } - - public ITypeList UnsupportedTypes { get; } - - public SystemTextJsonSupportTypeMatcherOptions() - { - UnsupportedAttributes = new TypeList(); - UnsupportedTypes = new TypeList(); - } - } -} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs index 2c5a69e7e7..eea25417fc 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs @@ -39,6 +39,16 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding input.Time3.Value.Kind.ToString().ToLower() + "_" + input.InnerModel.Time4.Kind.ToString().ToLower(); } + + //JSON input and output. + [HttpPost("ComplexTypeDateTimeKind_JSON")] + public string ComplexTypeDateTimeKind_JSON([FromBody]GetDateTimeKindModel input) + { + return input.Time1.Kind.ToString().ToLower() + "_" + + input.Time2.Kind.ToString().ToLower() + "_" + + input.Time3.Value.Kind.ToString().ToLower() + "_" + + input.InnerModel.Time4.Kind.ToString().ToLower(); + } } public class GetDateTimeKindModel diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs index 698723a34a..556521d82c 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs @@ -1,9 +1,14 @@ using System; using System.Net; +using System.Net.Http; +using System.Text; +using System.Text.Json; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Shouldly; +using Volo.Abp.Http; +using Volo.Abp.Json.SystemTextJson; using Volo.Abp.Timing; using Xunit; @@ -13,6 +18,15 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding { protected DateTimeKind DateTimeKind { get; set; } + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + services.Configure(options => + { + options.UnsupportedTypes.Add(); + options.UnsupportedTypes.Add(); + }); + } + [Fact] public async Task DateTimeKind_Test() { @@ -75,8 +89,29 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding var resultAsString = await response.Content.ReadAsStringAsync(); //Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is UTC //https://docs.microsoft.com/en-us/aspnet/core/migration/31-to-50?view=aspnetcore-3.1&tabs=visual-studio#datetime-values-are-model-bound-as-utc-times - resultAsString.ShouldBe( - $"utc_{DateTimeKind.ToString().ToLower()}_{DateTimeKind.ToString().ToLower()}_utc"); + resultAsString.ShouldBe($"utc_{DateTimeKind.ToString().ToLower()}_{DateTimeKind.ToString().ToLower()}_utc"); + } + + [Fact] + public async Task ComplexTypeDateTimeKind_JSON_Test() + { + var time = DateTime.Parse("2010-01-01T00:00:00Z"); + var response = await Client.PostAsync("/api/model-Binding-test/ComplexTypeDateTimeKind_JSON", + new StringContent(JsonSerializer.Serialize( + new GetDateTimeKindModel { + Time1 = time, + Time2 = time, + Time3 = time, + InnerModel = new GetDateTimeKindModel.GetDateTimeKindInnerModel + { + Time4 = time + } + } + ), Encoding.UTF8, MimeTypes.Application.Json)); + + response.StatusCode.ShouldBe(HttpStatusCode.OK); + var resultAsString = await response.Content.ReadAsStringAsync(); + resultAsString.ShouldBe($"local_{DateTimeKind.ToString().ToLower()}_{DateTimeKind.ToString().ToLower()}_local"); } } @@ -86,6 +121,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding { DateTimeKind = DateTimeKind.Utc; services.Configure(x => x.Kind = DateTimeKind); + + base.ConfigureServices(context, services); } } @@ -95,6 +132,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding { DateTimeKind = DateTimeKind.Local; services.Configure(x => x.Kind = DateTimeKind); + + base.ConfigureServices(context, services); } } } diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSupportTypeMatcher_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSupportTypeMatcher_Tests.cs new file mode 100644 index 0000000000..0e49181fab --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSupportTypeMatcher_Tests.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Json.SystemTextJson; +using Xunit; + +namespace Volo.Abp.Json +{ + public class AbpSystemTextJsonSupportTypeMatcher_Tests : AbpJsonTestBase + { + private readonly AbpSystemTextJsonSupportTypeMatcher _abpSystemTextJsonSupportTypeMatcher; + + public AbpSystemTextJsonSupportTypeMatcher_Tests() + { + _abpSystemTextJsonSupportTypeMatcher = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + services.Configure(options => + { + options.UnsupportedTypes.Add(); + options.UnsupportedTypes.Add(); + options.UnsupportedTypes.Add>(); + }); + } + + [Fact] + public void CanHandle_Test() + { + _abpSystemTextJsonSupportTypeMatcher.Match(typeof(MyClass)).ShouldBeFalse(); + _abpSystemTextJsonSupportTypeMatcher.Match(typeof(byte[])).ShouldBeFalse(); + + _abpSystemTextJsonSupportTypeMatcher.Match(typeof(MyClass2)).ShouldBeTrue(); + _abpSystemTextJsonSupportTypeMatcher.Match(typeof(MyClass3)).ShouldBeTrue(); + _abpSystemTextJsonSupportTypeMatcher.Match(typeof(MyClass4)).ShouldBeTrue(); + + _abpSystemTextJsonSupportTypeMatcher.Match(typeof(string)).ShouldBeTrue(); + _abpSystemTextJsonSupportTypeMatcher.Match(typeof(string[])).ShouldBeTrue(); + + _abpSystemTextJsonSupportTypeMatcher.Match(typeof(Dictionary)).ShouldBeFalse(); + _abpSystemTextJsonSupportTypeMatcher.Match(typeof(IDictionary)).ShouldBeTrue(); + } + + class MyClass + { + public DateTime Prop1 { get; set; } + } + + class MyClass2 + { + public DateTime Prop1 { get; set; } + } + + class MyClass3 + { + public MyClass4 Prop1 { get; set; } + } + + class MyClass4 + { + public DateTime Prop1 { get; set; } + } + } +} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypeMatcher_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypeMatcher_Tests.cs deleted file mode 100644 index 6fdc6fcb94..0000000000 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/SystemTextJsonSupportTypeMatcher_Tests.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.DependencyInjection; -using Shouldly; -using Volo.Abp.Json.SystemTextJson; -using Volo.Abp.Timing; -using Xunit; - -namespace Volo.Abp.Json -{ - public class SystemTextJsonSupportTypeMatcher_Tests : AbpJsonTestBase - { - private readonly SystemTextJsonSupportTypeMatcher _systemTextJsonSupportTypeMatcher; - - protected override void AfterAddApplication(IServiceCollection services) - { - services.Configure(options => - { - options.UnsupportedTypes.Add(); - options.UnsupportedTypes.Add(); - }); - - base.AfterAddApplication(services); - } - - public SystemTextJsonSupportTypeMatcher_Tests() - { - _systemTextJsonSupportTypeMatcher = GetRequiredService(); - } - - [Fact] - public void CanHandle_Test() - { - _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass)).ShouldBeFalse(); - _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass2)).ShouldBeFalse(); - _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass3)).ShouldBeFalse(); - _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass4)).ShouldBeFalse(); - - _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass5)).ShouldBeTrue(); - _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass6)).ShouldBeTrue(); - - _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass7)).ShouldBeFalse(); - - _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass8)).ShouldBeFalse(); - _systemTextJsonSupportTypeMatcher.Match(typeof(MyClass9)).ShouldBeFalse(); - - _systemTextJsonSupportTypeMatcher.Match(typeof(string)).ShouldBeTrue(); - _systemTextJsonSupportTypeMatcher.Match(typeof(string[])).ShouldBeTrue(); - - _systemTextJsonSupportTypeMatcher.Match(typeof(int)).ShouldBeTrue(); - - _systemTextJsonSupportTypeMatcher.Match(typeof(byte)).ShouldBeFalse(); - _systemTextJsonSupportTypeMatcher.Match(typeof(Dictionary)).ShouldBeFalse(); - _systemTextJsonSupportTypeMatcher.Match(typeof(Dictionary)).ShouldBeFalse(); - } - - [DisableDateTimeNormalization] - class MyClass - { - public DateTime Prop1 { get; set; } - } - - class MyClass2 - { - [DisableDateTimeNormalization] - public DateTime Prop1 { get; set; } - } - - class MyClass3 - { - public MyClass4 Prop1 { get; set; } - } - - class MyClass4 - { - [DisableDateTimeNormalization] - public DateTime Prop1 { get; set; } - } - - class MyClass5 - { - public DateTime Prop1 { get; set; } - - public MyClass6 Prop2 { get; set; } - } - - class MyClass6 - { - public DateTime Prop1 { get; set; } - } - - class MyClass7 - { - public DateTime Prop1 { get; set; } - } - - class MyClass8 - { - public MyClass10[] Prop1 { get; set; } - } - - class MyClass9 - { - public Dictionary Prop1 { get; set; } - } - - class MyClass10 - { - [DisableDateTimeNormalization] - public DateTime Prop1 { get; set; } - } - } -} From 5650f6461d857bbabd6b189c4b4bbb3ead2879ad Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 2 Nov 2020 11:26:30 +0800 Subject: [PATCH 12/17] Add AbpHybridJsonSerializer_Tests. --- .../AbpSystemTextJsonSerializerOptions.cs | 5 + .../AbpSystemTextJsonSupportTypeMatcher.cs | 4 +- ...SystemTextJsonSupportTypeMatcherOptions.cs | 14 -- .../ModelBindingController_Tests.cs | 2 +- .../Abp/Json/AbpHybridJsonSerializer_Tests.cs | 125 ++++++++++++++++++ ...pSystemTextJsonSupportTypeMatcher_Tests.cs | 2 +- 6 files changed, 134 insertions(+), 18 deletions(-) delete mode 100644 framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcherOptions.cs create mode 100644 framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHybridJsonSerializer_Tests.cs diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs index 1f986e688b..17a4ba661a 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs @@ -1,4 +1,5 @@ using System.Text.Json; +using Volo.Abp.Collections; namespace Volo.Abp.Json.SystemTextJson { @@ -6,6 +7,8 @@ namespace Volo.Abp.Json.SystemTextJson { public JsonSerializerOptions JsonSerializerOptions { get; } + public ITypeList UnsupportedTypes { get; } + public AbpSystemTextJsonSerializerOptions() { //TODO:Defaults? @@ -13,6 +16,8 @@ namespace Volo.Abp.Json.SystemTextJson //https://github.com/dotnet/runtime/blob/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerDefaults.cs JsonSerializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); + + UnsupportedTypes = new TypeList(); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcher.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcher.cs index e53a4a1b1e..6b991f051a 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcher.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcher.cs @@ -6,9 +6,9 @@ namespace Volo.Abp.Json.SystemTextJson { public class AbpSystemTextJsonSupportTypeMatcher : ITransientDependency { - protected AbpSystemTextJsonSupportTypeMatcherOptions Options { get; } + protected AbpSystemTextJsonSerializerOptions Options { get; } - public AbpSystemTextJsonSupportTypeMatcher(IOptions options) + public AbpSystemTextJsonSupportTypeMatcher(IOptions options) { Options = options.Value; } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcherOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcherOptions.cs deleted file mode 100644 index be9b62352f..0000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcherOptions.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Volo.Abp.Collections; - -namespace Volo.Abp.Json.SystemTextJson -{ - public class AbpSystemTextJsonSupportTypeMatcherOptions - { - public ITypeList UnsupportedTypes { get; } - - public AbpSystemTextJsonSupportTypeMatcherOptions() - { - UnsupportedTypes = new TypeList(); - } - } -} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs index 556521d82c..fcce316772 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs @@ -20,7 +20,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) { - services.Configure(options => + services.Configure(options => { options.UnsupportedTypes.Add(); options.UnsupportedTypes.Add(); diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHybridJsonSerializer_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHybridJsonSerializer_Tests.cs new file mode 100644 index 0000000000..98f8acc7b4 --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHybridJsonSerializer_Tests.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text.Json; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Shouldly; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Json.Newtonsoft; +using Volo.Abp.Json.SystemTextJson; +using Xunit; +using JsonSerializer = Newtonsoft.Json.JsonSerializer; + +namespace Volo.Abp.Json +{ + public class AbpHybridJsonSerializer_Tests : AbpJsonTestBase + { + private readonly IJsonSerializer _jsonSerializer; + + public AbpHybridJsonSerializer_Tests() + { + _jsonSerializer = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + services.Configure(options => + { + options.UnsupportedTypes.Add(); + + options.JsonSerializerOptions.Converters.Add(new SystemTextJsonConverter()); + }); + + services.Configure(options => + { + options.Converters.Add(); + }); + } + + [Fact] + public void NewtonsoftSerialize_Test() + { + var json = _jsonSerializer.Serialize(new MyClass1 + { + Providers = new List + { + new MyClass3() + } + }); + + json.ShouldContain("Newtonsoft"); + } + + [Fact] + public void SystemTextJsonSerialize_Test() + { + var json = _jsonSerializer.Serialize(new MyClass2 + { + Providers = new List + { + new MyClass3() + } + }); + + json.ShouldContain("SystemTextJson"); + } + + public class MyClass1 + { + public string Provider { get; set; } + + public List Providers { get; set; } + } + + public class MyClass2 + { + public string Provider { get; set; } + + public List Providers { get; set; } + } + + public class MyClass3 + { + public string Provider { get; set; } + } + + class NewtonsoftJsonConverter : JsonConverter, ITransientDependency + { + public override void WriteJson(JsonWriter writer, MyClass1 value, JsonSerializer serializer) + { + value.Provider = "Newtonsoft"; + foreach (var provider in value.Providers) + { + provider.Provider = "Newtonsoft"; + } + + writer.WriteRawValue(JsonConvert.SerializeObject(value)); + } + + public override MyClass1 ReadJson(JsonReader reader, Type objectType, MyClass1 existingValue, bool hasExistingValue, JsonSerializer serializer) + { + return (MyClass1)serializer.Deserialize(reader, objectType); + } + } + + class SystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter, ITransientDependency + { + public override void Write(Utf8JsonWriter writer, MyClass2 value, JsonSerializerOptions options) + { + value.Provider = "SystemTextJson"; + foreach (var provider in value.Providers) + { + provider.Provider = "SystemTextJson"; + } + System.Text.Json.JsonSerializer.Serialize(writer, value); + } + + public override MyClass2 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return (MyClass2)System.Text.Json.JsonSerializer.Deserialize(ref reader, typeToConvert); + } + } + } +} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSupportTypeMatcher_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSupportTypeMatcher_Tests.cs index 0e49181fab..929e892af3 100644 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSupportTypeMatcher_Tests.cs +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSupportTypeMatcher_Tests.cs @@ -18,7 +18,7 @@ namespace Volo.Abp.Json protected override void AfterAddApplication(IServiceCollection services) { - services.Configure(options => + services.Configure(options => { options.UnsupportedTypes.Add(); options.UnsupportedTypes.Add(); From 2ab31f491f683083937dd3ba9c9132e547c3b358 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 2 Nov 2020 11:38:15 +0800 Subject: [PATCH 13/17] Rename AbpSystemTextJsonSupportTypeMatcher to AbpSystemTextJsonUnsupportedTypeMatcher. --- .../Mvc/Json/AbpHybridJsonInputFormatter.cs | 4 +- .../Mvc/Json/AbpHybridJsonOutputFormatter.cs | 4 +- .../AbpSystemTextJsonSerializerProvider.cs | 8 +-- ...bpSystemTextJsonUnsupportedTypeMatcher.cs} | 6 +- ...pSystemTextJsonSupportTypeMatcher_Tests.cs | 66 ------------------- ...temTextJsonUnsupportedTypeMatcher_Tests.cs | 66 +++++++++++++++++++ 6 files changed, 77 insertions(+), 77 deletions(-) rename framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/{AbpSystemTextJsonSupportTypeMatcher.cs => AbpSystemTextJsonUnsupportedTypeMatcher.cs} (57%) delete mode 100644 framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSupportTypeMatcher_Tests.cs create mode 100644 framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonUnsupportedTypeMatcher_Tests.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs index 43d59c4e3d..bd2ade69ad 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs @@ -25,8 +25,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Json protected virtual TextInputFormatter GetTextInputFormatter(InputFormatterContext context) { - var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); - if (typesMatcher.Match(context.ModelType)) + var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); + if (!typesMatcher.Match(context.ModelType)) { return context.HttpContext.RequestServices.GetRequiredService(); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs index 54039abf1a..1507457f08 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs @@ -25,8 +25,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Json protected virtual TextOutputFormatter GetTextInputFormatter(OutputFormatterWriteContext context) { - var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); - if (typesMatcher.Match(context.ObjectType)) + var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); + if (!typesMatcher.Match(context.ObjectType)) { return context.HttpContext.RequestServices.GetRequiredService(); } 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 1bf5f214d6..570d1c162c 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 @@ -9,19 +9,19 @@ namespace Volo.Abp.Json.SystemTextJson { protected AbpSystemTextJsonSerializerOptions Options { get; } - protected AbpSystemTextJsonSupportTypeMatcher AbpSystemTextJsonSupportTypeMatcher { get; } + protected AbpSystemTextJsonUnsupportedTypeMatcher AbpSystemTextJsonUnsupportedTypeMatcher { get; } public AbpSystemTextJsonSerializerProvider( IOptions options, - AbpSystemTextJsonSupportTypeMatcher abpSystemTextJsonSupportTypeMatcher) + AbpSystemTextJsonUnsupportedTypeMatcher abpSystemTextJsonUnsupportedTypeMatcher) { - AbpSystemTextJsonSupportTypeMatcher = abpSystemTextJsonSupportTypeMatcher; + AbpSystemTextJsonUnsupportedTypeMatcher = abpSystemTextJsonUnsupportedTypeMatcher; Options = options.Value; } public bool CanHandle(Type type) { - return AbpSystemTextJsonSupportTypeMatcher.Match(type); + return !AbpSystemTextJsonUnsupportedTypeMatcher.Match(type); } public string Serialize(object obj, bool camelCase = true, bool indented = false) diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcher.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonUnsupportedTypeMatcher.cs similarity index 57% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcher.cs rename to framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonUnsupportedTypeMatcher.cs index 6b991f051a..2beea42c68 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSupportTypeMatcher.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonUnsupportedTypeMatcher.cs @@ -4,18 +4,18 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Json.SystemTextJson { - public class AbpSystemTextJsonSupportTypeMatcher : ITransientDependency + public class AbpSystemTextJsonUnsupportedTypeMatcher : ITransientDependency { protected AbpSystemTextJsonSerializerOptions Options { get; } - public AbpSystemTextJsonSupportTypeMatcher(IOptions options) + public AbpSystemTextJsonUnsupportedTypeMatcher(IOptions options) { Options = options.Value; } public virtual bool Match(Type type) { - return !Options.UnsupportedTypes.Contains(type); + return Options.UnsupportedTypes.Contains(type); } } } diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSupportTypeMatcher_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSupportTypeMatcher_Tests.cs deleted file mode 100644 index 929e892af3..0000000000 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSupportTypeMatcher_Tests.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.DependencyInjection; -using Shouldly; -using Volo.Abp.Json.SystemTextJson; -using Xunit; - -namespace Volo.Abp.Json -{ - public class AbpSystemTextJsonSupportTypeMatcher_Tests : AbpJsonTestBase - { - private readonly AbpSystemTextJsonSupportTypeMatcher _abpSystemTextJsonSupportTypeMatcher; - - public AbpSystemTextJsonSupportTypeMatcher_Tests() - { - _abpSystemTextJsonSupportTypeMatcher = GetRequiredService(); - } - - protected override void AfterAddApplication(IServiceCollection services) - { - services.Configure(options => - { - options.UnsupportedTypes.Add(); - options.UnsupportedTypes.Add(); - options.UnsupportedTypes.Add>(); - }); - } - - [Fact] - public void CanHandle_Test() - { - _abpSystemTextJsonSupportTypeMatcher.Match(typeof(MyClass)).ShouldBeFalse(); - _abpSystemTextJsonSupportTypeMatcher.Match(typeof(byte[])).ShouldBeFalse(); - - _abpSystemTextJsonSupportTypeMatcher.Match(typeof(MyClass2)).ShouldBeTrue(); - _abpSystemTextJsonSupportTypeMatcher.Match(typeof(MyClass3)).ShouldBeTrue(); - _abpSystemTextJsonSupportTypeMatcher.Match(typeof(MyClass4)).ShouldBeTrue(); - - _abpSystemTextJsonSupportTypeMatcher.Match(typeof(string)).ShouldBeTrue(); - _abpSystemTextJsonSupportTypeMatcher.Match(typeof(string[])).ShouldBeTrue(); - - _abpSystemTextJsonSupportTypeMatcher.Match(typeof(Dictionary)).ShouldBeFalse(); - _abpSystemTextJsonSupportTypeMatcher.Match(typeof(IDictionary)).ShouldBeTrue(); - } - - class MyClass - { - public DateTime Prop1 { get; set; } - } - - class MyClass2 - { - public DateTime Prop1 { get; set; } - } - - class MyClass3 - { - public MyClass4 Prop1 { get; set; } - } - - class MyClass4 - { - public DateTime Prop1 { get; set; } - } - } -} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonUnsupportedTypeMatcher_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonUnsupportedTypeMatcher_Tests.cs new file mode 100644 index 0000000000..cc31ceca34 --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonUnsupportedTypeMatcher_Tests.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Json.SystemTextJson; +using Xunit; + +namespace Volo.Abp.Json +{ + public class AbpSystemTextJsonUnsupportedTypeMatcher_Tests : AbpJsonTestBase + { + private readonly AbpSystemTextJsonUnsupportedTypeMatcher _abpSystemTextJsonUnsupportedTypeMatcher; + + public AbpSystemTextJsonUnsupportedTypeMatcher_Tests() + { + _abpSystemTextJsonUnsupportedTypeMatcher = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + services.Configure(options => + { + options.UnsupportedTypes.Add(); + options.UnsupportedTypes.Add(); + options.UnsupportedTypes.Add>(); + }); + } + + [Fact] + public void Match_Test() + { + _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(MyClass)).ShouldBeTrue(); + _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(byte[])).ShouldBeTrue(); + + _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(MyClass2)).ShouldBeFalse(); + _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(MyClass3)).ShouldBeFalse(); + _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(MyClass4)).ShouldBeFalse(); + + _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(string)).ShouldBeFalse(); + _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(string[])).ShouldBeFalse(); + + _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(Dictionary)).ShouldBeTrue(); + _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(IDictionary)).ShouldBeFalse(); + } + + class MyClass + { + public DateTime Prop1 { get; set; } + } + + class MyClass2 + { + public DateTime Prop1 { get; set; } + } + + class MyClass3 + { + public MyClass4 Prop1 { get; set; } + } + + class MyClass4 + { + public DateTime Prop1 { get; set; } + } + } +} From f7cf19f335b7e6075811c9e6f93c1a3591c5bca7 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 2 Nov 2020 13:29:09 +0800 Subject: [PATCH 14/17] Use IServiceScopeFactory in AbpHybridJsonSerializer. --- .../Volo/Abp/Json/AbpHybridJsonSerializer.cs | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs index 9980689760..7a108fbac0 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs @@ -10,37 +10,46 @@ namespace Volo.Abp.Json { protected AbpJsonOptions Options { get; } - protected IServiceProvider ServiceProvider { get; } + protected IServiceScopeFactory ServiceScopeFactory { get; } - public AbpHybridJsonSerializer(IOptions options, IServiceProvider serviceProvider) + public AbpHybridJsonSerializer(IOptions options, IServiceScopeFactory serviceScopeFactory) { Options = options.Value; - ServiceProvider = serviceProvider; + ServiceScopeFactory = serviceScopeFactory; } public string Serialize(object obj, bool camelCase = true, bool indented = false) { - var provider = GetSerializerProvider(obj.GetType()); - return provider.Serialize(obj, camelCase, indented); + using (var scope = ServiceScopeFactory.CreateScope()) + { + var serializerProvider = GetSerializerProvider(scope.ServiceProvider, obj.GetType()); + return serializerProvider.Serialize(obj, camelCase, indented); + } } public T Deserialize(string jsonString, bool camelCase = true) { - var provider = GetSerializerProvider(typeof(T)); - return provider.Deserialize(jsonString, camelCase); + using (var scope = ServiceScopeFactory.CreateScope()) + { + var serializerProvider = GetSerializerProvider(scope.ServiceProvider, typeof(T)); + return serializerProvider.Deserialize(jsonString, camelCase); + } } public object Deserialize(Type type, string jsonString, bool camelCase = true) { - var provider = GetSerializerProvider(type); - return provider.Deserialize(type, jsonString, camelCase); + using (var scope = ServiceScopeFactory.CreateScope()) + { + var serializerProvider = GetSerializerProvider(scope.ServiceProvider, type); + return serializerProvider.Deserialize(type, jsonString, camelCase); + } } - protected virtual IJsonSerializerProvider GetSerializerProvider(Type type) + protected virtual IJsonSerializerProvider GetSerializerProvider(IServiceProvider serviceProvider, Type type) { foreach (var providerType in Options.Providers.Reverse()) { - var provider = ServiceProvider.GetRequiredService(providerType) as IJsonSerializerProvider; + var provider = serviceProvider.GetRequiredService(providerType) as IJsonSerializerProvider; if (provider.CanHandle(type)) { return provider; From 739ac37333efc6831441f2c6834ad471b7cc6f75 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 2 Nov 2020 15:08:20 +0800 Subject: [PATCH 15/17] Set ReadCommentHandling, AllowTrailingCommas for JsonSerializerOptions --- .../Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs | 4 ++++ .../Volo/Abp/Json/AbpHybridJsonSerializer.cs | 12 ++++++------ .../src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs | 3 +-- .../AbpSystemTextJsonSerializerOptions.cs | 10 +++++----- .../Json/JsonLocalizationDictionaryBuilder.cs | 4 +++- 5 files changed, 19 insertions(+), 14 deletions(-) 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 b456204ed8..4b63828997 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 @@ -1,4 +1,5 @@ using System; +using System.Text.Json; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -17,6 +18,9 @@ namespace Volo.Abp.AspNetCore.Mvc.Json public void Configure(JsonOptions options) { + options.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip; + options.JsonSerializerOptions.AllowTrailingCommas = true; + options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService()); options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService()); } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs index 7a108fbac0..69f27d4b3c 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs @@ -10,17 +10,17 @@ namespace Volo.Abp.Json { protected AbpJsonOptions Options { get; } - protected IServiceScopeFactory ServiceScopeFactory { get; } + protected IHybridServiceScopeFactory HybridServiceScopeFactory { get; } - public AbpHybridJsonSerializer(IOptions options, IServiceScopeFactory serviceScopeFactory) + public AbpHybridJsonSerializer(IOptions options, IHybridServiceScopeFactory hybridServiceScopeFactory) { Options = options.Value; - ServiceScopeFactory = serviceScopeFactory; + HybridServiceScopeFactory = hybridServiceScopeFactory; } public string Serialize(object obj, bool camelCase = true, bool indented = false) { - using (var scope = ServiceScopeFactory.CreateScope()) + using (var scope = HybridServiceScopeFactory.CreateScope()) { var serializerProvider = GetSerializerProvider(scope.ServiceProvider, obj.GetType()); return serializerProvider.Serialize(obj, camelCase, indented); @@ -29,7 +29,7 @@ namespace Volo.Abp.Json public T Deserialize(string jsonString, bool camelCase = true) { - using (var scope = ServiceScopeFactory.CreateScope()) + using (var scope = HybridServiceScopeFactory.CreateScope()) { var serializerProvider = GetSerializerProvider(scope.ServiceProvider, typeof(T)); return serializerProvider.Deserialize(jsonString, camelCase); @@ -38,7 +38,7 @@ namespace Volo.Abp.Json public object Deserialize(Type type, string jsonString, bool camelCase = true) { - using (var scope = ServiceScopeFactory.CreateScope()) + using (var scope = HybridServiceScopeFactory.CreateScope()) { var serializerProvider = GetSerializerProvider(scope.ServiceProvider, type); return serializerProvider.Deserialize(type, jsonString, camelCase); diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs index c5f102f9c9..fae54ec08b 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs @@ -14,8 +14,7 @@ namespace Volo.Abp.Json public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.TryAddEnumerable(ServiceDescriptor - .Transient, - AbpSystemTextJsonSerializerOptionsSetup>()); + .Transient, AbpSystemTextJsonSerializerOptionsSetup>()); Configure(options => { diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs index 17a4ba661a..e2774df58a 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs @@ -11,11 +11,11 @@ namespace Volo.Abp.Json.SystemTextJson public AbpSystemTextJsonSerializerOptions() { - //TODO:Defaults? - //https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.Core/src/JsonOptions.cs#L18 - //https://github.com/dotnet/runtime/blob/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerDefaults.cs - - JsonSerializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); + JsonSerializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web) + { + ReadCommentHandling = JsonCommentHandling.Skip, + AllowTrailingCommas = true + }; UnsupportedTypes = new TypeList(); } 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 c13fb643bd..9ccc6738a6 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 @@ -36,7 +36,9 @@ namespace Volo.Abp.Localization.Json var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, - DictionaryKeyPolicy = JsonNamingPolicy.CamelCase + DictionaryKeyPolicy = JsonNamingPolicy.CamelCase, + ReadCommentHandling = JsonCommentHandling.Skip, + AllowTrailingCommas = true }; jsonFile = JsonSerializer.Deserialize(jsonString, options); From 3c70e366fbd25ef5e214c75ecb7c8e499bc4d94e Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 3 Nov 2020 21:07:17 +0800 Subject: [PATCH 16/17] Use IServiceScopeFactory in AbpHybridJsonSerializer. --- .../Volo/Abp/Json/AbpHybridJsonSerializer.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs index 69f27d4b3c..560d6baa36 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs @@ -10,17 +10,17 @@ namespace Volo.Abp.Json { protected AbpJsonOptions Options { get; } - protected IHybridServiceScopeFactory HybridServiceScopeFactory { get; } + protected IServiceScopeFactory ServiceScopeFactory { get; } - public AbpHybridJsonSerializer(IOptions options, IHybridServiceScopeFactory hybridServiceScopeFactory) + public AbpHybridJsonSerializer(IOptions options, IServiceScopeFactory serviceScopeFactory) { Options = options.Value; - HybridServiceScopeFactory = hybridServiceScopeFactory; + ServiceScopeFactory = serviceScopeFactory; } public string Serialize(object obj, bool camelCase = true, bool indented = false) { - using (var scope = HybridServiceScopeFactory.CreateScope()) + using (var scope = ServiceScopeFactory.CreateScope()) { var serializerProvider = GetSerializerProvider(scope.ServiceProvider, obj.GetType()); return serializerProvider.Serialize(obj, camelCase, indented); @@ -29,7 +29,7 @@ namespace Volo.Abp.Json public T Deserialize(string jsonString, bool camelCase = true) { - using (var scope = HybridServiceScopeFactory.CreateScope()) + using (var scope = ServiceScopeFactory.CreateScope()) { var serializerProvider = GetSerializerProvider(scope.ServiceProvider, typeof(T)); return serializerProvider.Deserialize(jsonString, camelCase); @@ -38,7 +38,7 @@ namespace Volo.Abp.Json public object Deserialize(Type type, string jsonString, bool camelCase = true) { - using (var scope = HybridServiceScopeFactory.CreateScope()) + using (var scope = ServiceScopeFactory.CreateScope()) { var serializerProvider = GetSerializerProvider(scope.ServiceProvider, type); return serializerProvider.Deserialize(type, jsonString, camelCase); From fb4f46d4d43ce9f91212d05918ea9f2145ee6308 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 3 Nov 2020 21:56:56 +0800 Subject: [PATCH 17/17] Make JsonConverter's Write method simple. --- ...ctionStringValueItemSourceJsonConverter.cs | 10 +-------- .../StringValueTypeJsonConverter.cs | 18 +-------------- .../ValueValidatorJsonConverter.cs | 22 +------------------ 3 files changed, 3 insertions(+), 47 deletions(-) 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 0812fcc59f..feaa68ccc6 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 @@ -26,15 +26,7 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public override void Write(Utf8JsonWriter writer, ISelectionStringValueItemSource value, JsonSerializerOptions options) { var newOptions = JsonSerializerOptionsHelper.Create(options, this); - - if (value.GetType() == typeof(StaticSelectionStringValueItemSource)) - { - JsonSerializer.Serialize(writer, (StaticSelectionStringValueItemSource)value, newOptions); - } - else - { - throw new JsonException("Unknown ISelectionStringValueItemSource type!"); - } + JsonSerializer.Serialize(writer, value, value.GetType(), newOptions); } } } 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 9ca037d001..32748231da 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 @@ -25,23 +25,7 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public override void Write(Utf8JsonWriter writer, IStringValueType value, JsonSerializerOptions options) { var newOptions = JsonSerializerOptionsHelper.Create(options, this); - - if (value.GetType() == typeof(FreeTextStringValueType)) - { - JsonSerializer.Serialize(writer, (FreeTextStringValueType)value, newOptions); - } - else if (value.GetType() == typeof(SelectionStringValueType)) - { - JsonSerializer.Serialize(writer, (SelectionStringValueType)value, newOptions); - } - else if (value.GetType() == typeof(ToggleStringValueType)) - { - JsonSerializer.Serialize(writer, (ToggleStringValueType)value, newOptions); - } - else - { - throw new JsonException("Unknown IStringValueType type!"); - } + JsonSerializer.Serialize(writer, value, value.GetType(), newOptions); } } } 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 9d94cf8b55..7276a36923 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 @@ -33,27 +33,7 @@ namespace Volo.Abp.FeatureManagement.JsonConverters public override void Write(Utf8JsonWriter writer, IValueValidator value, JsonSerializerOptions options) { var newOptions = JsonSerializerOptionsHelper.Create(options, this); - - if (value.GetType() == typeof(AlwaysValidValueValidator)) - { - JsonSerializer.Serialize(writer, (AlwaysValidValueValidator)value, newOptions); - } - else if (value.GetType() == typeof(BooleanValueValidator)) - { - JsonSerializer.Serialize(writer, (BooleanValueValidator)value, newOptions); - } - else if (value.GetType() == typeof(NumericValueValidator)) - { - JsonSerializer.Serialize(writer, (NumericValueValidator)value, newOptions); - } - else if (value.GetType() == typeof(StringValueValidator)) - { - JsonSerializer.Serialize(writer, (StringValueValidator)value, newOptions); - } - else - { - throw new JsonException("Unknown IValueValidator type!"); - } + JsonSerializer.Serialize(writer, value, value.GetType(), newOptions); } protected virtual IValueValidator CreateValueValidatorByName(string name)