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; } - } - } -}