mirror of https://github.com/abpframework/abp.git
39 changed files with 574 additions and 115 deletions
@ -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<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding) |
||||
|
{ |
||||
|
return await GetTextInputFormatter(context).ReadRequestBodyAsync(context, encoding); |
||||
|
} |
||||
|
|
||||
|
private TextInputFormatter GetTextInputFormatter(InputFormatterContext context) |
||||
|
{ |
||||
|
if (context.HttpContext.RequestServices.GetRequiredService<SystemTextJsonSupportTypes>().CanHandle(context.ModelType)) |
||||
|
{ |
||||
|
return context.HttpContext.RequestServices.GetRequiredService<SystemTextJsonInputFormatter>(); |
||||
|
} |
||||
|
|
||||
|
return context.HttpContext.RequestServices.GetRequiredService<NewtonsoftJsonInputFormatter>(); |
||||
|
} |
||||
|
|
||||
|
public InputFormatterExceptionPolicy ExceptionPolicy => InputFormatterExceptionPolicy.MalformedInputExceptions; |
||||
|
} |
||||
|
} |
||||
@ -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<SystemTextJsonSupportTypes>().CanHandle(context.ObjectType)) |
||||
|
{ |
||||
|
return context.HttpContext.RequestServices.GetRequiredService<SystemTextJsonOutputFormatter>(); |
||||
|
} |
||||
|
|
||||
|
return context.HttpContext.RequestServices.GetRequiredService<NewtonsoftJsonOutputFormatter>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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<DisableDateTimeNormalizationAttribute>(member) == null) |
||||
|
{ |
||||
|
property.Converter = _dateTimeConverter; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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<MvcNewtonsoftJsonOptions> |
||||
|
{ |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
|
public AbpMvcNewtonsoftJsonOptionsSetup(IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
ServiceProvider = serviceProvider; |
||||
|
} |
||||
|
|
||||
|
public void Configure(MvcNewtonsoftJsonOptions options) |
||||
|
{ |
||||
|
options.SerializerSettings.ContractResolver = ServiceProvider.GetRequiredService<AbpMvcJsonContractResolver>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using Microsoft.Net.Http.Headers; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.Json |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.NewtonsoftJson/src/MediaTypeHeaderValues.cs
|
||||
|
/// </summary>
|
||||
|
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(); |
||||
|
} |
||||
|
} |
||||
@ -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<IOptions<JsonOptions>>(); |
||||
|
var logger = provider.GetRequiredService<ILoggerFactory>().CreateLogger<SystemTextJsonInputFormatter>(); |
||||
|
return new SystemTextJsonInputFormatter(jsonOptions.Value, logger); |
||||
|
}); |
||||
|
|
||||
|
//NewtonsoftJsonInputFormatter
|
||||
|
builder.Services.AddTransient(provider => |
||||
|
{ |
||||
|
var jsonOptions = provider.GetRequiredService<IOptions<MvcNewtonsoftJsonOptions>>().Value; |
||||
|
|
||||
|
return new NewtonsoftJsonInputFormatter( |
||||
|
provider.GetRequiredService<ILoggerFactory>().CreateLogger<NewtonsoftJsonInputFormatter>(), |
||||
|
jsonOptions.SerializerSettings, |
||||
|
provider.GetRequiredService<ArrayPool<char>>(), |
||||
|
provider.GetRequiredService<DefaultObjectPoolProvider>(), |
||||
|
provider.GetRequiredService<IOptions<MvcOptions>>().Value, |
||||
|
jsonOptions); |
||||
|
}); |
||||
|
|
||||
|
//SystemTextJsonOutputFormatter
|
||||
|
builder.Services.AddTransient(provider => |
||||
|
{ |
||||
|
var jsonSerializerOptions = provider.GetRequiredService<IOptions<JsonOptions>>().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<IOptions<MvcNewtonsoftJsonOptions>>().Value; |
||||
|
return new NewtonsoftJsonOutputFormatter( |
||||
|
jsonOptions.SerializerSettings, |
||||
|
provider.GetRequiredService<ArrayPool<char>>(), |
||||
|
provider.GetRequiredService<IOptions<MvcOptions>>().Value); |
||||
|
}); |
||||
|
|
||||
|
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<JsonOptions>, AbpJsonOptionsSetup>()); |
||||
|
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<MvcNewtonsoftJsonOptions>, AbpMvcNewtonsoftJsonOptionsSetup>()); |
||||
|
|
||||
|
builder.Services.Configure<MvcOptions>(options => |
||||
|
{ |
||||
|
options.InputFormatters.RemoveType<SystemTextJsonInputFormatter>(); |
||||
|
options.InputFormatters.RemoveType<NewtonsoftJsonInputFormatter>(); |
||||
|
options.InputFormatters.Add(new AbpHybridJsonInputFormatter()); |
||||
|
|
||||
|
options.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>(); |
||||
|
options.OutputFormatters.RemoveType<NewtonsoftJsonOutputFormatter>(); |
||||
|
options.OutputFormatters.Add(new AbpHybridJsonOutputFormatter()); |
||||
|
}); |
||||
|
|
||||
|
return builder; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,3 +0,0 @@ |
|||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|
||||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|
||||
</Weavers> |
|
||||
@ -1,30 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|
||||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|
||||
<xs:element name="Weavers"> |
|
||||
<xs:complexType> |
|
||||
<xs:all> |
|
||||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|
||||
<xs:complexType> |
|
||||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|
||||
</xs:complexType> |
|
||||
</xs:element> |
|
||||
</xs:all> |
|
||||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|
||||
<xs:annotation> |
|
||||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|
||||
</xs:annotation> |
|
||||
</xs:attribute> |
|
||||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|
||||
<xs:annotation> |
|
||||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|
||||
</xs:annotation> |
|
||||
</xs:attribute> |
|
||||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|
||||
<xs:annotation> |
|
||||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|
||||
</xs:annotation> |
|
||||
</xs:attribute> |
|
||||
</xs:complexType> |
|
||||
</xs:element> |
|
||||
</xs:schema> |
|
||||
@ -1,25 +0,0 @@ |
|||||
<Project Sdk="Microsoft.NET.Sdk"> |
|
||||
|
|
||||
<Import Project="..\..\..\configureawait.props" /> |
|
||||
<Import Project="..\..\..\common.props" /> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<TargetFramework>netstandard2.0</TargetFramework> |
|
||||
<AssemblyName>Volo.Abp.Json.Newtonsoft</AssemblyName> |
|
||||
<PackageId>Volo.Abp.Json.Newtonsoft</PackageId> |
|
||||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
|
||||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|
||||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|
||||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|
||||
<RootNamespace /> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<ProjectReference Include="..\Volo.Abp.Json\Volo.Abp.Json.csproj" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
</Project> |
|
||||
@ -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<AbpNewtonsoftJsonSerializerOptions>(options => |
|
||||
{ |
|
||||
options.Converters.Add<AbpJsonIsoDateTimeConverter>(); |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -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<List<IJsonSerializerProvider>> _lazyProviders; |
||||
|
public List<IJsonSerializerProvider> Providers => _lazyProviders.Value; |
||||
|
|
||||
|
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 |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
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<T>(string jsonString, bool camelCase = true) |
||||
|
{ |
||||
|
var provider = GetSerializerProvider(typeof(T)); |
||||
|
return provider.Deserialize<T>(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!"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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<T>(string jsonString, bool camelCase = true); |
||||
|
|
||||
|
object Deserialize(Type type, string jsonString, bool camelCase = true); |
||||
|
} |
||||
|
} |
||||
@ -1,12 +1,12 @@ |
|||||
using System.Text.Json; |
using System.Text.Json; |
||||
|
|
||||
namespace Volo.Abp.Json |
namespace Volo.Abp.Json.SystemTextJson |
||||
{ |
{ |
||||
public class AbpJsonSerializerOptions |
public class AbpSystemTextJsonSerializerOptions |
||||
{ |
{ |
||||
public JsonSerializerOptions JsonSerializerOptions { get; } |
public JsonSerializerOptions JsonSerializerOptions { get; } |
||||
|
|
||||
public AbpJsonSerializerOptions() |
public AbpSystemTextJsonSerializerOptions() |
||||
{ |
{ |
||||
//TODO:Defaults?
|
//TODO:Defaults?
|
||||
//https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.Core/src/JsonOptions.cs#L18
|
//https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.Core/src/JsonOptions.cs#L18
|
||||
@ -1,20 +1,21 @@ |
|||||
using System; |
using System; |
||||
using Microsoft.Extensions.DependencyInjection; |
using Microsoft.Extensions.DependencyInjection; |
||||
using Microsoft.Extensions.Options; |
using Microsoft.Extensions.Options; |
||||
using Volo.Abp.Json.JsonConverters; |
using Volo.Abp.Json.SystemTextJson; |
||||
|
using Volo.Abp.Json.SystemTextJson.JsonConverters; |
||||
|
|
||||
namespace Volo.Abp.Json |
namespace Volo.Abp.Json |
||||
{ |
{ |
||||
public class AbpJsonSerializerOptionsSetup : IConfigureOptions<AbpJsonSerializerOptions> |
public class AbpSystemTextJsonSerializerOptionsSetup : IConfigureOptions<AbpSystemTextJsonSerializerOptions> |
||||
{ |
{ |
||||
protected IServiceProvider ServiceProvider { get; } |
protected IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
public AbpJsonSerializerOptionsSetup(IServiceProvider serviceProvider) |
public AbpSystemTextJsonSerializerOptionsSetup(IServiceProvider serviceProvider) |
||||
{ |
{ |
||||
ServiceProvider = serviceProvider; |
ServiceProvider = serviceProvider; |
||||
} |
} |
||||
|
|
||||
public void Configure(AbpJsonSerializerOptions options) |
public void Configure(AbpSystemTextJsonSerializerOptions options) |
||||
{ |
{ |
||||
options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService<AbpDateTimeConverter>()); |
options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService<AbpDateTimeConverter>()); |
||||
options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService<AbpNullableDateTimeConverter>()); |
options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService<AbpNullableDateTimeConverter>()); |
||||
@ -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<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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
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,16 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.test.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.Json\Volo.Abp.Json.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> |
||||
|
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
||||
|
</ItemGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp.Testing; |
||||
|
|
||||
|
namespace Volo.Abp.Json |
||||
|
{ |
||||
|
public abstract class AbpJsonTestBase : AbpIntegratedTest<AbpJsonTestModule> |
||||
|
{ |
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -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<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…
Reference in new issue