Browse Source

Add `Volo.Abp.AspNetCore.Mvc.NewtonsoftJson` package.

pull/13357/head
maliming 4 years ago
parent
commit
f77f92aeee
No known key found for this signature in database GPG Key ID: 96224957E51C89E
  1. 7
      framework/Volo.Abp.sln
  2. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/FodyWeavers.xml
  3. 30
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/FodyWeavers.xsd
  4. 28
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson.csproj
  5. 42
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpAspNetCoreMvcNewtonsoftModule.cs
  6. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpAspNetCoreMvcNewtonsoftOptions.cs
  7. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpMvcNewtonsoftJsonOptionsSetup.cs
  8. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpNewtonsoftJsonContractResolver.cs
  9. 65
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpNewtonsoftJsonFormatter.cs
  10. 1
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj
  11. 17
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonFormatterOptions.cs
  12. 31
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs
  13. 72
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOptionsSetup.cs
  14. 32
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs
  15. 60
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpSystemTextJsonFormatter.cs
  16. 12
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/IAbpHybridJsonInputFormatter.cs
  17. 12
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/IAbpHybridJsonOutputFormatter.cs
  18. 28
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs
  19. 7
      framework/src/Volo.Abp.Json.Core/Volo/Abp/Json/AbpJsonOptions.cs
  20. 9
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs
  21. 2
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj
  22. 3
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs
  23. 1
      nupkg/common.ps1

7
framework/Volo.Abp.sln

@ -415,6 +415,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Json.SystemTextJso
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Json.Core", "src\Volo.Abp.Json.Core\Volo.Abp.Json.Core.csproj", "{08531C5D-0436-4721-986D-96446CF54316}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.NewtonsoftJson", "src\Volo.Abp.AspNetCore.Mvc.NewtonsoftJson\Volo.Abp.AspNetCore.Mvc.NewtonsoftJson.csproj", "{0CFC9D4F-F12F-4B44-ABCF-AB4A0E9E85B2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -1237,6 +1239,10 @@ Global
{08531C5D-0436-4721-986D-96446CF54316}.Debug|Any CPU.Build.0 = Debug|Any CPU
{08531C5D-0436-4721-986D-96446CF54316}.Release|Any CPU.ActiveCfg = Release|Any CPU
{08531C5D-0436-4721-986D-96446CF54316}.Release|Any CPU.Build.0 = Release|Any CPU
{0CFC9D4F-F12F-4B44-ABCF-AB4A0E9E85B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0CFC9D4F-F12F-4B44-ABCF-AB4A0E9E85B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0CFC9D4F-F12F-4B44-ABCF-AB4A0E9E85B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0CFC9D4F-F12F-4B44-ABCF-AB4A0E9E85B2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1446,6 +1452,7 @@ Global
{9DD41C8F-0886-483C-B98B-C55EAA7F226D} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{0AD06E14-CBFE-4551-8D18-9E921D8F2A87} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{08531C5D-0436-4721-986D-96446CF54316} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{0CFC9D4F-F12F-4B44-ABCF-AB4A0E9E85B2} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

3
framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?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>

28
framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson.csproj

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.NewtonsoftJson</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Mvc.NewtonsoftJson</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<IsPackable>true</IsPackable>
<OutputType>Library</OutputType>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc\Volo.Abp.AspNetCore.Mvc.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="$(MicrosoftAspNetCorePackageVersion)" />
</ItemGroup>
</Project>

42
framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpAspNetCoreMvcNewtonsoftModule.cs

@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.ObjectPool;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.Json;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.NewtonsoftJson;
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
public class AbpAspNetCoreMvcNewtonsoftModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var options = context.Services.ExecutePreConfiguredActions<AbpAspNetCoreMvcNewtonsoftOptions>();
if (options.UseHybridSerializer)
{
context.Services.TryAddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
Configure<MvcOptions>(mvcOptions =>
{
mvcOptions.InputFormatters.RemoveType<NewtonsoftJsonInputFormatter>();
mvcOptions.OutputFormatters.RemoveType<NewtonsoftJsonOutputFormatter>();
});
Configure<AbpHybridJsonFormatterOptions>(formatterOptions =>
{
formatterOptions.TextInputFormatters.Add<AbpNewtonsoftJsonFormatter>();
formatterOptions.TextOutputFormatters.Add<AbpNewtonsoftJsonFormatter>();
});
}
else
{
context.Services.AddMvcCore().AddNewtonsoftJson();
}
context.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<MvcNewtonsoftJsonOptions>, AbpMvcNewtonsoftJsonOptionsSetup>());
}
}

11
framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpAspNetCoreMvcNewtonsoftOptions.cs

@ -0,0 +1,11 @@
namespace Volo.Abp.AspNetCore.Mvc.NewtonsoftJson;
public class AbpAspNetCoreMvcNewtonsoftOptions
{
public bool UseHybridSerializer { get; set; }
public AbpAspNetCoreMvcNewtonsoftOptions()
{
UseHybridSerializer = true;
}
}

4
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcNewtonsoftJsonOptionsSetup.cs → framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpMvcNewtonsoftJsonOptionsSetup.cs

@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace Volo.Abp.AspNetCore.Mvc.Json;
namespace Volo.Abp.AspNetCore.Mvc.NewtonsoftJson;
public class AbpMvcNewtonsoftJsonOptionsSetup : IConfigureOptions<MvcNewtonsoftJsonOptions>
{
@ -16,6 +16,6 @@ public class AbpMvcNewtonsoftJsonOptionsSetup : IConfigureOptions<MvcNewtonsoftJ
public void Configure(MvcNewtonsoftJsonOptions options)
{
options.SerializerSettings.ContractResolver = ServiceProvider.GetRequiredService<AbpMvcJsonContractResolver>();
options.SerializerSettings.ContractResolver = ServiceProvider.GetRequiredService<AbpNewtonsoftJsonContractResolver>();
}
}

6
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs → framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpNewtonsoftJsonContractResolver.cs

@ -8,13 +8,13 @@ using Volo.Abp.Json.Newtonsoft;
using Volo.Abp.Reflection;
using Volo.Abp.Timing;
namespace Volo.Abp.AspNetCore.Mvc.Json;
namespace Volo.Abp.AspNetCore.Mvc.NewtonsoftJson;
public class AbpMvcJsonContractResolver : DefaultContractResolver, ITransientDependency
public class AbpNewtonsoftJsonContractResolver : DefaultContractResolver, ITransientDependency
{
private readonly Lazy<AbpJsonIsoDateTimeConverter> _dateTimeConverter;
public AbpMvcJsonContractResolver(IServiceProvider serviceProvider)
public AbpNewtonsoftJsonContractResolver(IServiceProvider serviceProvider)
{
_dateTimeConverter = new Lazy<AbpJsonIsoDateTimeConverter>(
serviceProvider.GetRequiredService<AbpJsonIsoDateTimeConverter>,

65
framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpNewtonsoftJsonFormatter.cs

@ -0,0 +1,65 @@
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
framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj

@ -29,7 +29,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.0.0" />
</ItemGroup>

17
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonFormatterOptions.cs

@ -0,0 +1,17 @@
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>();
}
}

31
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs

@ -1,21 +1,16 @@
using System.Text;
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Json.SystemTextJson;
using Microsoft.Extensions.Options;
namespace Volo.Abp.AspNetCore.Mvc.Json;
public class AbpHybridJsonInputFormatter : TextInputFormatter, IInputFormatterExceptionPolicy
{
private readonly SystemTextJsonInputFormatter _systemTextJsonInputFormatter;
private readonly NewtonsoftJsonInputFormatter _newtonsoftJsonInputFormatter;
public AbpHybridJsonInputFormatter(SystemTextJsonInputFormatter systemTextJsonInputFormatter, NewtonsoftJsonInputFormatter newtonsoftJsonInputFormatter)
public AbpHybridJsonInputFormatter()
{
_systemTextJsonInputFormatter = systemTextJsonInputFormatter;
_newtonsoftJsonInputFormatter = newtonsoftJsonInputFormatter;
SupportedEncodings.Add(UTF8EncodingWithoutBOM);
SupportedEncodings.Add(UTF16EncodingLittleEndian);
@ -24,21 +19,25 @@ public class AbpHybridJsonInputFormatter : TextInputFormatter, IInputFormatterEx
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax);
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
public async override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
{
return await GetTextInputFormatter(context).ReadRequestBodyAsync(context, encoding);
return await (await GetTextInputFormatterAsync(context)).ReadRequestBodyAsync(context, encoding);
}
protected virtual TextInputFormatter GetTextInputFormatter(InputFormatterContext context)
protected virtual async Task<TextInputFormatter> GetTextInputFormatterAsync(InputFormatterContext context)
{
var typesMatcher = context.HttpContext.RequestServices.GetRequiredService<AbpSystemTextJsonUnsupportedTypeMatcher>();
var options = context.HttpContext.RequestServices.GetRequiredService<IOptions<AbpHybridJsonFormatterOptions>>().Value;
if (!typesMatcher.Match(context.ModelType))
foreach (var inputFormatterType in options.TextInputFormatters)
{
return _systemTextJsonInputFormatter;
var inputFormatter = context.HttpContext.RequestServices.GetRequiredService(inputFormatterType).As<IAbpHybridJsonInputFormatter>();
if (await inputFormatter.CanHandleAsync(context.ModelType))
{
return await inputFormatter.GetTextInputFormatterAsync();
}
}
return _newtonsoftJsonInputFormatter;
throw new AbpException($"The {nameof(AbpHybridJsonInputFormatter)} can't handle '{context.ModelType.GetFullNameWithAssemblyName()}'!");
}
public virtual InputFormatterExceptionPolicy ExceptionPolicy => InputFormatterExceptionPolicy.MalformedInputExceptions;

72
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOptionsSetup.cs

@ -1,72 +0,0 @@
using System.Buffers;
using System.Text.Encodings.Web;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.ObjectPool;
using Microsoft.Extensions.Options;
namespace Volo.Abp.AspNetCore.Mvc.Json;
public class AbpHybridJsonOptionsSetup : IConfigureOptions<MvcOptions>
{
private readonly IOptions<JsonOptions> _jsonOptions;
private readonly IOptions<MvcNewtonsoftJsonOptions> _mvcNewtonsoftJsonOptions;
private readonly ILoggerFactory _loggerFactory;
private readonly ArrayPool<char> _charPool;
private readonly ObjectPoolProvider _objectPoolProvider;
public AbpHybridJsonOptionsSetup(
IOptions<JsonOptions> jsonOptions,
IOptions<MvcNewtonsoftJsonOptions> mvcNewtonsoftJsonOptions,
ILoggerFactory loggerFactory,
ArrayPool<char> charPool,
ObjectPoolProvider objectPoolProvider)
{
_jsonOptions = jsonOptions;
_mvcNewtonsoftJsonOptions = mvcNewtonsoftJsonOptions;
_loggerFactory = loggerFactory;
_charPool = charPool;
_objectPoolProvider = objectPoolProvider;
}
public void Configure(MvcOptions options)
{
var systemTextJsonInputFormatter = new SystemTextJsonInputFormatter(
_jsonOptions.Value,
_loggerFactory.CreateLogger<SystemTextJsonInputFormatter>());
var newtonsoftJsonInputFormatter = new NewtonsoftJsonInputFormatter(
_loggerFactory.CreateLogger<NewtonsoftJsonInputFormatter>(),
_mvcNewtonsoftJsonOptions.Value.SerializerSettings,
_charPool,
_objectPoolProvider,
options,
_mvcNewtonsoftJsonOptions.Value);
options.InputFormatters.RemoveType<SystemTextJsonInputFormatter>();
options.InputFormatters.RemoveType<NewtonsoftJsonInputFormatter>();
options.InputFormatters.Add(new AbpHybridJsonInputFormatter(systemTextJsonInputFormatter, newtonsoftJsonInputFormatter));
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,
};
}
var systemTextJsonOutputFormatter = new SystemTextJsonOutputFormatter(jsonSerializerOptions);
var newtonsoftJsonOutputFormatter = new NewtonsoftJsonOutputFormatter(
_mvcNewtonsoftJsonOptions.Value.SerializerSettings,
_charPool,
options);
options.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>();
options.OutputFormatters.RemoveType<NewtonsoftJsonOutputFormatter>();
options.OutputFormatters.Add(new AbpHybridJsonOutputFormatter(systemTextJsonOutputFormatter, newtonsoftJsonOutputFormatter));
}
}

32
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs

@ -1,21 +1,16 @@
using System.Text;
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Json.SystemTextJson;
using Microsoft.Extensions.Options;
namespace Volo.Abp.AspNetCore.Mvc.Json;
public class AbpHybridJsonOutputFormatter : TextOutputFormatter
{
private readonly SystemTextJsonOutputFormatter _systemTextJsonOutputFormatter;
private readonly NewtonsoftJsonOutputFormatter _newtonsoftJsonOutputFormatter;
public AbpHybridJsonOutputFormatter(SystemTextJsonOutputFormatter systemTextJsonOutputFormatter, NewtonsoftJsonOutputFormatter newtonsoftJsonOutputFormatter)
public AbpHybridJsonOutputFormatter()
{
_systemTextJsonOutputFormatter = systemTextJsonOutputFormatter;
_newtonsoftJsonOutputFormatter = newtonsoftJsonOutputFormatter;
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
@ -24,19 +19,24 @@ public class AbpHybridJsonOutputFormatter : TextOutputFormatter
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax);
}
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
public async override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
await GetTextInputFormatter(context).WriteResponseBodyAsync(context, selectedEncoding);
await (await GetTextInputFormatter(context)).WriteResponseBodyAsync(context, selectedEncoding);
}
protected virtual TextOutputFormatter GetTextInputFormatter(OutputFormatterWriteContext context)
protected virtual async Task<TextOutputFormatter> GetTextInputFormatter(OutputFormatterWriteContext context)
{
var typesMatcher = context.HttpContext.RequestServices.GetRequiredService<AbpSystemTextJsonUnsupportedTypeMatcher>();
if (!typesMatcher.Match(context.ObjectType))
var options = context.HttpContext.RequestServices.GetRequiredService<IOptions<AbpHybridJsonFormatterOptions>>().Value;
foreach (var outputFormatterType in options.TextOutputFormatters)
{
return _systemTextJsonOutputFormatter;
var outputFormatter = context.HttpContext.RequestServices.GetRequiredService(outputFormatterType).As<IAbpHybridJsonOutputFormatter>();
if (await outputFormatter.CanHandleAsync(context.ObjectType))
{
return await outputFormatter.GetTextOutputFormatterAsync();
}
}
return _newtonsoftJsonOutputFormatter;
throw new AbpException($"The {nameof(AbpHybridJsonOutputFormatter)} can't handle '{context.ObjectType.GetFullNameWithAssemblyName()}'!");
}
}

60
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpSystemTextJsonFormatter.cs

@ -0,0 +1,60 @@
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 AbpSystemTextJsonUnsupportedTypeMatcher _unsupportedTypeMatcher;
private readonly IOptions<JsonOptions> _jsonOptions;
private readonly ILoggerFactory _loggerFactory;
public AbpSystemTextJsonFormatter(AbpSystemTextJsonUnsupportedTypeMatcher unsupportedTypeMatcher,
IOptions<JsonOptions> jsonOptions,
ILoggerFactory loggerFactory)
{
_unsupportedTypeMatcher = unsupportedTypeMatcher;
_jsonOptions = jsonOptions;
_loggerFactory = loggerFactory;
}
Task<bool> IAbpHybridJsonInputFormatter.CanHandleAsync(Type type)
{
return Task.FromResult(!_unsupportedTypeMatcher.Match(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(!_unsupportedTypeMatcher.Match(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));
}
}

12
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/IAbpHybridJsonInputFormatter.cs

@ -0,0 +1,12 @@
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();
}

12
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/IAbpHybridJsonOutputFormatter.cs

@ -0,0 +1,12 @@
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();
}

28
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs

@ -1,9 +1,8 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.ObjectPool;
using Volo.Abp.Json;
namespace Volo.Abp.AspNetCore.Mvc.Json;
@ -11,18 +10,23 @@ public static class MvcCoreBuilderExtensions
{
public static IMvcCoreBuilder AddAbpHybridJson(this IMvcCoreBuilder builder)
{
var abpJsonOptions = builder.Services.ExecutePreConfiguredActions<AbpJsonOptions>();
if (!abpJsonOptions.UseHybridSerializer)
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<JsonOptions>, AbpJsonOptionsSetup>());
builder.Services.Configure<MvcOptions>(options =>
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<MvcNewtonsoftJsonOptions>, AbpMvcNewtonsoftJsonOptionsSetup>());
builder.AddNewtonsoftJson();
return builder;
}
options.InputFormatters.RemoveType<SystemTextJsonInputFormatter>();
options.InputFormatters.Add(new AbpHybridJsonInputFormatter());
options.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>();
options.OutputFormatters.Add(new AbpHybridJsonOutputFormatter());
});
builder.Services.Configure<AbpHybridJsonFormatterOptions>(options =>
{
options.TextInputFormatters.Add<AbpSystemTextJsonFormatter>();
options.TextOutputFormatters.Add<AbpSystemTextJsonFormatter>();
});
builder.Services.TryAddTransient<DefaultObjectPoolProvider>();
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<JsonOptions>, AbpJsonOptionsSetup>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<MvcNewtonsoftJsonOptions>, AbpMvcNewtonsoftJsonOptionsSetup>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, AbpHybridJsonOptionsSetup>());
return builder;
}
}

7
framework/src/Volo.Abp.Json.Core/Volo/Abp/Json/AbpJsonOptions.cs

@ -9,17 +9,10 @@ public class AbpJsonOptions
/// </summary>
public string DefaultDateTimeFormat { get; set; }
/// <summary>
/// It will try to use System.Json.Text to handle JSON if it can otherwise use Newtonsoft.
/// Affects both AbpJsonModule and AbpAspNetCoreMvcModule.
/// </summary>
public bool UseHybridSerializer { get; set; }
public ITypeList<IJsonSerializerProvider> Providers { get; }
public AbpJsonOptions()
{
Providers = new TypeList<IJsonSerializerProvider>();
UseHybridSerializer = true;
}
}

9
framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs

@ -11,16 +11,11 @@ public class AbpJsonSystemTextJsonModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.TryAddEnumerable(ServiceDescriptor
.Transient<IConfigureOptions<AbpSystemTextJsonSerializerOptions>, AbpSystemTextJsonSerializerOptionsSetup>());
context.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<AbpSystemTextJsonSerializerOptions>, AbpSystemTextJsonSerializerOptionsSetup>());
var preActions = context.Services.GetPreConfigureActions<AbpJsonOptions>();
Configure<AbpJsonOptions>(options =>
{
if (preActions.Configure().UseHybridSerializer)
{
options.Providers.Add<AbpSystemTextJsonSerializerProvider>();
}
options.Providers.Add<AbpSystemTextJsonSerializerProvider>();
});
}
}

2
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj

@ -25,7 +25,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.AspNetCore.Mvc.UI\Volo.Abp.AspNetCore.Mvc.UI.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.AspNetCore.Mvc\Volo.Abp.AspNetCore.Mvc.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.AspNetCore.Mvc.NewtonsoftJson\Volo.Abp.AspNetCore.Mvc.NewtonsoftJson.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\Volo.Abp.AspNetCore.Tests\Volo.Abp.AspNetCore.Tests.csproj" />
<ProjectReference Include="..\Volo.Abp.MemoryDb.Tests\Volo.Abp.MemoryDb.Tests.csproj" />

3
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs

@ -11,6 +11,7 @@ using Volo.Abp.AspNetCore.Mvc.Authorization;
using Volo.Abp.AspNetCore.Mvc.GlobalFeatures;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.Localization.Resource;
using Volo.Abp.AspNetCore.Mvc.NewtonsoftJson;
using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.AspNetCore.TestBase;
using Volo.Abp.Authorization;
@ -29,7 +30,7 @@ namespace Volo.Abp.AspNetCore.Mvc;
[DependsOn(
typeof(AbpAspNetCoreTestBaseModule),
typeof(AbpMemoryDbTestModule),
typeof(AbpAspNetCoreMvcModule),
typeof(AbpAspNetCoreMvcNewtonsoftModule),
typeof(AbpAutofacModule)
)]
public class AbpAspNetCoreMvcTestModule : AbpModule

1
nupkg/common.ps1

@ -112,6 +112,7 @@ $projects = (
"framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common",
"framework/src/Volo.Abp.AspNetCore.Mvc.Contracts",
"framework/src/Volo.Abp.AspNetCore.Mvc",
"framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling",

Loading…
Cancel
Save