mirror of https://github.com/abpframework/abp.git
52 changed files with 237 additions and 845 deletions
@ -1,47 +1,21 @@ |
|||||
using System; |
using Microsoft.AspNetCore.Mvc; |
||||
using System.Collections.Generic; |
|
||||
using Microsoft.AspNetCore.Mvc; |
|
||||
using Microsoft.AspNetCore.Mvc.Formatters; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
using Microsoft.Extensions.DependencyInjection; |
||||
using Microsoft.Extensions.DependencyInjection.Extensions; |
|
||||
using Microsoft.Extensions.ObjectPool; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Newtonsoft.Json; |
|
||||
using Volo.Abp.AspNetCore.Mvc.Json; |
|
||||
using Volo.Abp.Json.Newtonsoft; |
using Volo.Abp.Json.Newtonsoft; |
||||
using Volo.Abp.Modularity; |
using Volo.Abp.Modularity; |
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.NewtonsoftJson; |
namespace Volo.Abp.AspNetCore.Mvc.NewtonsoftJson; |
||||
|
|
||||
[DependsOn(typeof(AbpAspNetCoreMvcModule))] |
[DependsOn(typeof(AbpJsonNewtonsoftModule), typeof(AbpAspNetCoreMvcModule))] |
||||
public class AbpAspNetCoreMvcNewtonsoftModule : AbpModule |
public class AbpAspNetCoreMvcNewtonsoftModule : AbpModule |
||||
{ |
{ |
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
{ |
{ |
||||
context.Services.TryAddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>(); |
context.Services.AddMvcCore().AddNewtonsoftJson(); |
||||
|
|
||||
Configure<MvcOptions>(mvcOptions => |
|
||||
{ |
|
||||
mvcOptions.InputFormatters.RemoveType<NewtonsoftJsonInputFormatter>(); |
|
||||
mvcOptions.OutputFormatters.RemoveType<NewtonsoftJsonOutputFormatter>(); |
|
||||
}); |
|
||||
|
|
||||
Configure<AbpHybridJsonFormatterOptions>(formatterOptions => |
|
||||
{ |
|
||||
formatterOptions.TextInputFormatters.Add<AbpNewtonsoftJsonFormatter>(); |
|
||||
formatterOptions.TextOutputFormatters.Add<AbpNewtonsoftJsonFormatter>(); |
|
||||
}); |
|
||||
|
|
||||
context.Services.AddOptions<MvcNewtonsoftJsonOptions>() |
context.Services.AddOptions<MvcNewtonsoftJsonOptions>() |
||||
.Configure<IServiceProvider>((options, serviceProvider) => |
.Configure<AbpCamelCasePropertyNamesContractResolver>((options, contractResolver) => |
||||
{ |
{ |
||||
options.SerializerSettings.ContractResolver = serviceProvider.GetRequiredService<AbpCamelCasePropertyNamesContractResolver>(); |
options.SerializerSettings.ContractResolver = contractResolver; |
||||
|
|
||||
var converters = serviceProvider.GetRequiredService<IOptions<AbpNewtonsoftJsonSerializerOptions>>().Value |
|
||||
.Converters.Select(converterType => serviceProvider.GetRequiredService(converterType).As<JsonConverter>()) |
|
||||
.ToList(); |
|
||||
|
|
||||
options.SerializerSettings.Converters.InsertRange(0, converters); |
|
||||
}); |
}); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,65 +0,0 @@ |
|||||
using System; |
|
||||
using System.Buffers; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.AspNetCore.Mvc; |
|
||||
using Microsoft.AspNetCore.Mvc.Formatters; |
|
||||
using Microsoft.Extensions.Logging; |
|
||||
using Microsoft.Extensions.ObjectPool; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Volo.Abp.AspNetCore.Mvc.Json; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.NewtonsoftJson; |
|
||||
|
|
||||
public class AbpNewtonsoftJsonFormatter : IAbpHybridJsonInputFormatter, IAbpHybridJsonOutputFormatter, ITransientDependency |
|
||||
{ |
|
||||
private readonly ILoggerFactory _loggerFactory; |
|
||||
private readonly ArrayPool<char> _charPool; |
|
||||
private readonly ObjectPoolProvider _objectPoolProvider; |
|
||||
private readonly IOptions<MvcOptions> _mvcOptions; |
|
||||
private readonly IOptions<MvcNewtonsoftJsonOptions> _mvcNewtonsoftJsonOptions; |
|
||||
|
|
||||
public AbpNewtonsoftJsonFormatter( |
|
||||
ILoggerFactory loggerFactory, |
|
||||
ArrayPool<char> charPool, |
|
||||
ObjectPoolProvider objectPoolProvider, |
|
||||
IOptions<MvcOptions> mvcOptions, |
|
||||
IOptions<MvcNewtonsoftJsonOptions> mvcNewtonsoftJsonOptions) |
|
||||
{ |
|
||||
_loggerFactory = loggerFactory; |
|
||||
_charPool = charPool; |
|
||||
_objectPoolProvider = objectPoolProvider; |
|
||||
_mvcOptions = mvcOptions; |
|
||||
_mvcNewtonsoftJsonOptions = mvcNewtonsoftJsonOptions; |
|
||||
} |
|
||||
|
|
||||
Task<bool> IAbpHybridJsonInputFormatter.CanHandleAsync(Type type) |
|
||||
{ |
|
||||
return Task.FromResult(true); |
|
||||
} |
|
||||
|
|
||||
public Task<TextInputFormatter> GetTextInputFormatterAsync() |
|
||||
{ |
|
||||
return Task.FromResult<TextInputFormatter>(new NewtonsoftJsonInputFormatter( |
|
||||
_loggerFactory.CreateLogger<NewtonsoftJsonInputFormatter>(), |
|
||||
_mvcNewtonsoftJsonOptions.Value.SerializerSettings, |
|
||||
_charPool, |
|
||||
_objectPoolProvider, |
|
||||
_mvcOptions.Value, |
|
||||
_mvcNewtonsoftJsonOptions.Value)); |
|
||||
} |
|
||||
|
|
||||
Task<bool> IAbpHybridJsonOutputFormatter.CanHandleAsync(Type type) |
|
||||
{ |
|
||||
return Task.FromResult(true); |
|
||||
} |
|
||||
|
|
||||
public Task<TextOutputFormatter> GetTextOutputFormatterAsync() |
|
||||
{ |
|
||||
return Task.FromResult<TextOutputFormatter>(new NewtonsoftJsonOutputFormatter( |
|
||||
_mvcNewtonsoftJsonOptions.Value.SerializerSettings, |
|
||||
_charPool, |
|
||||
_mvcOptions.Value, |
|
||||
_mvcNewtonsoftJsonOptions.Value)); |
|
||||
} |
|
||||
} |
|
||||
@ -1,17 +0,0 @@ |
|||||
using Microsoft.AspNetCore.Mvc.Formatters; |
|
||||
using Volo.Abp.Collections; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.Json; |
|
||||
|
|
||||
public class AbpHybridJsonFormatterOptions |
|
||||
{ |
|
||||
public ITypeList<IAbpHybridJsonInputFormatter> TextInputFormatters { get; } |
|
||||
|
|
||||
public ITypeList<IAbpHybridJsonInputFormatter> TextOutputFormatters { get; } |
|
||||
|
|
||||
public AbpHybridJsonFormatterOptions() |
|
||||
{ |
|
||||
TextInputFormatters = new TypeList<IAbpHybridJsonInputFormatter>(); |
|
||||
TextOutputFormatters = new TypeList<IAbpHybridJsonInputFormatter>(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,44 +0,0 @@ |
|||||
using System; |
|
||||
using System.Text; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.AspNetCore.Mvc.Formatters; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
|
|
||||
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 (await GetTextInputFormatterAsync(context)).ReadRequestBodyAsync(context, encoding); |
|
||||
} |
|
||||
|
|
||||
protected virtual async Task<TextInputFormatter> GetTextInputFormatterAsync(InputFormatterContext context) |
|
||||
{ |
|
||||
var options = context.HttpContext.RequestServices.GetRequiredService<IOptions<AbpHybridJsonFormatterOptions>>().Value; |
|
||||
|
|
||||
foreach (var inputFormatterType in options.TextInputFormatters) |
|
||||
{ |
|
||||
var inputFormatter = context.HttpContext.RequestServices.GetRequiredService(inputFormatterType).As<IAbpHybridJsonInputFormatter>(); |
|
||||
if (await inputFormatter.CanHandleAsync(context.ModelType)) |
|
||||
{ |
|
||||
return await inputFormatter.GetTextInputFormatterAsync(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
throw new AbpException($"The {nameof(AbpHybridJsonInputFormatter)} can't handle '{context.ModelType.GetFullNameWithAssemblyName()}'!"); |
|
||||
} |
|
||||
|
|
||||
public virtual InputFormatterExceptionPolicy ExceptionPolicy => InputFormatterExceptionPolicy.MalformedInputExceptions; |
|
||||
} |
|
||||
@ -1,42 +0,0 @@ |
|||||
using System; |
|
||||
using System.Text; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.AspNetCore.Mvc.Formatters; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
|
|
||||
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 (await GetTextInputFormatter(context)).WriteResponseBodyAsync(context, selectedEncoding); |
|
||||
} |
|
||||
|
|
||||
protected virtual async Task<TextOutputFormatter> GetTextInputFormatter(OutputFormatterWriteContext context) |
|
||||
{ |
|
||||
var options = context.HttpContext.RequestServices.GetRequiredService<IOptions<AbpHybridJsonFormatterOptions>>().Value; |
|
||||
|
|
||||
foreach (var outputFormatterType in options.TextOutputFormatters) |
|
||||
{ |
|
||||
var outputFormatter = context.HttpContext.RequestServices.GetRequiredService(outputFormatterType).As<IAbpHybridJsonOutputFormatter>(); |
|
||||
if (await outputFormatter.CanHandleAsync(context.ObjectType)) |
|
||||
{ |
|
||||
return await outputFormatter.GetTextOutputFormatterAsync(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
throw new AbpException($"The {nameof(AbpHybridJsonOutputFormatter)} can't handle '{context.ObjectType.GetFullNameWithAssemblyName()}'!"); |
|
||||
} |
|
||||
} |
|
||||
@ -1,61 +0,0 @@ |
|||||
using System; |
|
||||
using System.Text.Encodings.Web; |
|
||||
using System.Text.Json; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.AspNetCore.Mvc; |
|
||||
using Microsoft.AspNetCore.Mvc.Formatters; |
|
||||
using Microsoft.Extensions.Logging; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
using Volo.Abp.Json.SystemTextJson; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.Json; |
|
||||
|
|
||||
public class AbpSystemTextJsonFormatter : IAbpHybridJsonInputFormatter, IAbpHybridJsonOutputFormatter, ITransientDependency |
|
||||
{ |
|
||||
private readonly IOptions<JsonOptions> _jsonOptions; |
|
||||
private readonly IOptions<AbpSystemTextJsonSerializerOptions> _systemTextJsonSerializerOptions; |
|
||||
private readonly ILoggerFactory _loggerFactory; |
|
||||
|
|
||||
public AbpSystemTextJsonFormatter( |
|
||||
IOptions<JsonOptions> jsonOptions, |
|
||||
IOptions<AbpSystemTextJsonSerializerOptions> systemTextJsonSerializerOptions, |
|
||||
ILoggerFactory loggerFactory) |
|
||||
{ |
|
||||
_jsonOptions = jsonOptions; |
|
||||
_systemTextJsonSerializerOptions = systemTextJsonSerializerOptions; |
|
||||
_loggerFactory = loggerFactory; |
|
||||
} |
|
||||
|
|
||||
Task<bool> IAbpHybridJsonInputFormatter.CanHandleAsync(Type type) |
|
||||
{ |
|
||||
return Task.FromResult(!_systemTextJsonSerializerOptions.Value.UnsupportedTypes.Contains(type)); |
|
||||
} |
|
||||
|
|
||||
public virtual Task<TextInputFormatter> GetTextInputFormatterAsync() |
|
||||
{ |
|
||||
return Task.FromResult<TextInputFormatter>(new SystemTextJsonInputFormatter( |
|
||||
_jsonOptions.Value, |
|
||||
_loggerFactory.CreateLogger<SystemTextJsonInputFormatter>())); |
|
||||
} |
|
||||
|
|
||||
Task<bool> IAbpHybridJsonOutputFormatter.CanHandleAsync(Type type) |
|
||||
{ |
|
||||
return Task.FromResult(!_systemTextJsonSerializerOptions.Value.UnsupportedTypes.Contains(type)); |
|
||||
} |
|
||||
|
|
||||
public Task<TextOutputFormatter> GetTextOutputFormatterAsync() |
|
||||
{ |
|
||||
var jsonSerializerOptions = _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 Task.FromResult<TextOutputFormatter>(new SystemTextJsonOutputFormatter(jsonSerializerOptions)); |
|
||||
} |
|
||||
} |
|
||||
@ -1,12 +0,0 @@ |
|||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.AspNetCore.Mvc.Formatters; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.Json; |
|
||||
|
|
||||
public interface IAbpHybridJsonInputFormatter |
|
||||
{ |
|
||||
Task<bool> CanHandleAsync(Type type); |
|
||||
|
|
||||
Task<TextInputFormatter> GetTextInputFormatterAsync(); |
|
||||
} |
|
||||
@ -1,12 +0,0 @@ |
|||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.AspNetCore.Mvc.Formatters; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.Json; |
|
||||
|
|
||||
public interface IAbpHybridJsonOutputFormatter |
|
||||
{ |
|
||||
Task<bool> CanHandleAsync(Type type); |
|
||||
|
|
||||
Task<TextOutputFormatter> GetTextOutputFormatterAsync(); |
|
||||
} |
|
||||
@ -1,21 +0,0 @@ |
|||||
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(); |
|
||||
} |
|
||||
@ -1,42 +0,0 @@ |
|||||
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<Type> _ignoredTypes; |
|
||||
|
|
||||
public AuditingContractResolver(List<Type> 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; |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,78 @@ |
|||||
|
using System.Collections.Concurrent; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using System.Text.Json; |
||||
|
using System.Text.Json.Serialization.Metadata; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.Auditing; |
||||
|
|
||||
|
public class JsonAuditSerializer : IAuditSerializer, ITransientDependency |
||||
|
{ |
||||
|
protected AbpAuditingOptions Options; |
||||
|
|
||||
|
public JsonAuditSerializer(IOptions<AbpAuditingOptions> options) |
||||
|
{ |
||||
|
Options = options.Value; |
||||
|
} |
||||
|
|
||||
|
public string Serialize(object obj) |
||||
|
{ |
||||
|
return JsonSerializer.Serialize(obj, CreateJsonSerializerOptions()); |
||||
|
} |
||||
|
|
||||
|
private static readonly ConcurrentDictionary<string, JsonSerializerOptions> JsonSerializerOptionsCache = |
||||
|
new ConcurrentDictionary<string, JsonSerializerOptions>(); |
||||
|
|
||||
|
protected virtual JsonSerializerOptions CreateJsonSerializerOptions() |
||||
|
{ |
||||
|
return JsonSerializerOptionsCache.GetOrAdd(nameof(JsonAuditSerializer), _ => |
||||
|
{ |
||||
|
var settings = new JsonSerializerOptions() |
||||
|
{ |
||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase, |
||||
|
TypeInfoResolver = new DefaultJsonTypeInfoResolver() |
||||
|
{ |
||||
|
Modifiers = |
||||
|
{ |
||||
|
jsonTypeInfo => |
||||
|
{ |
||||
|
if (Options.IgnoredTypes.Any(ignoredType => ignoredType.IsAssignableFrom(jsonTypeInfo.Type))) |
||||
|
{ |
||||
|
jsonTypeInfo.Properties.Clear(); |
||||
|
} |
||||
|
|
||||
|
if (jsonTypeInfo.Type.GetCustomAttributes(typeof(DisableAuditingAttribute), false).Any()) |
||||
|
{ |
||||
|
jsonTypeInfo.Properties.Clear(); |
||||
|
} |
||||
|
|
||||
|
foreach (var property in jsonTypeInfo.Properties) |
||||
|
{ |
||||
|
if (Options.IgnoredTypes.Any(ignoredType => ignoredType.IsAssignableFrom(property.PropertyType))) |
||||
|
{ |
||||
|
property.ShouldSerialize = (_, _) => false; |
||||
|
} |
||||
|
|
||||
|
if (property.AttributeProvider != null && |
||||
|
property.AttributeProvider.GetCustomAttributes(typeof(DisableAuditingAttribute), false).Any()) |
||||
|
{ |
||||
|
property.ShouldSerialize = (_, _) => false; |
||||
|
} |
||||
|
|
||||
|
if (property.PropertyType.DeclaringType != null && |
||||
|
property.PropertyType.DeclaringType.IsDefined(typeof(DisableAuditingAttribute))) |
||||
|
{ |
||||
|
property.ShouldSerialize = (_, _) => false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
return settings; |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -1,43 +0,0 @@ |
|||||
using Microsoft.Extensions.Options; |
|
||||
using Newtonsoft.Json; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
|
|
||||
namespace Volo.Abp.Auditing; |
|
||||
|
|
||||
//TODO: Rename to JsonAuditSerializer
|
|
||||
public class JsonNetAuditSerializer : IAuditSerializer, ITransientDependency |
|
||||
{ |
|
||||
protected AbpAuditingOptions Options; |
|
||||
|
|
||||
public JsonNetAuditSerializer(IOptions<AbpAuditingOptions> options) |
|
||||
{ |
|
||||
Options = options.Value; |
|
||||
} |
|
||||
|
|
||||
public string Serialize(object obj) |
|
||||
{ |
|
||||
return JsonConvert.SerializeObject(obj, GetSharedJsonSerializerSettings()); |
|
||||
} |
|
||||
|
|
||||
private static readonly object SyncObj = new object(); |
|
||||
private static JsonSerializerSettings _sharedJsonSerializerSettings; |
|
||||
|
|
||||
private JsonSerializerSettings GetSharedJsonSerializerSettings() |
|
||||
{ |
|
||||
if (_sharedJsonSerializerSettings == null) |
|
||||
{ |
|
||||
lock (SyncObj) |
|
||||
{ |
|
||||
if (_sharedJsonSerializerSettings == null) |
|
||||
{ |
|
||||
_sharedJsonSerializerSettings = new JsonSerializerSettings |
|
||||
{ |
|
||||
ContractResolver = new AuditingContractResolver(Options.IgnoredTypes) |
|
||||
}; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return _sharedJsonSerializerSettings; |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,9 @@ |
|||||
|
namespace Volo.Abp.Json; |
||||
|
|
||||
|
public class AbpJsonOptions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Used to set default value for the DateTimeFormat.
|
||||
|
/// </summary>
|
||||
|
public string DefaultDateTimeFormat { get; set; } |
||||
|
} |
||||
@ -1,66 +0,0 @@ |
|||||
using System; |
|
||||
using System.Linq; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
|
|
||||
namespace Volo.Abp.Json; |
|
||||
|
|
||||
public class AbpHybridJsonSerializer : IJsonSerializer, ITransientDependency |
|
||||
{ |
|
||||
protected AbpJsonOptions Options { get; } |
|
||||
|
|
||||
protected IServiceScopeFactory ServiceScopeFactory { get; } |
|
||||
|
|
||||
public AbpHybridJsonSerializer(IOptions<AbpJsonOptions> options, IServiceScopeFactory serviceScopeFactory) |
|
||||
{ |
|
||||
Options = options.Value; |
|
||||
ServiceScopeFactory = serviceScopeFactory; |
|
||||
} |
|
||||
|
|
||||
public string Serialize([CanBeNull] object obj, bool camelCase = true, bool indented = false) |
|
||||
{ |
|
||||
using (var scope = ServiceScopeFactory.CreateScope()) |
|
||||
{ |
|
||||
var serializerProvider = GetSerializerProvider(scope.ServiceProvider, obj?.GetType()); |
|
||||
return serializerProvider.Serialize(obj, camelCase, indented); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public T Deserialize<T>([NotNull] string jsonString, bool camelCase = true) |
|
||||
{ |
|
||||
Check.NotNull(jsonString, nameof(jsonString)); |
|
||||
|
|
||||
using (var scope = ServiceScopeFactory.CreateScope()) |
|
||||
{ |
|
||||
var serializerProvider = GetSerializerProvider(scope.ServiceProvider, typeof(T)); |
|
||||
return serializerProvider.Deserialize<T>(jsonString, camelCase); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public object Deserialize(Type type, [NotNull] string jsonString, bool camelCase = true) |
|
||||
{ |
|
||||
Check.NotNull(jsonString, nameof(jsonString)); |
|
||||
|
|
||||
using (var scope = ServiceScopeFactory.CreateScope()) |
|
||||
{ |
|
||||
var serializerProvider = GetSerializerProvider(scope.ServiceProvider, type); |
|
||||
return serializerProvider.Deserialize(type, jsonString, camelCase); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected virtual IJsonSerializerProvider GetSerializerProvider(IServiceProvider serviceProvider, [CanBeNull] Type type) |
|
||||
{ |
|
||||
foreach (var providerType in Options.Providers.Reverse()) |
|
||||
{ |
|
||||
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()}'!"); |
|
||||
} |
|
||||
} |
|
||||
@ -1,18 +0,0 @@ |
|||||
using Volo.Abp.Collections; |
|
||||
|
|
||||
namespace Volo.Abp.Json; |
|
||||
|
|
||||
public class AbpJsonOptions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Used to set default value for the DateTimeFormat.
|
|
||||
/// </summary>
|
|
||||
public string DefaultDateTimeFormat { get; set; } |
|
||||
|
|
||||
public ITypeList<IJsonSerializerProvider> Providers { get; } |
|
||||
|
|
||||
public AbpJsonOptions() |
|
||||
{ |
|
||||
Providers = new TypeList<IJsonSerializerProvider>(); |
|
||||
} |
|
||||
} |
|
||||
@ -1,15 +0,0 @@ |
|||||
using System; |
|
||||
using JetBrains.Annotations; |
|
||||
|
|
||||
namespace Volo.Abp.Json; |
|
||||
|
|
||||
public interface IJsonSerializerProvider |
|
||||
{ |
|
||||
bool CanHandle([CanBeNull] 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); |
|
||||
} |
|
||||
@ -0,0 +1,33 @@ |
|||||
|
using System; |
||||
|
using System.Reflection; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Newtonsoft.Json; |
||||
|
using Newtonsoft.Json.Serialization; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.Json.Newtonsoft; |
||||
|
|
||||
|
public class AbpDefaultContractResolver : DefaultContractResolver, ITransientDependency |
||||
|
{ |
||||
|
private readonly Lazy<AbpJsonIsoDateTimeConverter> _dateTimeConverter; |
||||
|
|
||||
|
public AbpDefaultContractResolver(IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
_dateTimeConverter = new Lazy<AbpJsonIsoDateTimeConverter>( |
||||
|
serviceProvider.GetRequiredService<AbpJsonIsoDateTimeConverter>, |
||||
|
true |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) |
||||
|
{ |
||||
|
var property = base.CreateProperty(member, memberSerialization); |
||||
|
|
||||
|
if (AbpJsonIsoDateTimeConverter.ShouldNormalize(member, property)) |
||||
|
{ |
||||
|
property.Converter = _dateTimeConverter.Value; |
||||
|
} |
||||
|
|
||||
|
return property; |
||||
|
} |
||||
|
} |
||||
@ -1,149 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Text.Json; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Newtonsoft.Json; |
|
||||
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<IJsonSerializer>(); |
|
||||
} |
|
||||
|
|
||||
protected override void AfterAddApplication(IServiceCollection services) |
|
||||
{ |
|
||||
services.Configure<AbpSystemTextJsonSerializerOptions>(options => |
|
||||
{ |
|
||||
options.UnsupportedTypes.Add<MyClass1>(); |
|
||||
|
|
||||
options.JsonSerializerOptions.Converters.Add(new SystemTextJsonConverter()); |
|
||||
}); |
|
||||
|
|
||||
services.Configure<AbpNewtonsoftJsonSerializerOptions>(options => |
|
||||
{ |
|
||||
options.Converters.Add<NewtonsoftJsonConverter>(); |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void NewtonsoftSerialize_Test() |
|
||||
{ |
|
||||
var json = _jsonSerializer.Serialize(new MyClass1 |
|
||||
{ |
|
||||
Providers = new List<MyClass3> |
|
||||
{ |
|
||||
new MyClass3() |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
json.ShouldContain("Newtonsoft"); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void SystemTextJsonSerialize_Test() |
|
||||
{ |
|
||||
var json = _jsonSerializer.Serialize(new MyClass2 |
|
||||
{ |
|
||||
Providers = new List<MyClass3> |
|
||||
{ |
|
||||
new MyClass3() |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
json.ShouldContain("SystemTextJson"); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void SystemTextJsonSerialize_With_Dictionary_Test() |
|
||||
{ |
|
||||
var json = _jsonSerializer.Serialize(new MyClassWithDictionary |
|
||||
{ |
|
||||
Properties = |
|
||||
{ |
|
||||
{"A", "AV"}, |
|
||||
{"B", "BV"} |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
var deserialized = _jsonSerializer.Deserialize<MyClassWithDictionary>(json); |
|
||||
deserialized.Properties.ShouldContain(p => p.Key == "A" && p.Value == "AV"); |
|
||||
deserialized.Properties.ShouldContain(p => p.Key == "B" && p.Value == "BV"); |
|
||||
} |
|
||||
|
|
||||
public class MyClass1 |
|
||||
{ |
|
||||
public string Provider { get; set; } |
|
||||
|
|
||||
public List<MyClass3> Providers { get; set; } |
|
||||
} |
|
||||
|
|
||||
public class MyClass2 |
|
||||
{ |
|
||||
public string Provider { get; set; } |
|
||||
|
|
||||
public List<MyClass3> Providers { get; set; } |
|
||||
} |
|
||||
|
|
||||
public class MyClass3 |
|
||||
{ |
|
||||
public string Provider { get; set; } |
|
||||
} |
|
||||
|
|
||||
public class MyClassWithDictionary |
|
||||
{ |
|
||||
public Dictionary<string, string> Properties { get; set; } |
|
||||
|
|
||||
public MyClassWithDictionary() |
|
||||
{ |
|
||||
Properties = new Dictionary<string, string>(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
class NewtonsoftJsonConverter : JsonConverter<MyClass1>, 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<MyClass2>, 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); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue