pull/5952/head
maliming 5 years ago
parent 8c28ee1dd2
commit bffccb8f66

@ -25,7 +25,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Json
private TextInputFormatter GetTextInputFormatter(InputFormatterContext context)
{
if (context.HttpContext.RequestServices.GetRequiredService<SystemTextJsonSupportTypes>().CanHandle(context.ModelType))
var typesMatcher = context.HttpContext.RequestServices.GetRequiredService<SystemTextJsonSupportTypeMatcher>();
if (typesMatcher.Match(context.ModelType))
{
return context.HttpContext.RequestServices.GetRequiredService<SystemTextJsonInputFormatter>();
}

@ -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<SystemTextJsonSupportTypes>().CanHandle(context.ObjectType))
var typesMatcher = context.HttpContext.RequestServices.GetRequiredService<SystemTextJsonSupportTypeMatcher>();
if (typesMatcher.Match(context.ObjectType))
{
return context.HttpContext.RequestServices.GetRequiredService<SystemTextJsonOutputFormatter>();
}

@ -22,7 +22,7 @@
<ProjectReference Include="..\Volo.Abp.Threading\Volo.Abp.Threading.csproj" />
<ProjectReference Include="..\Volo.Abp.Timing\Volo.Abp.Timing.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>

@ -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<List<IJsonSerializerProvider>> _lazyProviders;
public List<IJsonSerializerProvider> Providers => _lazyProviders.Value;
protected AbpJsonOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }
public AbpHybridJsonSerializer(IOptions<AbpJsonOptions> options, IServiceProvider serviceProvider)
{
_lazyProviders = new Lazy<List<IJsonSerializerProvider>>(
() => 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()}'!");
}
}
}

@ -23,9 +23,9 @@ namespace Volo.Abp.Json
options.Providers.Add<SystemTextJsonSerializerProvider>();
});
Configure<SystemTextJsonSupportTypesOptions>(options =>
Configure<SystemTextJsonSupportTypeMatcherOptions>(options =>
{
options.IgnoreAttributes.Add<DisableDateTimeNormalizationAttribute>();
options.UnsupportedAttributes.Add<DisableDateTimeNormalizationAttribute>();
});
}
}

@ -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<AbpSystemTextJsonSerializerOptions> options, SystemTextJsonSupportTypes systemTextJsonSupportTypes)
public SystemTextJsonSerializerProvider(
IOptions<AbpSystemTextJsonSerializerOptions> 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)

@ -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<Type> CacheTypes = new ConcurrentBag<Type>();
private readonly SystemTextJsonSupportTypeMatcherOptions _options;
public SystemTextJsonSupportTypeMatcher(IOptions<SystemTextJsonSupportTypeMatcherOptions> 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;
}
}
}

@ -0,0 +1,18 @@
using System;
using Volo.Abp.Collections;
namespace Volo.Abp.Json.SystemTextJson
{
public class SystemTextJsonSupportTypeMatcherOptions
{
public ITypeList<Attribute> UnsupportedAttributes { get; }
public ITypeList UnsupportedTypes { get; }
public SystemTextJsonSupportTypeMatcherOptions()
{
UnsupportedAttributes = new TypeList<Attribute>();
UnsupportedTypes = new TypeList();
}
}
}

@ -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<Type> CacheTypes = new List<Type>();
private readonly SystemTextJsonSupportTypesOptions Options;
public SystemTextJsonSupportTypes(IOptions<SystemTextJsonSupportTypesOptions> 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;
}
}
}

@ -1,15 +0,0 @@
using System;
using Volo.Abp.Collections;
namespace Volo.Abp.Json.SystemTextJson
{
public class SystemTextJsonSupportTypesOptions
{
public ITypeList<Attribute> IgnoreAttributes;
public SystemTextJsonSupportTypesOptions()
{
IgnoreAttributes = new TypeList<Attribute>();
}
}
}

@ -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<SystemTextJsonSupportTypeMatcherOptions>(options =>
{
options.UnsupportedTypes.Add<MyClass7>();
});
base.AfterAddApplication(services);
}
public SystemTextJsonSupportTypeMatcher_Tests()
{
_systemTextJsonSupportTypeMatcher = GetRequiredService<SystemTextJsonSupportTypeMatcher>();
}
[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; }
}
}
}

@ -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<SystemTextJsonSupportTypes>();
}
[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; }
}
}
}
Loading…
Cancel
Save