diff --git a/docs/en/JSON.md b/docs/en/JSON.md index 29e93007af8..283690c2e1a 100644 --- a/docs/en/JSON.md +++ b/docs/en/JSON.md @@ -4,7 +4,7 @@ The ABP Framework provides an abstraction to work with JSON. Having such an abst * You can write library independent code. Therefore, you can change the underlying library with the minimum effort and code change. * You can use the predefined converters defined in the ABP without worrying about the underlying library's internal details. -> The JSON serialization system is implemented with the [Volo.Abp.Json](https://www.nuget.org/packages/Volo.Abp.Json) NuGet package. Most of the time, you don't need to manually [install it](https://abp.io/package-detail/Volo.Abp.Json) since it comes pre-installed with the [application startup template](Startup-Templates/Application.md). +> The JSON serialization system is implemented with the [Volo.Abp.Json](https://www.nuget.org/packages/Volo.Abp.Json) NuGet package([Volo.Abp.Json.SystemTextJson](https://www.nuget.org/packages/Volo.Abp.Json.SystemTextJson) is the default implementation). Most of the time, you don't need to manually [install it](https://abp.io/package-detail/Volo.Abp.Json) since it comes pre-installed with the [application startup template](Startup-Templates/Application.md). ## IJsonSerializer @@ -45,16 +45,24 @@ public class ProductManager `AbpJsonOptions` type provides options for the JSON operations in the ABP Framework. Properties: -* **DefaultDateTimeFormat(`string`)**: Default `DateTime` format. -* **UseHybridSerializer(`bool`)**: True by default. Boolean field indicating whether the ABP Framework uses the hybrid approach or not. If the field is true, it will try to use `System.Json.Text` to handle JSON if it can otherwise use the `Newtonsoft.Json.` -* **Providers(`ITypeList`)**: List of JSON serializer providers implementing the `IJsonSerializerProvider` interface. You can create and add custom serializers to the list, and the ABP Framework uses them automatically. When the `Serialize` or `Deserialize` method is called on the `IJsonSerializer` interface, the ABP Framework calls the `CanHandle` methods of the given providers in reverse order and uses the first provider that returns `true` to do the JSON operation. +* **InputDateTimeFormats(`List`)**: Formats of input JSON date, Empty string means default format. You can provide multiple formats to parse the date. +* **OutputDateTimeFormat(`string`)**: Format of output json date, Null or empty string means default format. + +## System Text Json ### AbpSystemTextJsonSerializerOptions -`AbpSystemTextJsonSerializerOptions` provides options for `System.Text.Json` usage. +- **JsonSerializerOptions(`System.Text.Json.JsonSerializerOptions`)**: Global options for System.Text.Json library operations. See [here](https://docs.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions) for reference. -Properties: +### AbpSystemTextJsonSerializerModifiersOptions -- **JsonSerializerOptions(`System.Text.Json.JsonSerializerOptions`)**: Global options for System.Text.Json library operations. See [here](https://docs.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions) for reference. -- **UnsupportedTypes(`ITypeList`)**: List of the unsupported types. You can add types of the unsupported types to the list and, the hybrid JSON serializer automatically uses the `Newtonsoft.Json` library instead of `System.Text.Json`. +- **Modifiers(`List>`)**: Configure `Modifiers` of `DefaultJsonTypeInfoResolver`. See [here](https://devblogs.microsoft.com/dotnet/announcing-dotnet-7-preview-6/#json-contract-customization) for reference. + + +## Newtonsoft + +Add [Volo.Abp.Json.Newtonsoft](https://www.nuget.org/packages/Volo.Abp.Json.Newtonsoft) packge and depends on `AbpJsonNewtonsoftModule` to replace the `System Text Json`. + +#### AbpNewtonsoftJsonSerializerOptions +- **JsonSerializerSettings(`Newtonsoft.Json.JsonSerializerSettings`)**: Global options for Newtonsoft library operations. See [here](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonSerializerSettings.htm) for reference. diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 4ce47bdbc84..771d59dbd06 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -409,6 +409,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.RemoteServices", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.PlugIn", "test\Volo.Abp.AspNetCore.Mvc.PlugIn\Volo.Abp.AspNetCore.Mvc.PlugIn.csproj", "{C6D6D878-208A-4FD2-822E-365545D8681B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Json.Newtonsoft", "src\Volo.Abp.Json.Newtonsoft\Volo.Abp.Json.Newtonsoft.csproj", "{9DD41C8F-0886-483C-B98B-C55EAA7F226D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Json.SystemTextJson", "src\Volo.Abp.Json.SystemTextJson\Volo.Abp.Json.SystemTextJson.csproj", "{0AD06E14-CBFE-4551-8D18-9E921D8F2A87}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Json.Abstractions", "src\Volo.Abp.Json.Abstractions\Volo.Abp.Json.Abstractions.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 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Dapr", "src\Volo.Abp.Dapr\Volo.Abp.Dapr.csproj", "{192A829F-D608-4E41-8DE0-058E943E453F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EventBus.Dapr", "src\Volo.Abp.EventBus.Dapr\Volo.Abp.EventBus.Dapr.csproj", "{DCC41E99-EBC7-4F19-BA0D-A6F770D8E431}" @@ -1231,6 +1239,22 @@ Global {C6D6D878-208A-4FD2-822E-365545D8681B}.Debug|Any CPU.Build.0 = Debug|Any CPU {C6D6D878-208A-4FD2-822E-365545D8681B}.Release|Any CPU.ActiveCfg = Release|Any CPU {C6D6D878-208A-4FD2-822E-365545D8681B}.Release|Any CPU.Build.0 = Release|Any CPU + {9DD41C8F-0886-483C-B98B-C55EAA7F226D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9DD41C8F-0886-483C-B98B-C55EAA7F226D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9DD41C8F-0886-483C-B98B-C55EAA7F226D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9DD41C8F-0886-483C-B98B-C55EAA7F226D}.Release|Any CPU.Build.0 = Release|Any CPU + {0AD06E14-CBFE-4551-8D18-9E921D8F2A87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0AD06E14-CBFE-4551-8D18-9E921D8F2A87}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0AD06E14-CBFE-4551-8D18-9E921D8F2A87}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0AD06E14-CBFE-4551-8D18-9E921D8F2A87}.Release|Any CPU.Build.0 = Release|Any CPU + {08531C5D-0436-4721-986D-96446CF54316}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {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 {192A829F-D608-4E41-8DE0-058E943E453F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {192A829F-D608-4E41-8DE0-058E943E453F}.Debug|Any CPU.Build.0 = Debug|Any CPU {192A829F-D608-4E41-8DE0-058E943E453F}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -1461,6 +1485,10 @@ Global {3683340D-92F5-4B14-B77B-34A163333309} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {EDFFDA74-090D-439C-A58D-06CCF86D4423} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {C6D6D878-208A-4FD2-822E-365545D8681B} = {447C8A77-E5F0-4538-8687-7383196D04EA} + {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} {192A829F-D608-4E41-8DE0-058E943E453F} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {DCC41E99-EBC7-4F19-BA0D-A6F770D8E431} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {18B796D2-D45D-41AE-9A42-75C9B14B20DF} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/FodyWeavers.xml b/framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/FodyWeavers.xml new file mode 100644 index 00000000000..bc5a74a236f --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/FodyWeavers.xsd b/framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/FodyWeavers.xsd new file mode 100644 index 00000000000..3f3946e282d --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson.csproj new file mode 100644 index 00000000000..026fb2f4d4f --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson.csproj @@ -0,0 +1,29 @@ + + + + + + + net7.0 + true + Volo.Abp.AspNetCore.Mvc.NewtonsoftJson + Volo.Abp.AspNetCore.Mvc.NewtonsoftJson + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + true + Library + + + + + + + + + + + + + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpAspNetCoreMvcNewtonsoftModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpAspNetCoreMvcNewtonsoftModule.cs new file mode 100644 index 00000000000..6e71fe7b5f9 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpAspNetCoreMvcNewtonsoftModule.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Json.Newtonsoft; +using Volo.Abp.Modularity; + +namespace Volo.Abp.AspNetCore.Mvc.NewtonsoftJson; + +[DependsOn(typeof(AbpJsonNewtonsoftModule), typeof(AbpAspNetCoreMvcModule))] +public class AbpAspNetCoreMvcNewtonsoftModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddMvcCore().AddNewtonsoftJson(); + + context.Services.AddOptions() + .Configure((options, contractResolver) => + { + options.SerializerSettings.ContractResolver = contractResolver; + }); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj index 46baa07c191..37b98229661 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj @@ -29,7 +29,6 @@ - diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs index 22b919c91ca..ec3690ca8e5 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs @@ -38,6 +38,7 @@ using Volo.Abp.Http.Modeling; using Volo.Abp.Http.ProxyScripting.Generators.JQuery; using Volo.Abp.Json; +using Volo.Abp.Json.SystemTextJson; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.UI; @@ -52,7 +53,8 @@ namespace Volo.Abp.AspNetCore.Mvc; typeof(AbpAspNetCoreMvcContractsModule), typeof(AbpUiNavigationModule), typeof(AbpGlobalFeaturesModule), - typeof(AbpDddApplicationModule) + typeof(AbpDddApplicationModule), + typeof(AbpJsonSystemTextJsonModule) )] public class AbpAspNetCoreMvcModule : AbpModule { @@ -145,7 +147,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) mvcCoreBuilder.AddAbpRazorRuntimeCompilation(); } - mvcCoreBuilder.AddAbpHybridJson(); + mvcCoreBuilder.AddAbpJson(); context.Services.ExecutePreConfiguredActions(mvcBuilder); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProviderOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProviderOptions.cs index 2b9e231874a..4dc4a9719a7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProviderOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProviderOptions.cs @@ -62,19 +62,12 @@ public AspNetCoreApiDescriptionModelProviderOptions() { if (apiParameterDescription.ModelMetadata is DefaultModelMetadata defaultModelMetadata) { - var jsonPropertyNameAttribute = (System.Text.Json.Serialization.JsonPropertyNameAttribute) - defaultModelMetadata?.Attributes?.PropertyAttributes?.FirstOrDefault(x => x is System.Text.Json.Serialization.JsonPropertyNameAttribute); + var jsonPropertyNameAttribute = (JsonPropertyNameAttribute) + defaultModelMetadata?.Attributes?.PropertyAttributes?.FirstOrDefault(x => x is JsonPropertyNameAttribute); if (jsonPropertyNameAttribute != null) { return jsonPropertyNameAttribute.Name; } - - var jsonPropertyAttribute = (Newtonsoft.Json.JsonPropertyAttribute) - defaultModelMetadata?.Attributes?.PropertyAttributes?.FirstOrDefault(x => x is Newtonsoft.Json.JsonPropertyAttribute); - if (jsonPropertyAttribute != null) - { - return jsonPropertyAttribute.PropertyName; - } } return null; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs deleted file mode 100644 index 69da26a317b..00000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs +++ /dev/null @@ -1,45 +0,0 @@ -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 -{ - private readonly SystemTextJsonInputFormatter _systemTextJsonInputFormatter; - private readonly NewtonsoftJsonInputFormatter _newtonsoftJsonInputFormatter; - - public AbpHybridJsonInputFormatter(SystemTextJsonInputFormatter systemTextJsonInputFormatter, NewtonsoftJsonInputFormatter newtonsoftJsonInputFormatter) - { - _systemTextJsonInputFormatter = systemTextJsonInputFormatter; - _newtonsoftJsonInputFormatter = newtonsoftJsonInputFormatter; - - SupportedEncodings.Add(UTF8EncodingWithoutBOM); - SupportedEncodings.Add(UTF16EncodingLittleEndian); - - SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJson); - SupportedMediaTypes.Add(MediaTypeHeaderValues.TextJson); - SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax); - } - - public override async Task ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding) - { - return await GetTextInputFormatter(context).ReadRequestBodyAsync(context, encoding); - } - - protected virtual TextInputFormatter GetTextInputFormatter(InputFormatterContext context) - { - var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); - - if (!typesMatcher.Match(context.ModelType)) - { - return _systemTextJsonInputFormatter; - } - - return _newtonsoftJsonInputFormatter; - } - - public virtual InputFormatterExceptionPolicy ExceptionPolicy => InputFormatterExceptionPolicy.MalformedInputExceptions; -} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOptionsSetup.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOptionsSetup.cs deleted file mode 100644 index 794bc79af90..00000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOptionsSetup.cs +++ /dev/null @@ -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 -{ - private readonly IOptions _jsonOptions; - private readonly IOptions _mvcNewtonsoftJsonOptions; - private readonly ILoggerFactory _loggerFactory; - private readonly ArrayPool _charPool; - private readonly ObjectPoolProvider _objectPoolProvider; - - public AbpHybridJsonOptionsSetup( - IOptions jsonOptions, - IOptions mvcNewtonsoftJsonOptions, - ILoggerFactory loggerFactory, - ArrayPool 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()); - - var newtonsoftJsonInputFormatter = new NewtonsoftJsonInputFormatter( - _loggerFactory.CreateLogger(), - _mvcNewtonsoftJsonOptions.Value.SerializerSettings, - _charPool, - _objectPoolProvider, - options, - _mvcNewtonsoftJsonOptions.Value); - - options.InputFormatters.RemoveType(); - options.InputFormatters.RemoveType(); - 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(); - options.OutputFormatters.RemoveType(); - options.OutputFormatters.Add(new AbpHybridJsonOutputFormatter(systemTextJsonOutputFormatter, newtonsoftJsonOutputFormatter)); - } -} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs deleted file mode 100644 index f4c5df1dc93..00000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs +++ /dev/null @@ -1,42 +0,0 @@ -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 -{ - private readonly SystemTextJsonOutputFormatter _systemTextJsonOutputFormatter; - private readonly NewtonsoftJsonOutputFormatter _newtonsoftJsonOutputFormatter; - - public AbpHybridJsonOutputFormatter(SystemTextJsonOutputFormatter systemTextJsonOutputFormatter, NewtonsoftJsonOutputFormatter newtonsoftJsonOutputFormatter) - { - _systemTextJsonOutputFormatter = systemTextJsonOutputFormatter; - _newtonsoftJsonOutputFormatter = newtonsoftJsonOutputFormatter; - - SupportedEncodings.Add(Encoding.UTF8); - SupportedEncodings.Add(Encoding.Unicode); - - SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJson); - SupportedMediaTypes.Add(MediaTypeHeaderValues.TextJson); - SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax); - } - - public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) - { - await GetTextInputFormatter(context).WriteResponseBodyAsync(context, selectedEncoding); - } - - protected virtual TextOutputFormatter GetTextInputFormatter(OutputFormatterWriteContext context) - { - var typesMatcher = context.HttpContext.RequestServices.GetRequiredService(); - if (!typesMatcher.Match(context.ObjectType)) - { - return _systemTextJsonOutputFormatter; - } - - return _newtonsoftJsonOutputFormatter; - } -} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs deleted file mode 100644 index 116adca4e88..00000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Text.Json; -using System.Text.Json.Serialization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Volo.Abp.Json.SystemTextJson.JsonConverters; - -namespace Volo.Abp.AspNetCore.Mvc.Json; - -public class AbpJsonOptionsSetup : IConfigureOptions -{ - protected IServiceProvider ServiceProvider { get; } - - public AbpJsonOptionsSetup(IServiceProvider serviceProvider) - { - ServiceProvider = serviceProvider; - } - - public void Configure(JsonOptions options) - { - options.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip; - options.JsonSerializerOptions.AllowTrailingCommas = true; - - options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService()); - options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService()); - - options.JsonSerializerOptions.Converters.Add(new AbpStringToEnumFactory()); - options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter()); - - options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter()); - } -} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs deleted file mode 100644 index a6f242d59ca..00000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Reflection; -using Microsoft.Extensions.DependencyInjection; -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 Lazy _dateTimeConverter; - - public AbpMvcJsonContractResolver(IServiceProvider serviceProvider) - { - _dateTimeConverter = new Lazy( - serviceProvider.GetRequiredService, - true - ); - - 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(member) == null) - { - property.Converter = _dateTimeConverter.Value; - } - } -} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcNewtonsoftJsonOptionsSetup.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcNewtonsoftJsonOptionsSetup.cs deleted file mode 100644 index c68b912372b..00000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcNewtonsoftJsonOptionsSetup.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; - -namespace Volo.Abp.AspNetCore.Mvc.Json; - -public class AbpMvcNewtonsoftJsonOptionsSetup : IConfigureOptions -{ - protected IServiceProvider ServiceProvider { get; } - - public AbpMvcNewtonsoftJsonOptionsSetup(IServiceProvider serviceProvider) - { - ServiceProvider = serviceProvider; - } - - public void Configure(MvcNewtonsoftJsonOptions options) - { - options.SerializerSettings.ContractResolver = ServiceProvider.GetRequiredService(); - } -} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MediaTypeHeaderValues.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MediaTypeHeaderValues.cs deleted file mode 100644 index 23d039ef30c..00000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MediaTypeHeaderValues.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Microsoft.Net.Http.Headers; - -namespace Volo.Abp.AspNetCore.Mvc.Json; - -/// -/// https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.NewtonsoftJson/src/MediaTypeHeaderValues.cs -/// -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(); -} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs index 2d3a834d092..9777265abd8 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs @@ -1,28 +1,31 @@ -using Microsoft.AspNetCore.Mvc; +using System; +using System.Text.Json; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; -using Microsoft.Extensions.ObjectPool; -using Volo.Abp.Json; +using Volo.Abp.Json.SystemTextJson; +using Volo.Abp.Json.SystemTextJson.JsonConverters; namespace Volo.Abp.AspNetCore.Mvc.Json; public static class MvcCoreBuilderExtensions { - public static IMvcCoreBuilder AddAbpHybridJson(this IMvcCoreBuilder builder) + public static IMvcCoreBuilder AddAbpJson(this IMvcCoreBuilder builder) { - var abpJsonOptions = builder.Services.ExecutePreConfiguredActions(); - if (!abpJsonOptions.UseHybridSerializer) - { - builder.Services.TryAddEnumerable(ServiceDescriptor.Transient, AbpMvcNewtonsoftJsonOptionsSetup>()); - builder.AddNewtonsoftJson(); - return builder; - } + builder.Services.AddOptions() + .Configure((options, serviceProvider) => + { + options.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip; + options.JsonSerializerOptions.AllowTrailingCommas = true; + + options.JsonSerializerOptions.Converters.Add(new AbpStringToEnumFactory()); + options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter()); + options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter()); + + options.JsonSerializerOptions.TypeInfoResolver = new AbpDefaultJsonTypeInfoResolver(serviceProvider + .GetRequiredService>()); + }); - builder.Services.TryAddTransient(); - builder.Services.TryAddEnumerable(ServiceDescriptor.Transient, AbpJsonOptionsSetup>()); - builder.Services.TryAddEnumerable(ServiceDescriptor.Transient, AbpMvcNewtonsoftJsonOptionsSetup>()); - builder.Services.TryAddEnumerable(ServiceDescriptor.Transient, AbpHybridJsonOptionsSetup>()); return builder; } } diff --git a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs index 20afedf680b..eb9504570c7 100644 --- a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs +++ b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs @@ -40,7 +40,7 @@ protected virtual IHostBuilder CreateHostBuilder() .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); - webBuilder.UseTestServer(); + webBuilder.UseAbpTestServer(); }) .UseAutofac() .ConfigureServices(ConfigureServices); diff --git a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpNoopHostLifetime.cs b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpNoopHostLifetime.cs new file mode 100644 index 00000000000..c20cf0db3a7 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpNoopHostLifetime.cs @@ -0,0 +1,18 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; + +namespace Volo.Abp.AspNetCore.TestBase; + +public class AbpNoopHostLifetime : IHostLifetime +{ + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + public Task WaitForStartAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/WebHostBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/WebHostBuilderExtensions.cs new file mode 100644 index 00000000000..288f6ad5699 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/WebHostBuilderExtensions.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace Volo.Abp.AspNetCore.TestBase; + +public static class AbpWebHostBuilderExtensions +{ + public static IWebHostBuilder UseAbpTestServer(this IWebHostBuilder builder) + { + return builder.ConfigureServices(services => + { + services.AddScoped(); + services.AddScoped(); + }); + } +} diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingContractResolver.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingContractResolver.cs deleted file mode 100644 index 77d1b7ddb93..00000000000 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingContractResolver.cs +++ /dev/null @@ -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 _ignoredTypes; - - public AuditingContractResolver(List 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; - } -} diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonAuditSerializer.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonAuditSerializer.cs new file mode 100644 index 00000000000..5f64c58eedd --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonAuditSerializer.cs @@ -0,0 +1,77 @@ +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 options) + { + Options = options.Value; + } + + public string Serialize(object obj) + { + return JsonSerializer.Serialize(obj, CreateJsonSerializerOptions()); + } + + private static readonly ConcurrentDictionary JsonSerializerOptionsCache = + new ConcurrentDictionary(); + + 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.Type.GetCustomAttributes(typeof(DisableAuditingAttribute), false).Any()) + { + if (jsonTypeInfo.Kind == JsonTypeInfoKind.Object) + { + 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; + }); + } +} diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs deleted file mode 100644 index d5df2b2644f..00000000000 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs +++ /dev/null @@ -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 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; - } -} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj b/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj index 5c83874fa0d..1688a4246f9 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj +++ b/framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj @@ -30,5 +30,6 @@ + diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs index fefa8552b32..bf2bd71fc04 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs @@ -2,17 +2,14 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Cli.Commands; using Volo.Abp.Cli.Http; -using Volo.Abp.Cli.LIbs; using Volo.Abp.Cli.ServiceProxying; using Volo.Abp.Cli.ServiceProxying.Angular; using Volo.Abp.Cli.ServiceProxying.CSharp; using Volo.Abp.Cli.ServiceProxying.JavaScript; using Volo.Abp.Domain; using Volo.Abp.Http; -using Volo.Abp.Http.ProxyScripting.Generators.JQuery; using Volo.Abp.IdentityModel; using Volo.Abp.Json; -using Volo.Abp.Json.SystemTextJson; using Volo.Abp.Minify; using Volo.Abp.Modularity; @@ -34,11 +31,6 @@ public override void ConfigureServices(ServiceConfigurationContext context) Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - Configure(options => - { - options.UnsupportedTypes.Add(typeof(ResourceMapping)); - }); - Configure(options => { options.Commands[HelpCommand.Name] = typeof(HelpCommand); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/LIbs/InstallLibsService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/LIbs/InstallLibsService.cs index 654feb117b0..b925a4220c1 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/LIbs/InstallLibsService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/LIbs/InstallLibsService.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.FileSystemGlobbing.Abstractions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Newtonsoft.Json; using NuGet.Versioning; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; @@ -30,12 +31,9 @@ public class InstallLibsService : IInstallLibsService, ITransientDependency public ILogger Logger { get; set; } - private readonly IJsonSerializer _jsonSerializer; - - public InstallLibsService(IJsonSerializer jsonSerializer, NpmHelper npmHelper) + public InstallLibsService(NpmHelper npmHelper) { NpmHelper = npmHelper; - _jsonSerializer = jsonSerializer; } public async Task InstallLibsAsync(string directory) @@ -119,7 +117,7 @@ private List FindAllProjects(string directory) { return false; } - + using (var reader = File.OpenText(file)) { return reader.ReadToEnd().Contains("Microsoft.NET.Sdk.Web"); @@ -145,7 +143,8 @@ private async Task CleanAndCopyResources(string fileDirectory) { var mappingFileContent = await reader.ReadToEndAsync(); - var mapping = _jsonSerializer.Deserialize(mappingFileContent + // System.Text.Json doesn't support the property name without quotes. + var mapping = Newtonsoft.Json.JsonConvert.DeserializeObject(mappingFileContent .Replace("module.exports", string.Empty) .Replace("=", string.Empty).Trim().TrimEnd(';')); diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingConfiguration.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingConfiguration.cs index e8da5693f60..86449c89719 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingConfiguration.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingConfiguration.cs @@ -10,22 +10,6 @@ public static class AbpApiProxyScriptingConfiguration static AbpApiProxyScriptingConfiguration() { PropertyNameGenerator = propertyInfo => - { - var jsonPropertyNameAttribute = propertyInfo.GetSingleAttributeOrNull(true); - - if (jsonPropertyNameAttribute != null) - { - return jsonPropertyNameAttribute.Name; - } - - var jsonPropertyAttribute = propertyInfo.GetSingleAttributeOrNull(true); - - if (jsonPropertyAttribute != null) - { - return jsonPropertyAttribute.PropertyName; - } - - return null; - }; + propertyInfo.GetSingleAttributeOrNull()?.Name; } } diff --git a/framework/src/Volo.Abp.Json.Abstractions/FodyWeavers.xml b/framework/src/Volo.Abp.Json.Abstractions/FodyWeavers.xml new file mode 100644 index 00000000000..bc5a74a236f --- /dev/null +++ b/framework/src/Volo.Abp.Json.Abstractions/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + diff --git a/framework/src/Volo.Abp.Json.Abstractions/FodyWeavers.xsd b/framework/src/Volo.Abp.Json.Abstractions/FodyWeavers.xsd new file mode 100644 index 00000000000..3f3946e282d --- /dev/null +++ b/framework/src/Volo.Abp.Json.Abstractions/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Json.Abstractions/Volo.Abp.Json.Abstractions.csproj b/framework/src/Volo.Abp.Json.Abstractions/Volo.Abp.Json.Abstractions.csproj new file mode 100644 index 00000000000..15130c129ce --- /dev/null +++ b/framework/src/Volo.Abp.Json.Abstractions/Volo.Abp.Json.Abstractions.csproj @@ -0,0 +1,20 @@ + + + + + + + netstandard2.0 + Volo.Abp.Json.Abstractions + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + diff --git a/framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/AbpJsonAbstractionsModule.cs b/framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/AbpJsonAbstractionsModule.cs new file mode 100644 index 00000000000..422d34745da --- /dev/null +++ b/framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/AbpJsonAbstractionsModule.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Modularity; + +namespace Volo.Abp.Json; + +public class AbpJsonAbstractionsModule : AbpModule +{ + +} diff --git a/framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/AbpJsonOptions.cs b/framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/AbpJsonOptions.cs new file mode 100644 index 00000000000..043c1081d71 --- /dev/null +++ b/framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/AbpJsonOptions.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Json; + +public class AbpJsonOptions +{ + /// + /// Formats of input JSON date, Empty string means default format. + /// + public List InputDateTimeFormats { get; set; } + + /// + /// Format of output json date, Null or empty string means default format. + /// + public string OutputDateTimeFormat { get; set; } + + public AbpJsonOptions() + { + InputDateTimeFormats = new List(); + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/IJsonSerializer.cs b/framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/IJsonSerializer.cs similarity index 100% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/IJsonSerializer.cs rename to framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/IJsonSerializer.cs diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xml b/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xml new file mode 100644 index 00000000000..bc5a74a236f --- /dev/null +++ b/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd b/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd new file mode 100644 index 00000000000..3f3946e282d --- /dev/null +++ b/framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo.Abp.Json.Newtonsoft.csproj b/framework/src/Volo.Abp.Json.Newtonsoft/Volo.Abp.Json.Newtonsoft.csproj new file mode 100644 index 00000000000..6927cff0dbe --- /dev/null +++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo.Abp.Json.Newtonsoft.csproj @@ -0,0 +1,23 @@ + + + + + + + netstandard2.0 + Volo.Abp.Json.Newtonsoft + Volo.Abp.Json.Newtonsoft + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + + + diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpCamelCasePropertyNamesContractResolver.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpCamelCasePropertyNamesContractResolver.cs new file mode 100644 index 00000000000..3e4e5d01213 --- /dev/null +++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpCamelCasePropertyNamesContractResolver.cs @@ -0,0 +1,38 @@ +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 AbpCamelCasePropertyNamesContractResolver : CamelCasePropertyNamesContractResolver, ITransientDependency +{ + private readonly Lazy _dateTimeConverter; + + public AbpCamelCasePropertyNamesContractResolver(IServiceProvider serviceProvider) + { + _dateTimeConverter = new Lazy( + serviceProvider.GetRequiredService, + true + ); + + NamingStrategy = new CamelCaseNamingStrategy + { + ProcessDictionaryKeys = false + }; + } + + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + var property = base.CreateProperty(member, memberSerialization); + + if (AbpDateTimeConverter.ShouldNormalize(member, property)) + { + property.Converter = _dateTimeConverter.Value; + } + + return property; + } +} diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDateTimeConverter.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDateTimeConverter.cs new file mode 100644 index 00000000000..3bd97f7aee1 --- /dev/null +++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDateTimeConverter.cs @@ -0,0 +1,116 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Reflection; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; +using Volo.Abp.Reflection; +using Volo.Abp.Timing; + +namespace Volo.Abp.Json.Newtonsoft; + +public class AbpDateTimeConverter : DateTimeConverterBase +{ + private readonly string _dateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; + private readonly DateTimeStyles _dateTimeStyles = DateTimeStyles.RoundtripKind; + private readonly CultureInfo _culture = CultureInfo.InvariantCulture; + private readonly IClock _clock; + private readonly AbpJsonOptions _options; + + public AbpDateTimeConverter(IClock clock, IOptions options) + { + _clock = clock; + _options = options.Value; + } + + public override bool CanConvert(Type objectType) + { + return objectType == typeof(DateTime) || objectType == typeof(DateTime?); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var nullable = Nullable.GetUnderlyingType(objectType) != null; + if (reader.TokenType == JsonToken.Null) + { + if (!nullable) + { + throw new JsonSerializationException($"Cannot convert null value to {objectType.FullName}."); + } + + return null; + } + + if (reader.TokenType == JsonToken.Date) + { + return _clock.Normalize(reader.Value.To()); + } + + if (reader.TokenType != JsonToken.String) + { + throw new JsonSerializationException($"Unexpected token parsing date. Expected String, got {reader.TokenType}."); + } + + var dateText = reader.Value?.ToString(); + + if (dateText.IsNullOrEmpty() && nullable) + { + return null; + } + + if (_options.InputDateTimeFormats.Any()) + { + foreach (var format in _options.InputDateTimeFormats) + { + if (DateTime.TryParseExact(dateText, format, _culture, _dateTimeStyles, out var d1)) + { + return _clock.Normalize(d1); + } + } + } + + var date = !_dateTimeFormat.IsNullOrEmpty() ? + DateTime.ParseExact(dateText, _dateTimeFormat, _culture, _dateTimeStyles) : + DateTime.Parse(dateText, _culture, _dateTimeStyles); + + return _clock.Normalize(date); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value != null) + { + value = _clock.Normalize(value.To()); + } + + if (value is DateTime dateTime) + { + if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal || + (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal) + { + dateTime = dateTime.ToUniversalTime(); + } + + writer.WriteValue(_options.OutputDateTimeFormat.IsNullOrWhiteSpace() + ? dateTime.ToString(_dateTimeFormat, _culture) + : dateTime.ToString(_options.OutputDateTimeFormat, _culture)); + } + else + { + throw new JsonSerializationException($"Unexpected value when converting date. Expected DateTime or DateTimeOffset, got {value.GetType()}."); + } + } + + internal static bool ShouldNormalize(MemberInfo member, JsonProperty property) + { + if (property.PropertyType != typeof(DateTime) && + property.PropertyType != typeof(DateTime?)) + { + return false; + } + + return ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(member) == null; + } +} diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDefaultContractResolver.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDefaultContractResolver.cs new file mode 100644 index 00000000000..131e95d4c29 --- /dev/null +++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDefaultContractResolver.cs @@ -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 _dateTimeConverter; + + public AbpDefaultContractResolver(IServiceProvider serviceProvider) + { + _dateTimeConverter = new Lazy( + serviceProvider.GetRequiredService, + true + ); + } + + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + var property = base.CreateProperty(member, memberSerialization); + + if (AbpDateTimeConverter.ShouldNormalize(member, property)) + { + property.Converter = _dateTimeConverter.Value; + } + + return property; + } +} diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonNewtonsoftModule.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonNewtonsoftModule.cs new file mode 100644 index 00000000000..c1f1f3a0cf3 --- /dev/null +++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonNewtonsoftModule.cs @@ -0,0 +1,18 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; +using Volo.Abp.Timing; + +namespace Volo.Abp.Json.Newtonsoft; + +[DependsOn(typeof(AbpJsonAbstractionsModule), typeof(AbpTimingModule))] +public class AbpJsonNewtonsoftModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddOptions() + .Configure((options, contractResolver) => + { + options.JsonSerializerSettings.ContractResolver = contractResolver; + }); + } +} diff --git a/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializer.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializer.cs new file mode 100644 index 00000000000..36ba95e74c8 --- /dev/null +++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializer.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Concurrent; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Json.Newtonsoft; + +[Dependency(ReplaceServices = true)] +public class AbpNewtonsoftJsonSerializer : IJsonSerializer, ITransientDependency +{ + protected IServiceProvider ServiceProvider { get; } + protected IOptions Options { get; } + + public AbpNewtonsoftJsonSerializer(IServiceProvider serviceProvider, IOptions options) + { + ServiceProvider = serviceProvider; + Options = options; + } + + public string Serialize(object obj, bool camelCase = true, bool indented = false) + { + return JsonConvert.SerializeObject(obj, CreateJsonSerializerOptions(camelCase, indented)); + } + + public T Deserialize(string jsonString, bool camelCase = true) + { + return JsonConvert.DeserializeObject(jsonString, CreateJsonSerializerOptions(camelCase)); + } + + public object Deserialize(Type type, string jsonString, bool camelCase = true) + { + return JsonConvert.DeserializeObject(jsonString, type, CreateJsonSerializerOptions(camelCase)); + } + + private static readonly ConcurrentDictionary JsonSerializerOptionsCache = + new ConcurrentDictionary(); + + protected virtual JsonSerializerSettings CreateJsonSerializerOptions(bool camelCase = true, bool indented = false) + { + return JsonSerializerOptionsCache.GetOrAdd(new + { + camelCase, + indented + }, _ => + { + var settings = new JsonSerializerSettings + { + Binder = Options.Value.JsonSerializerSettings.Binder, + CheckAdditionalContent = Options.Value.JsonSerializerSettings.CheckAdditionalContent, + Context = Options.Value.JsonSerializerSettings.Context, + ContractResolver = Options.Value.JsonSerializerSettings.ContractResolver, + ConstructorHandling = Options.Value.JsonSerializerSettings.ConstructorHandling, + Converters = Options.Value.JsonSerializerSettings.Converters, + Culture = Options.Value.JsonSerializerSettings.Culture, + DateFormatHandling = Options.Value.JsonSerializerSettings.DateFormatHandling, + DateFormatString = Options.Value.JsonSerializerSettings.DateFormatString, + DateParseHandling = Options.Value.JsonSerializerSettings.DateParseHandling, + DateTimeZoneHandling = Options.Value.JsonSerializerSettings.DateTimeZoneHandling, + DefaultValueHandling = Options.Value.JsonSerializerSettings.DefaultValueHandling, + Error = Options.Value.JsonSerializerSettings.Error, + EqualityComparer = Options.Value.JsonSerializerSettings.EqualityComparer, + FloatFormatHandling = Options.Value.JsonSerializerSettings.FloatFormatHandling, + FloatParseHandling = Options.Value.JsonSerializerSettings.FloatParseHandling, + Formatting = Options.Value.JsonSerializerSettings.Formatting, + MaxDepth = Options.Value.JsonSerializerSettings.MaxDepth, + MetadataPropertyHandling = Options.Value.JsonSerializerSettings.MetadataPropertyHandling, + MissingMemberHandling = Options.Value.JsonSerializerSettings.MissingMemberHandling, + NullValueHandling = Options.Value.JsonSerializerSettings.NullValueHandling, + ObjectCreationHandling = Options.Value.JsonSerializerSettings.ObjectCreationHandling, + PreserveReferencesHandling = Options.Value.JsonSerializerSettings.PreserveReferencesHandling, + ReferenceLoopHandling = Options.Value.JsonSerializerSettings.ReferenceLoopHandling, + ReferenceResolver = Options.Value.JsonSerializerSettings.ReferenceResolver, + ReferenceResolverProvider = Options.Value.JsonSerializerSettings.ReferenceResolverProvider, + SerializationBinder = Options.Value.JsonSerializerSettings.SerializationBinder, + StringEscapeHandling = Options.Value.JsonSerializerSettings.StringEscapeHandling, + TraceWriter = Options.Value.JsonSerializerSettings.TraceWriter, + TypeNameAssemblyFormat = Options.Value.JsonSerializerSettings.TypeNameAssemblyFormat, + TypeNameHandling = Options.Value.JsonSerializerSettings.TypeNameHandling, + TypeNameAssemblyFormatHandling = Options.Value.JsonSerializerSettings.TypeNameAssemblyFormatHandling + }; + + settings.ContractResolver = camelCase + ? ServiceProvider.GetRequiredService() + : ServiceProvider.GetRequiredService(); + + if (indented) + { + settings.Formatting = Formatting.Indented; + } + + return settings; + }); + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs similarity index 56% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs rename to framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs index d4e392cf80c..e5da4ac83f9 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs +++ b/framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs @@ -1,14 +1,13 @@ using Newtonsoft.Json; -using Volo.Abp.Collections; namespace Volo.Abp.Json.Newtonsoft; public class AbpNewtonsoftJsonSerializerOptions { - public ITypeList Converters { get; } + public JsonSerializerSettings JsonSerializerSettings { get; } public AbpNewtonsoftJsonSerializerOptions() { - Converters = new TypeList(); + JsonSerializerSettings = new JsonSerializerSettings(); } } diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/FodyWeavers.xml b/framework/src/Volo.Abp.Json.SystemTextJson/FodyWeavers.xml new file mode 100644 index 00000000000..bc5a74a236f --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/FodyWeavers.xsd b/framework/src/Volo.Abp.Json.SystemTextJson/FodyWeavers.xsd new file mode 100644 index 00000000000..3f3946e282d --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo.Abp.Json.SystemTextJson.csproj b/framework/src/Volo.Abp.Json.SystemTextJson/Volo.Abp.Json.SystemTextJson.csproj new file mode 100644 index 00000000000..b3aba746a3e --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo.Abp.Json.SystemTextJson.csproj @@ -0,0 +1,23 @@ + + + + + + + netstandard2.0 + Volo.Abp.Json.SystemTextJson + Volo.Abp.Json.SystemTextJson + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + + + diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpDefaultJsonTypeInfoResolver.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpDefaultJsonTypeInfoResolver.cs new file mode 100644 index 00000000000..385544dc0b8 --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpDefaultJsonTypeInfoResolver.cs @@ -0,0 +1,16 @@ +using System.Text.Json.Serialization.Metadata; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Json.SystemTextJson; + +public class AbpDefaultJsonTypeInfoResolver : DefaultJsonTypeInfoResolver, ITransientDependency +{ + public AbpDefaultJsonTypeInfoResolver(IOptions options) + { + foreach (var modifier in options.Value.Modifiers) + { + Modifiers.Add(modifier); + } + } +} diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs new file mode 100644 index 00000000000..50dd47d9e22 --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs @@ -0,0 +1,37 @@ +using System; +using System.Text.Encodings.Web; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.Json.SystemTextJson.JsonConverters; +using Volo.Abp.Json.SystemTextJson.Modifiers; +using Volo.Abp.Modularity; +using Volo.Abp.Timing; + +namespace Volo.Abp.Json.SystemTextJson; + +[DependsOn(typeof(AbpJsonAbstractionsModule), typeof(AbpTimingModule))] +public class AbpJsonSystemTextJsonModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddOptions() + .Configure((options, serviceProvider) => + { + // If the user hasn't explicitly configured the encoder, use the less strict encoder that does not encode all non-ASCII characters. + options.JsonSerializerOptions.Encoder ??= JavaScriptEncoder.UnsafeRelaxedJsonEscaping; + + options.JsonSerializerOptions.Converters.Add(new AbpStringToEnumFactory()); + options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter()); + options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter()); + + options.JsonSerializerOptions.TypeInfoResolver = new AbpDefaultJsonTypeInfoResolver(serviceProvider + .GetRequiredService>()); + }); + + context.Services.AddOptions() + .Configure((options, serviceProvider) => + { + options.Modifiers.Add(new AbpDateTimeConverterModifier().CreateModifyAction(serviceProvider)); + }); + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializer.cs similarity index 66% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs rename to framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializer.cs index 802dd3f5287..8313f6ee999 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializer.cs @@ -6,25 +6,15 @@ namespace Volo.Abp.Json.SystemTextJson; -public class AbpSystemTextJsonSerializerProvider : IJsonSerializerProvider, ITransientDependency +public class AbpSystemTextJsonSerializer : IJsonSerializer, ITransientDependency { protected AbpSystemTextJsonSerializerOptions Options { get; } - protected AbpSystemTextJsonUnsupportedTypeMatcher AbpSystemTextJsonUnsupportedTypeMatcher { get; } - - public AbpSystemTextJsonSerializerProvider( - IOptions options, - AbpSystemTextJsonUnsupportedTypeMatcher abpSystemTextJsonUnsupportedTypeMatcher) + public AbpSystemTextJsonSerializer(IOptions options) { - AbpSystemTextJsonUnsupportedTypeMatcher = abpSystemTextJsonUnsupportedTypeMatcher; Options = options.Value; } - public bool CanHandle(Type type) - { - return !AbpSystemTextJsonUnsupportedTypeMatcher.Match(type); - } - public string Serialize(object obj, bool camelCase = true, bool indented = false) { return JsonSerializer.Serialize(obj, CreateJsonSerializerOptions(camelCase, indented)); @@ -40,7 +30,8 @@ public object Deserialize(Type type, string jsonString, bool camelCase = true) return JsonSerializer.Deserialize(jsonString, type, CreateJsonSerializerOptions(camelCase)); } - private readonly static ConcurrentDictionary JsonSerializerOptionsCache = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary JsonSerializerOptionsCache = + new ConcurrentDictionary(); protected virtual JsonSerializerOptions CreateJsonSerializerOptions(bool camelCase = true, bool indented = false) { diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerModifiersOptions.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerModifiersOptions.cs new file mode 100644 index 00000000000..5b59a7583da --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerModifiersOptions.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization.Metadata; +using Volo.Abp.Json.SystemTextJson.Modifiers; + + +namespace Volo.Abp.Json.SystemTextJson; + +public class AbpSystemTextJsonSerializerModifiersOptions +{ + public List> Modifiers { get; } + + public AbpSystemTextJsonSerializerModifiersOptions() + { + Modifiers = new List> + { + AbpIncludeExtraPropertiesModifiers.Modify, + }; + } +} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs similarity index 83% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs rename to framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs index f9d6e1a5d93..7288be03c0c 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs @@ -7,8 +7,6 @@ public class AbpSystemTextJsonSerializerOptions { public JsonSerializerOptions JsonSerializerOptions { get; } - public ITypeList UnsupportedTypes { get; } - public AbpSystemTextJsonSerializerOptions() { JsonSerializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web) @@ -16,7 +14,5 @@ public AbpSystemTextJsonSerializerOptions() ReadCommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true }; - - UnsupportedTypes = new TypeList(); } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs similarity index 62% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs rename to framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs index 42af7117729..366a933d13a 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Extensions.Options; @@ -21,25 +22,28 @@ public AbpDateTimeConverter(IClock clock, IOptions abpJsonOption public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (!_options.DefaultDateTimeFormat.IsNullOrWhiteSpace()) + if (_options.InputDateTimeFormats.Any()) { if (reader.TokenType == JsonTokenType.String) { - var s = reader.GetString(); - if (DateTime.TryParseExact(s, _options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1)) + foreach (var format in _options.InputDateTimeFormats) { - return _clock.Normalize(d1); + var s = reader.GetString(); + if (DateTime.TryParseExact(s, format, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1)) + { + return _clock.Normalize(d1); + } } - - throw new JsonException($"'{s}' can't parse to DateTime({_options.DefaultDateTimeFormat})!"); } - - throw new JsonException("Reader's TokenType is not String!"); + else + { + throw new JsonException("Reader's TokenType is not String!"); + } } - if (reader.TryGetDateTime(out var d2)) + if (reader.TryGetDateTime(out var d3)) { - return _clock.Normalize(d2); + return _clock.Normalize(d3); } throw new JsonException("Can't get datetime from the reader!"); @@ -47,13 +51,13 @@ public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, Jso public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) { - if (_options.DefaultDateTimeFormat.IsNullOrWhiteSpace()) + if (_options.OutputDateTimeFormat.IsNullOrWhiteSpace()) { writer.WriteStringValue(_clock.Normalize(value)); } else { - writer.WriteStringValue(_clock.Normalize(value).ToString(_options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture)); + writer.WriteStringValue(_clock.Normalize(value).ToString(_options.OutputDateTimeFormat, CultureInfo.CurrentUICulture)); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs similarity index 68% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs rename to framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs index 8b3459fccef..da5983250d1 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Extensions.Options; @@ -21,20 +22,23 @@ public AbpNullableDateTimeConverter(IClock clock, IOptions abpJs public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (!_options.DefaultDateTimeFormat.IsNullOrWhiteSpace()) + if (_options.InputDateTimeFormats.Any()) { if (reader.TokenType == JsonTokenType.String) { - var s = reader.GetString(); - if (DateTime.TryParseExact(s, _options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1)) + foreach (var format in _options.InputDateTimeFormats) { - return _clock.Normalize(d1); + var s = reader.GetString(); + if (DateTime.TryParseExact(s, format, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1)) + { + return _clock.Normalize(d1); + } } - - throw new JsonException($"'{s}' can't parse to DateTime({_options.DefaultDateTimeFormat})!"); } - - throw new JsonException("Reader's TokenType is not String!"); + else + { + throw new JsonException("Reader's TokenType is not String!"); + } } if (reader.TryGetDateTime(out var d2)) @@ -53,13 +57,13 @@ public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerialize } else { - if (_options.DefaultDateTimeFormat.IsNullOrWhiteSpace()) + if (_options.OutputDateTimeFormat.IsNullOrWhiteSpace()) { writer.WriteStringValue(_clock.Normalize(value.Value)); } else { - writer.WriteStringValue(_clock.Normalize(value.Value).ToString(_options.DefaultDateTimeFormat, CultureInfo.CurrentUICulture)); + writer.WriteStringValue(_clock.Normalize(value.Value).ToString(_options.OutputDateTimeFormat, CultureInfo.CurrentUICulture)); } } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs similarity index 100% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs rename to framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs similarity index 100% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs rename to framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumFactory.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumFactory.cs similarity index 100% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumFactory.cs rename to framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumFactory.cs diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs similarity index 100% rename from framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs rename to framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpDateTimeConverterModifier.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpDateTimeConverterModifier.cs new file mode 100644 index 00000000000..a691423cf31 --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpDateTimeConverterModifier.cs @@ -0,0 +1,39 @@ +using System; +using System.Linq; +using System.Text.Json.Serialization.Metadata; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Json.SystemTextJson.JsonConverters; +using Volo.Abp.Reflection; +using Volo.Abp.Timing; + +namespace Volo.Abp.Json.SystemTextJson.Modifiers; + +public class AbpDateTimeConverterModifier +{ + private IServiceProvider _serviceProvider; + + public Action CreateModifyAction(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + return Modify; + } + + private void Modify(JsonTypeInfo jsonTypeInfo) + { + if (ReflectionHelper.GetAttributesOfMemberOrDeclaringType(jsonTypeInfo.Type).Any()) + { + return; + } + + foreach (var property in jsonTypeInfo.Properties.Where(x => x.PropertyType == typeof(DateTime) || x.PropertyType == typeof(DateTime?))) + { + if (property.AttributeProvider == null || + !property.AttributeProvider.GetCustomAttributes(typeof(DisableDateTimeNormalizationAttribute), false).Any()) + { + property.CustomConverter = property.PropertyType == typeof(DateTime) + ? _serviceProvider.GetRequiredService() + : _serviceProvider.GetRequiredService(); + } + } + } +} diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpIgnorePropertiesModifiers.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpIgnorePropertiesModifiers.cs new file mode 100644 index 00000000000..27a50395bf2 --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpIgnorePropertiesModifiers.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; +using System.Text.Json.Serialization.Metadata; + +namespace Volo.Abp.Json.SystemTextJson.Modifiers; + +public class AbpIgnorePropertiesModifiers + where TClass : class +{ + private Expression> _propertySelector; + + public Action CreateModifyAction(Expression> propertySelector) + { + _propertySelector = propertySelector; + return Modify; + } + + public void Modify(JsonTypeInfo jsonTypeInfo) + { + if (jsonTypeInfo.Type == typeof(TClass)) + { + jsonTypeInfo.Properties.RemoveAll( + x => x.AttributeProvider is MemberInfo memberInfo && + memberInfo.Name == _propertySelector.Body.As().Member.Name); + } + } +} diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpIncludeExtraPropertiesModifiers.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpIncludeExtraPropertiesModifiers.cs new file mode 100644 index 00000000000..d692c358eba --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpIncludeExtraPropertiesModifiers.cs @@ -0,0 +1,29 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Text.Json.Serialization.Metadata; +using Volo.Abp.Data; +using Volo.Abp.ObjectExtending; + +namespace Volo.Abp.Json.SystemTextJson.Modifiers; + +public static class AbpIncludeExtraPropertiesModifiers +{ + public static void Modify(JsonTypeInfo jsonTypeInfo) + { + var propertyJsonInfo = jsonTypeInfo.Properties + .Where(x => x.AttributeProvider is MemberInfo) + .FirstOrDefault(x => + x.PropertyType == typeof(ExtraPropertyDictionary) && + x.AttributeProvider.As().Name == nameof(ExtensibleObject.ExtraProperties) && + x.Set == null); + + if (propertyJsonInfo != null) + { + propertyJsonInfo.Set = (extraProperties, value) => + { + ObjectHelper.TrySetProperty(extraProperties.As(), x => x.ExtraProperties, () => (ExtraPropertyDictionary)value); + }; + } + } +} diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpIncludeNonPublicPropertiesModifiers.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpIncludeNonPublicPropertiesModifiers.cs new file mode 100644 index 00000000000..3721c3ffcd0 --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpIncludeNonPublicPropertiesModifiers.cs @@ -0,0 +1,43 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text.Json.Serialization.Metadata; + +namespace Volo.Abp.Json.SystemTextJson.Modifiers; + +public class AbpIncludeNonPublicPropertiesModifiers + where TClass : class +{ + private Expression> _propertySelector; + + public Action CreateModifyAction(Expression> propertySelector) + { + _propertySelector = propertySelector; + return Modify; + } + + public void Modify(JsonTypeInfo jsonTypeInfo) + { + if (jsonTypeInfo.Type == typeof(TClass)) + { + var propertyName = _propertySelector.Body.As().Member.Name; + var propertyJsonInfo = jsonTypeInfo.Properties.FirstOrDefault(x => + x.AttributeProvider is MemberInfo memberInfo && + memberInfo.Name == propertyName && + x.Set == null); + if (propertyJsonInfo != null) + { + var propertyInfo = typeof(TClass).GetProperty(propertyName, BindingFlags.NonPublic); + if (propertyInfo != null) + { + var jsonPropertyInfo = jsonTypeInfo.CreateJsonPropertyInfo(typeof(TProperty), propertyJsonInfo.Name); + jsonPropertyInfo.Get = propertyInfo.GetValue; + jsonPropertyInfo.Set = propertyInfo.SetValue; + jsonTypeInfo.Properties.Remove(propertyJsonInfo); + jsonTypeInfo.Properties.Add(jsonPropertyInfo); + } + } + } + } +} diff --git a/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj b/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj index 76cbe9f28f1..eee618b18d1 100644 --- a/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj +++ b/framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj @@ -15,9 +15,7 @@ - - - + diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs deleted file mode 100644 index f61f8b78ce6..00000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs +++ /dev/null @@ -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 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([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(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()}'!"); - } -} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs index 77f791cd27b..b3b9c459b6b 100644 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs +++ b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs @@ -1,34 +1,10 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Options; -using Volo.Abp.Json.Newtonsoft; -using Volo.Abp.Json.SystemTextJson; +using Volo.Abp.Json.SystemTextJson; using Volo.Abp.Modularity; -using Volo.Abp.Timing; namespace Volo.Abp.Json; -[DependsOn(typeof(AbpTimingModule))] +[DependsOn(typeof(AbpJsonSystemTextJsonModule))] public class AbpJsonModule : AbpModule { - public override void ConfigureServices(ServiceConfigurationContext context) - { - context.Services.TryAddEnumerable(ServiceDescriptor - .Transient, AbpSystemTextJsonSerializerOptionsSetup>()); - var preActions = context.Services.GetPreConfigureActions(); - Configure(options => - { - options.Providers.Add(); - if (preActions.Configure().UseHybridSerializer) - { - options.Providers.Add(); - } - }); - - Configure(options => - { - options.Converters.Add(); - }); - } } diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonOptions.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonOptions.cs deleted file mode 100644 index 74d0c0fb6ac..00000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonOptions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Volo.Abp.Collections; -using Volo.Abp.Json.SystemTextJson; - -namespace Volo.Abp.Json; - -public class AbpJsonOptions -{ - /// - /// Used to set default value for the DateTimeFormat. - /// - public string DefaultDateTimeFormat { get; set; } - - /// - /// It will try to use System.Json.Text to handle JSON if it can otherwise use Newtonsoft. - /// Affects both AbpJsonModule and AbpAspNetCoreMvcModule. - /// See - /// - public bool UseHybridSerializer { get; set; } - - public ITypeList Providers { get; } - - public AbpJsonOptions() - { - Providers = new TypeList(); - UseHybridSerializer = true; - } -} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/IJsonSerializerProvider.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/IJsonSerializerProvider.cs deleted file mode 100644 index c3ae179d457..00000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/IJsonSerializerProvider.cs +++ /dev/null @@ -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(string jsonString, bool camelCase = true); - - object Deserialize(Type type, string jsonString, bool camelCase = true); -} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs deleted file mode 100644 index 660a69e4e78..00000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Timing; - -namespace Volo.Abp.Json.Newtonsoft; - -public class AbpJsonIsoDateTimeConverter : IsoDateTimeConverter, ITransientDependency -{ - private readonly IClock _clock; - - public AbpJsonIsoDateTimeConverter(IClock clock, IOptions abpJsonOptions) - { - _clock = clock; - - if (abpJsonOptions.Value.DefaultDateTimeFormat != null) - { - DateTimeFormat = abpJsonOptions.Value.DefaultDateTimeFormat; - } - } - - public override bool CanConvert(Type objectType) - { - if (objectType == typeof(DateTime) || objectType == typeof(DateTime?)) - { - return true; - } - - return false; - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var date = base.ReadJson(reader, objectType, existingValue, serializer) as DateTime?; - - if (date.HasValue) - { - return _clock.Normalize(date.Value); - } - - return null; - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var date = value as DateTime?; - base.WriteJson(writer, date.HasValue ? _clock.Normalize(date.Value) : value, serializer); - } -} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerProvider.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerProvider.cs deleted file mode 100644 index 14ae0556f34..00000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerProvider.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using Volo.Abp.DependencyInjection; - -namespace Volo.Abp.Json.Newtonsoft; - -public class AbpNewtonsoftJsonSerializerProvider : IJsonSerializerProvider, ITransientDependency -{ - private static readonly CamelCaseExceptDictionaryKeysResolver SharedCamelCaseExceptDictionaryKeysResolver = - new CamelCaseExceptDictionaryKeysResolver(); - - protected List Converters { get; } - - public AbpNewtonsoftJsonSerializerProvider( - IOptions options, - IServiceProvider serviceProvider) - { - Converters = options.Value - .Converters - .Select(c => (JsonConverter)serviceProvider.GetRequiredService(c)) - .ToList(); - } - - public bool CanHandle(Type type) - { - return true; - } - - public string Serialize(object obj, bool camelCase = true, bool indented = false) - { - return JsonConvert.SerializeObject(obj, CreateSerializerSettings(camelCase, indented)); - } - - public T Deserialize(string jsonString, bool camelCase = true) - { - return JsonConvert.DeserializeObject(jsonString, CreateSerializerSettings(camelCase)); - } - - public object Deserialize(Type type, string jsonString, bool camelCase = true) - { - return JsonConvert.DeserializeObject(jsonString, type, CreateSerializerSettings(camelCase)); - } - - protected virtual JsonSerializerSettings CreateSerializerSettings(bool camelCase = true, bool indented = false) - { - var settings = new JsonSerializerSettings(); - - settings.Converters.InsertRange(0, Converters); - - if (camelCase) - { - settings.ContractResolver = SharedCamelCaseExceptDictionaryKeysResolver; - } - - if (indented) - { - settings.Formatting = Formatting.Indented; - } - - return settings; - } - - private class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver - { - protected override JsonDictionaryContract CreateDictionaryContract(Type objectType) - { - var contract = base.CreateDictionaryContract(objectType); - - contract.DictionaryKeyResolver = propertyName => propertyName; - - return contract; - } - } -} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs deleted file mode 100644 index 1615581a9df..00000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Text.Encodings.Web; -using System.Text.Json.Serialization; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Volo.Abp.Json.SystemTextJson.JsonConverters; - -namespace Volo.Abp.Json.SystemTextJson; - -public class AbpSystemTextJsonSerializerOptionsSetup : IConfigureOptions -{ - protected IServiceProvider ServiceProvider { get; } - - public AbpSystemTextJsonSerializerOptionsSetup(IServiceProvider serviceProvider) - { - ServiceProvider = serviceProvider; - } - - public void Configure(AbpSystemTextJsonSerializerOptions options) - { - options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService()); - options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService()); - - options.JsonSerializerOptions.Converters.Add(new AbpStringToEnumFactory()); - options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter()); - - options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter()); - - // If the user hasn't explicitly configured the encoder, use the less strict encoder that does not encode all non-ASCII characters. - options.JsonSerializerOptions.Encoder ??= JavaScriptEncoder.UnsafeRelaxedJsonEscaping; - } -} diff --git a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonUnsupportedTypeMatcher.cs b/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonUnsupportedTypeMatcher.cs deleted file mode 100644 index eecc20c5551..00000000000 --- a/framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonUnsupportedTypeMatcher.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using JetBrains.Annotations; -using Microsoft.Extensions.Options; -using Volo.Abp.DependencyInjection; - -namespace Volo.Abp.Json.SystemTextJson; - -public class AbpSystemTextJsonUnsupportedTypeMatcher : ITransientDependency -{ - protected AbpSystemTextJsonSerializerOptions Options { get; } - - public AbpSystemTextJsonUnsupportedTypeMatcher(IOptions options) - { - Options = options.Value; - } - - public virtual bool Match([CanBeNull] Type type) - { - return Options.UnsupportedTypes.Contains(type); - } -} diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs index 4479eeb6486..611176b5704 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Text.Json.Serialization; using Volo.Abp.Data; using Volo.Abp.DynamicProxy; @@ -10,7 +9,6 @@ namespace Volo.Abp.ObjectExtending; [Serializable] public class ExtensibleObject : IHasExtraProperties, IValidatableObject { - [JsonInclude] public ExtraPropertyDictionary ExtraProperties { get; protected set; } public ExtensibleObject() diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj index 5cc7aa3857b..930cdb58552 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj @@ -25,7 +25,6 @@ - diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs index e303a0fb5db..d8a49abf233 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs @@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; -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; diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs index 851ef88db87..e7015313cb0 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs @@ -14,7 +14,7 @@ protected override void ConfigureServices(HostBuilderContext context, IServiceCo { services.Configure(options => { - options.DefaultDateTimeFormat = "yyyy*MM*dd"; + options.OutputDateTimeFormat = "yyyy*MM*dd"; }); base.ConfigureServices(context, services); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs index 2f986c89c3c..1613e4bb49f 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs @@ -21,7 +21,7 @@ protected override void ConfigureServices(HostBuilderContext context, IServiceCo { services.Configure(options => { - options.DefaultDateTimeFormat = "yyyy*MM*dd"; + options.OutputDateTimeFormat = "yyyy*MM*dd"; }); base.ConfigureServices(context, services); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs index 0d30d101cba..befbd169fa6 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; using Shouldly; using Volo.Abp.Http; using Volo.Abp.Json.SystemTextJson; @@ -18,15 +19,6 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase { protected DateTimeKind Kind { get; set; } - protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - services.Configure(options => - { - options.UnsupportedTypes.Add(); - options.UnsupportedTypes.Add(); - }); - } - [Fact] public async Task DateTimeKind_Test() { diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Startup.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Startup.cs index ad4a222c33f..df5a8b7b9c3 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Startup.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Startup.cs @@ -1,4 +1,6 @@ -using System.IO; +using System; +using System.IO; +using System.Linq; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; @@ -14,13 +16,34 @@ public void ConfigureServices(IServiceCollection services) services.AddApplication(options => { var hostEnvironment = services.GetHostingEnvironment(); + var currentDirectory = hostEnvironment.ContentRootPath; + var plugDllInPath = ""; + + for (var i = 0; i < 10; i++) + { + var parentDirectory = new DirectoryInfo(currentDirectory).Parent; + if (parentDirectory == null) + { + break; + } + + if (parentDirectory.Name == "test") + { #if DEBUG - var plugDllInPath = Path.Combine(hostEnvironment.ContentRootPath, - @"..\..\..\..\..\Volo.Abp.AspNetCore.Mvc.PlugIn\bin\Debug\net7.0\"); + plugDllInPath = Path.Combine(parentDirectory.FullName, "Volo.Abp.AspNetCore.Mvc.PlugIn", "bin", "Debug", "net7.0"); #else - plugDllInPath = Path.Combine(_env.ContentRootPath, - @"..\..\..\..\..\Volo.Abp.AspNetCore.Mvc.PlugIn\bin\Release\net7.0\"); + plugDllInPath = Path.Combine(parentDirectory.FullName, "Volo.Abp.AspNetCore.Mvc.PlugIn", "bin", "Release", "net7.0"); #endif + break; + } + + currentDirectory = parentDirectory.FullName; + } + + if (plugDllInPath.IsNullOrWhiteSpace()) + { + throw new AbpException("Could not find the plug DLL path!"); + } options.PlugInSources.AddFolder(plugDllInPath); }); diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/JsonNetAuditSerializer_Test.cs b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/JsonAuditSerializer_Test.cs similarity index 86% rename from framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/JsonNetAuditSerializer_Test.cs rename to framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/JsonAuditSerializer_Test.cs index 4de7881cace..2613fe4ba67 100644 --- a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/JsonNetAuditSerializer_Test.cs +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/JsonAuditSerializer_Test.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; +using System.Text.Json.Serialization; using Microsoft.Extensions.DependencyInjection; using Shouldly; using Xunit; namespace Volo.Abp.Auditing; -public class JsonNetAuditSerializer_Test : AbpAuditingTestBase +public class JsonAuditSerializer_Test : AbpAuditingTestBase { protected override void AfterAddApplication(IServiceCollection services) { @@ -27,7 +28,7 @@ public void Serialize_Test() {"input2", new Input2Dto {UserName = "admin", Password = "1q2w3E*", Birthday = DateTime.Now}} }; - var str = GetRequiredService().Serialize(arguments); + var str = GetRequiredService().Serialize(arguments); str.ShouldNotContain("IdCard"); str.ShouldNotContain("1q2w3E*"); @@ -51,7 +52,7 @@ class Input2Dto [DisableAuditing] public string Password { get; set; } - [Newtonsoft.Json.JsonIgnore] + [JsonIgnore] public string PrivateEmail { get; set; } public DateTime Birthday { get; set; } diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHybridJsonSerializer_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHybridJsonSerializer_Tests.cs deleted file mode 100644 index 5733d739d20..00000000000 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHybridJsonSerializer_Tests.cs +++ /dev/null @@ -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(); - } - - protected override void AfterAddApplication(IServiceCollection services) - { - services.Configure(options => - { - options.UnsupportedTypes.Add(); - - options.JsonSerializerOptions.Converters.Add(new SystemTextJsonConverter()); - }); - - services.Configure(options => - { - options.Converters.Add(); - }); - } - - [Fact] - public void NewtonsoftSerialize_Test() - { - var json = _jsonSerializer.Serialize(new MyClass1 - { - Providers = new List - { - new MyClass3() - } - }); - - json.ShouldContain("Newtonsoft"); - } - - [Fact] - public void SystemTextJsonSerialize_Test() - { - var json = _jsonSerializer.Serialize(new MyClass2 - { - Providers = new List - { - 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(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 Providers { get; set; } - } - - public class MyClass2 - { - public string Provider { get; set; } - - public List Providers { get; set; } - } - - public class MyClass3 - { - public string Provider { get; set; } - } - - public class MyClassWithDictionary - { - public Dictionary Properties { get; set; } - - public MyClassWithDictionary() - { - Properties = new Dictionary(); - } - } - - class NewtonsoftJsonConverter : JsonConverter, 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, 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); - } - } -} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpIgnorePropertiesModifiers_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpIgnorePropertiesModifiers_Tests.cs new file mode 100644 index 00000000000..138ffd46a7e --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpIgnorePropertiesModifiers_Tests.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Json.SystemTextJson; +using Volo.Abp.Json.SystemTextJson.Modifiers; +using Xunit; + +namespace Volo.Abp.Json; + +public class AbpIgnorePropertiesModifiers_Tests : AbpJsonTestBase +{ + private readonly IJsonSerializer _jsonSerializer; + + public AbpIgnorePropertiesModifiers_Tests() + { + _jsonSerializer = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + services.Configure(options => + { + options.Modifiers.Add(new AbpIgnorePropertiesModifiers>().CreateModifyAction(x => x.BarDtos)); + options.Modifiers.Add(new AbpIgnorePropertiesModifiers().CreateModifyAction(x => x.Id)); + }); + + base.AfterAddApplication(services); + } + + [Fact] + public void Test() + { + var json = _jsonSerializer.Serialize(new FooDto() + { + Name = "foo", + BarDtos = new List + { + new BarDto + { + Name = "bar1" + }, + new BarDto + { + Name = "bar2" + } + } + }); + + json.ShouldNotContain("bar"); + + json = _jsonSerializer.Serialize(new BarDto() + { + Id = "id", + Name = "bar" + }); + + json.ShouldNotContain("id"); + } + + class FooDto + { + public string Name { get; set; } + + public List BarDtos { get; set; } + } + + class BarDto + { + public string Id { get; set; } + + public string Name { get; set; } + } +} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpIncludeNonPublicPropertiesModifiers_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpIncludeNonPublicPropertiesModifiers_Tests.cs new file mode 100644 index 00000000000..d05ab2dfa0f --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpIncludeNonPublicPropertiesModifiers_Tests.cs @@ -0,0 +1,61 @@ +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Json.SystemTextJson; +using Volo.Abp.Json.SystemTextJson.Modifiers; +using Xunit; + +namespace Volo.Abp.Json; + +public class AbpIncludeNonPublicPropertiesModifiers_Tests : AbpJsonTestBase +{ + private readonly IJsonSerializer _jsonSerializer; + + public AbpIncludeNonPublicPropertiesModifiers_Tests() + { + _jsonSerializer = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + services.Configure(options => + { + options.Modifiers.Add(new AbpIncludeNonPublicPropertiesModifiers().CreateModifyAction(x => x.Name)); + options.Modifiers.Add(new AbpIncludeNonPublicPropertiesModifiers().CreateModifyAction(x => x.Age)); + }); + + base.AfterAddApplication(services); + } + + [Fact] + public void Test() + { + var json = _jsonSerializer.Serialize(new NonPublicPropertiesClass() + { + Id = "id" + }); + + json.ShouldContain("id"); + json.ShouldContain("name"); + json.ShouldContain("age"); + + var obj = _jsonSerializer.Deserialize(json); + obj.Id.ShouldBe("id"); + obj.Name.ShouldBe("name"); + obj.Age.ShouldBe("age"); + } + + class NonPublicPropertiesClass + { + public string Id { get; set; } + + public string Name { get; private set; } + + public string Age { get; protected set; } + + public NonPublicPropertiesClass() + { + Name = "name"; + Age = "age"; + } + } +} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs index 21b3fd51bbf..f605914d6e9 100644 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs @@ -11,11 +11,11 @@ namespace Volo.Abp.Json; public abstract class AbpSystemTextJsonSerializerProvider_TestBase : AbpJsonTestBase { - protected AbpSystemTextJsonSerializerProvider JsonSerializer; + protected AbpSystemTextJsonSerializer JsonSerializer; public AbpSystemTextJsonSerializerProvider_TestBase() { - JsonSerializer = GetRequiredService(); + JsonSerializer = GetRequiredService(); } public class TestExtensibleObjectClass : ExtensibleObject @@ -220,7 +220,8 @@ protected override void AfterAddApplication(IServiceCollection services) { services.Configure(options => { - options.DefaultDateTimeFormat = "yyyy*MM*dd"; + options.InputDateTimeFormats.Add("yyyy*MM*dd"); + options.OutputDateTimeFormat = "yyyy*MM*dd HH*mm*ss"; }); } @@ -233,8 +234,12 @@ public void Serialize_Deserialize_With_Format_Datetime() file.CreationTime.Month.ShouldBe(11); file.CreationTime.Day.ShouldBe(20); - var newJson = JsonSerializer.Serialize(file); - newJson.ShouldBe(json); + json = JsonSerializer.Serialize(new FileWithDatetime() + { + Name = "abp", + CreationTime = new DateTime(2020, 11, 20, 12, 34, 56) + }); + json.ShouldContain("\"2020*11*20 12*34*56\""); } [Fact] @@ -256,8 +261,12 @@ public void Serialize_Deserialize_With_Nullable_Format_Datetime() file.CreationTime.Value.Month.ShouldBe(11); file.CreationTime.Value.Day.ShouldBe(20); - var newJson = JsonSerializer.Serialize(file); - newJson.ShouldBe(json); + json = JsonSerializer.Serialize(new FileWithDatetime() + { + Name = "abp", + CreationTime = new DateTime(2020, 11, 20, 12, 34, 56) + }); + json.ShouldContain("\"2020*11*20 12*34*56\""); } } diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonUnsupportedTypeMatcher_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonUnsupportedTypeMatcher_Tests.cs deleted file mode 100644 index 1c621f39301..00000000000 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonUnsupportedTypeMatcher_Tests.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.DependencyInjection; -using Shouldly; -using Volo.Abp.Json.SystemTextJson; -using Xunit; - -namespace Volo.Abp.Json; - -public class AbpSystemTextJsonUnsupportedTypeMatcher_Tests : AbpJsonTestBase -{ - private readonly AbpSystemTextJsonUnsupportedTypeMatcher _abpSystemTextJsonUnsupportedTypeMatcher; - - public AbpSystemTextJsonUnsupportedTypeMatcher_Tests() - { - _abpSystemTextJsonUnsupportedTypeMatcher = GetRequiredService(); - } - - protected override void AfterAddApplication(IServiceCollection services) - { - services.Configure(options => - { - options.UnsupportedTypes.Add(); - options.UnsupportedTypes.Add(); - options.UnsupportedTypes.Add>(); - }); - } - - [Fact] - public void Match_Test() - { - _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(MyClass)).ShouldBeTrue(); - _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(byte[])).ShouldBeTrue(); - - _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(MyClass2)).ShouldBeFalse(); - _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(MyClass3)).ShouldBeFalse(); - _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(MyClass4)).ShouldBeFalse(); - - _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(string)).ShouldBeFalse(); - _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(string[])).ShouldBeFalse(); - - _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(Dictionary)).ShouldBeTrue(); - _abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(IDictionary)).ShouldBeFalse(); - } - - class MyClass - { - public DateTime Prop1 { get; set; } - } - - class MyClass2 - { - public DateTime Prop1 { get; set; } - } - - class MyClass3 - { - public MyClass4 Prop1 { get; set; } - } - - class MyClass4 - { - public DateTime Prop1 { get; set; } - } -} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObjectModifiers_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObjectModifiers_Tests.cs new file mode 100644 index 00000000000..820f18b1a29 --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObjectModifiers_Tests.cs @@ -0,0 +1,19 @@ +using Shouldly; +using Volo.Abp.Json.SystemTextJson; +using Volo.Abp.ObjectExtending; +using Xunit; + +namespace Volo.Abp.Json; + +public class ExtensibleObjectModifiers_Tests : AbpJsonTestBase +{ + [Fact] + public void Should_Modify_Object() + { + var jsonSerializer = GetRequiredService(); + + var extensibleObject = jsonSerializer.Deserialize("{\"ExtraProperties\": {\"Test-Key\":\"Test-Value\"}}"); + + extensibleObject.ExtraProperties.ShouldContainKeyAndValue("Test-Key", "Test-Value"); + } +} diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs index bdd41f20b64..a5bcb723dbe 100644 --- a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.Json; -public class ExtensibleObject_Tests: AbpJsonTestBase +public class ExtensibleObject_Tests : AbpJsonTestBase { private readonly IJsonSerializer _jsonSerializer; diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs index a69cb893d02..113ae34499c 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs @@ -21,4 +21,4 @@ public override void ConfigureServices(ServiceConfigurationContext context) options.FileSets.AddEmbedded(); }); } -} +} \ No newline at end of file diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo.Abp.FeatureManagement.Domain.Shared.csproj b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo.Abp.FeatureManagement.Domain.Shared.csproj index 21f8595cf7e..14f93d3db7f 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo.Abp.FeatureManagement.Domain.Shared.csproj +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo.Abp.FeatureManagement.Domain.Shared.csproj @@ -16,7 +16,7 @@ - + diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs index 5d924f14571..3d47bfbde82 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs @@ -1,10 +1,6 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.FeatureManagement.JsonConverters; using Volo.Abp.FeatureManagement.Localization; -using Volo.Abp.Json; -using Volo.Abp.Json.Newtonsoft; using Volo.Abp.Json.SystemTextJson; using Volo.Abp.Localization; using Volo.Abp.Localization.ExceptionHandling; @@ -17,7 +13,7 @@ namespace Volo.Abp.FeatureManagement; [DependsOn( typeof(AbpValidationModule), - typeof(AbpJsonModule) + typeof(AbpJsonSystemTextJsonModule) )] public class AbpFeatureManagementDomainSharedModule : AbpModule { @@ -42,11 +38,6 @@ public override void ConfigureServices(ServiceConfigurationContext context) options.MapCodeNamespace("Volo.Abp.FeatureManagement", typeof(AbpFeatureManagementResource)); }); - Configure(options => - { - options.Converters.Add(); - }); - var valueValidatorFactoryOptions = context.Services.GetPreConfigureActions(); Configure(options => { diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/JsonConverters/NewtonsoftStringValueTypeJsonConverter.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/JsonConverters/NewtonsoftStringValueTypeJsonConverter.cs deleted file mode 100644 index 2bb3e1fd2d6..00000000000 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/JsonConverters/NewtonsoftStringValueTypeJsonConverter.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Validation.StringValues; - -namespace Volo.Abp.FeatureManagement.JsonConverters; - -public class NewtonsoftStringValueTypeJsonConverter : JsonConverter, ITransientDependency -{ - public override bool CanWrite => false; - - protected readonly ValueValidatorFactoryOptions Options; - - public NewtonsoftStringValueTypeJsonConverter(IOptions options) - { - Options = options.Value; - } - - public override bool CanConvert(Type objectType) - { - return objectType == typeof(IStringValueType); - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new NotImplementedException("This method should not be called to write (since CanWrite is false)."); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - if (reader.TokenType != JsonToken.StartObject) - { - return null; - } - - var jsonObject = JObject.Load(reader); - - var stringValue = CreateStringValueTypeByName(jsonObject, jsonObject["name"].ToString()); - foreach (var o in serializer.Deserialize>( - new JsonTextReader(new StringReader(jsonObject["properties"].ToString())))) - { - stringValue[o.Key] = o.Value; - } - - stringValue.Validator = CreateValueValidatorByName(jsonObject["validator"], jsonObject["validator"]["name"].ToString()); - foreach (var o in serializer.Deserialize>( - new JsonTextReader(new StringReader(jsonObject["validator"]["properties"].ToString())))) - { - stringValue.Validator[o.Key] = o.Value; - } - - return stringValue; - } - - protected virtual IStringValueType CreateStringValueTypeByName(JObject jObject, string name) - { - if (name == "SelectionStringValueType") - { - var selectionStringValueType = new SelectionStringValueType(); - if (jObject["itemSource"].HasValues) - { - selectionStringValueType.ItemSource = new StaticSelectionStringValueItemSource(jObject["itemSource"]["items"] - .Select(item => new LocalizableSelectionStringValueItem() - { - Value = item["value"].ToString(), - DisplayText = new LocalizableStringInfo(item["displayText"]["resourceName"].ToString(), item["displayText"]["name"].ToString()) - }).ToArray()); - } - - return selectionStringValueType; - } - - return name switch - { - "FreeTextStringValueType" => new FreeTextStringValueType(), - "ToggleStringValueType" => new ToggleStringValueType(), - _ => throw new ArgumentException($"{nameof(IStringValueType)} named {name} was not found!") - }; - } - - protected virtual IValueValidator CreateValueValidatorByName(JToken jObject, string name) - { - foreach (var factory in Options.ValueValidatorFactory.Where(factory => factory.CanCreate(name))) - { - return factory.Create(); - } - - throw new ArgumentException($"{nameof(IValueValidator)} named {name} was cannot be created!"); - } -} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureGroupDefinitionRecord.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureGroupDefinitionRecord.cs index c40f74c2cd1..677f055f3ec 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureGroupDefinitionRecord.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureGroupDefinitionRecord.cs @@ -1,5 +1,5 @@ using System; -using Newtonsoft.Json; +using System.Text.Json.Serialization; using Volo.Abp.Data; using Volo.Abp.Domain.Entities; diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/NewtonsoftStringValueJsonConverter_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/NewtonsoftStringValueJsonConverter_Tests.cs deleted file mode 100644 index 09f3c2266d1..00000000000 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/NewtonsoftStringValueJsonConverter_Tests.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Json; - -namespace Volo.Abp.FeatureManagement; - -public class NewtonsoftStringValueJsonConverter_Tests : StringValueJsonConverter_Tests -{ - protected override void AfterAddApplication(IServiceCollection services) - { - services.PreConfigure(options => - { - options.UseHybridSerializer = false; - }); - } -} diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs deleted file mode 100644 index be4b431b820..00000000000 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.DependencyInjection; -using Shouldly; -using Volo.Abp.FeatureManagement.JsonConverters; -using Volo.Abp.Json; -using Volo.Abp.Validation.StringValues; -using Xunit; - -namespace Volo.Abp.FeatureManagement; - -public abstract class StringValueJsonConverter_Tests : FeatureManagementApplicationTestBase -{ - private readonly IJsonSerializer _jsonSerializer; - - public StringValueJsonConverter_Tests() - { - _jsonSerializer = GetRequiredService(); - } - - protected override void BeforeAddApplication(IServiceCollection services) - { - services.PreConfigure(options => - { - options.ValueValidatorFactory.Add(new ValueValidatorFactory("URL")); - }); - - base.BeforeAddApplication(services); - } - - [Fact] - public void Should_Serialize_And_Deserialize() - { - var featureListDto = new GetFeatureListResultDto - { - Groups = new List - { - new FeatureGroupDto - { - Name = "MyGroup", - DisplayName = "MyGroup", - Features = new List - { - new FeatureDto - { - ValueType = new FreeTextStringValueType - { - Validator = new BooleanValueValidator() - } - }, - new FeatureDto - { - ValueType = new SelectionStringValueType - { - ItemSource = new StaticSelectionStringValueItemSource( - new LocalizableSelectionStringValueItem - { - Value = "TestValue", - DisplayText = new LocalizableStringInfo("TestResourceName", "TestName") - }), - Validator = new AlwaysValidValueValidator() - } - }, - new FeatureDto - { - ValueType = new ToggleStringValueType - { - Validator = new NumericValueValidator - { - MaxValue = 1000, - MinValue = 10 - } - } - }, - new FeatureDto - { - Provider = new FeatureProviderDto - { - Name = "FeatureName", - Key = "FeatureKey" - } - }, - new FeatureDto - { - ValueType = new FreeTextStringValueType - { - Validator = new UrlValueValidator("https") - } - } - } - } - } - }; - - var serialized = _jsonSerializer.Serialize(featureListDto, indented: true); - - var featureListDto2 = _jsonSerializer.Deserialize(serialized); - - featureListDto2.ShouldNotBeNull(); - featureListDto2.Groups[0].Features[0].ValueType.ShouldBeOfType(); - featureListDto2.Groups[0].Features[0].ValueType.Validator.ShouldBeOfType(); - - featureListDto2.Groups[0].Features[1].ValueType.ShouldBeOfType(); - featureListDto2.Groups[0].Features[1].ValueType.Validator.ShouldBeOfType(); - featureListDto2.Groups[0].Features[1].ValueType.As().ItemSource.Items.ShouldBeOfType(); - featureListDto2.Groups[0].Features[1].ValueType.As().ItemSource.Items.ShouldContain(x => - x.Value == "TestValue" && x.DisplayText.ResourceName == "TestResourceName" && - x.DisplayText.Name == "TestName"); - - featureListDto2.Groups[0].Features[2].ValueType.ShouldBeOfType(); - featureListDto2.Groups[0].Features[2].ValueType.Validator.ShouldBeOfType(); - featureListDto2.Groups[0].Features[2].ValueType.Validator.As().MaxValue.ShouldBe(1000); - featureListDto2.Groups[0].Features[2].ValueType.Validator.As().MinValue.ShouldBe(10); - - featureListDto2.Groups[0].Features[3].Provider.Name.ShouldBe("FeatureName"); - featureListDto2.Groups[0].Features[3].Provider.Key.ShouldBe("FeatureKey"); - - featureListDto2.Groups[0].Features[4].ValueType.ShouldBeOfType(); - featureListDto2.Groups[0].Features[4].ValueType.Validator.ShouldBeOfType(); - featureListDto2.Groups[0].Features[4].ValueType.Validator.As().Scheme.ShouldBe("https"); - } -} diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/SystemTextJsonStringValueJsonConverter_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/SystemTextJsonStringValueJsonConverter_Tests.cs index 968055c09f6..05172105792 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/SystemTextJsonStringValueJsonConverter_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/SystemTextJsonStringValueJsonConverter_Tests.cs @@ -1,15 +1,122 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.FeatureManagement.JsonConverters; using Volo.Abp.Json; +using Volo.Abp.Validation.StringValues; +using Xunit; namespace Volo.Abp.FeatureManagement; -public class SystemTextJsonStringValueJsonConverter_Tests : StringValueJsonConverter_Tests +public class SystemTextJsonStringValueJsonConverter_Tests : FeatureManagementApplicationTestBase { - protected override void AfterAddApplication(IServiceCollection services) + private readonly IJsonSerializer _jsonSerializer; + + public SystemTextJsonStringValueJsonConverter_Tests() + { + _jsonSerializer = GetRequiredService(); + } + + protected override void BeforeAddApplication(IServiceCollection services) { - services.PreConfigure(options => + services.PreConfigure(options => { - options.UseHybridSerializer = true; + options.ValueValidatorFactory.Add(new ValueValidatorFactory("URL")); }); + + base.BeforeAddApplication(services); + } + + [Fact] + public void Should_Serialize_And_Deserialize() + { + var featureListDto = new GetFeatureListResultDto + { + Groups = new List + { + new FeatureGroupDto + { + Name = "MyGroup", + DisplayName = "MyGroup", + Features = new List + { + new FeatureDto + { + ValueType = new FreeTextStringValueType + { + Validator = new BooleanValueValidator() + } + }, + new FeatureDto + { + ValueType = new SelectionStringValueType + { + ItemSource = new StaticSelectionStringValueItemSource( + new LocalizableSelectionStringValueItem + { + Value = "TestValue", + DisplayText = new LocalizableStringInfo("TestResourceName", "TestName") + }), + Validator = new AlwaysValidValueValidator() + } + }, + new FeatureDto + { + ValueType = new ToggleStringValueType + { + Validator = new NumericValueValidator + { + MaxValue = 1000, + MinValue = 10 + } + } + }, + new FeatureDto + { + Provider = new FeatureProviderDto + { + Name = "FeatureName", + Key = "FeatureKey" + } + }, + new FeatureDto + { + ValueType = new FreeTextStringValueType + { + Validator = new UrlValueValidator("https") + } + } + } + } + } + }; + + var serialized = _jsonSerializer.Serialize(featureListDto, indented: true); + + var featureListDto2 = _jsonSerializer.Deserialize(serialized); + + featureListDto2.ShouldNotBeNull(); + featureListDto2.Groups[0].Features[0].ValueType.ShouldBeOfType(); + featureListDto2.Groups[0].Features[0].ValueType.Validator.ShouldBeOfType(); + + featureListDto2.Groups[0].Features[1].ValueType.ShouldBeOfType(); + featureListDto2.Groups[0].Features[1].ValueType.Validator.ShouldBeOfType(); + featureListDto2.Groups[0].Features[1].ValueType.As().ItemSource.Items.ShouldBeOfType(); + featureListDto2.Groups[0].Features[1].ValueType.As().ItemSource.Items.ShouldContain(x => + x.Value == "TestValue" && x.DisplayText.ResourceName == "TestResourceName" && + x.DisplayText.Name == "TestName"); + + featureListDto2.Groups[0].Features[2].ValueType.ShouldBeOfType(); + featureListDto2.Groups[0].Features[2].ValueType.Validator.ShouldBeOfType(); + featureListDto2.Groups[0].Features[2].ValueType.Validator.As().MaxValue.ShouldBe(1000); + featureListDto2.Groups[0].Features[2].ValueType.Validator.As().MinValue.ShouldBe(10); + + featureListDto2.Groups[0].Features[3].Provider.Name.ShouldBe("FeatureName"); + featureListDto2.Groups[0].Features[3].Provider.Key.ShouldBe("FeatureKey"); + + featureListDto2.Groups[0].Features[4].ValueType.ShouldBeOfType(); + featureListDto2.Groups[0].Features[4].ValueType.Validator.ShouldBeOfType(); + featureListDto2.Groups[0].Features[4].ValueType.Validator.As().Scheme.ShouldBe("https"); } } diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index ee2671c0448..7f9e694b09a 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -113,6 +113,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", @@ -196,6 +197,9 @@ $projects = ( "framework/src/Volo.Abp.Http", "framework/src/Volo.Abp.IdentityModel", "framework/src/Volo.Abp.Json", + "framework/src/Volo.Abp.Json.Abstractions", + "framework/src/Volo.Abp.Json.Newtonsoft", + "framework/src/Volo.Abp.Json.SystemTextJson", "framework/src/Volo.Abp.Ldap", "framework/src/Volo.Abp.Localization.Abstractions", "framework/src/Volo.Abp.MailKit",