Browse Source

Merge pull request #13357 from abpframework/json

Split JSON into `Newtonsoft` & `SystemTextJson` packages.
pull/14450/head
Halil İbrahim Kalkan 3 years ago
committed by GitHub
parent
commit
4d83ee63bb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      docs/en/JSON.md
  2. 28
      framework/Volo.Abp.sln
  3. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/FodyWeavers.xml
  4. 30
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/FodyWeavers.xsd
  5. 29
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson.csproj
  6. 21
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpAspNetCoreMvcNewtonsoftModule.cs
  7. 1
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj
  8. 6
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs
  9. 11
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProviderOptions.cs
  10. 45
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonInputFormatter.cs
  11. 72
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOptionsSetup.cs
  12. 42
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpHybridJsonOutputFormatter.cs
  13. 33
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs
  14. 48
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs
  15. 21
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcNewtonsoftJsonOptionsSetup.cs
  16. 21
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MediaTypeHeaderValues.cs
  17. 35
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs
  18. 2
      framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs
  19. 18
      framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpNoopHostLifetime.cs
  20. 19
      framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/WebHostBuilderExtensions.cs
  21. 42
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingContractResolver.cs
  22. 77
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonAuditSerializer.cs
  23. 43
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs
  24. 1
      framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj
  25. 8
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs
  26. 11
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/LIbs/InstallLibsService.cs
  27. 18
      framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingConfiguration.cs
  28. 3
      framework/src/Volo.Abp.Json.Abstractions/FodyWeavers.xml
  29. 30
      framework/src/Volo.Abp.Json.Abstractions/FodyWeavers.xsd
  30. 20
      framework/src/Volo.Abp.Json.Abstractions/Volo.Abp.Json.Abstractions.csproj
  31. 8
      framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/AbpJsonAbstractionsModule.cs
  32. 21
      framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/AbpJsonOptions.cs
  33. 0
      framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/IJsonSerializer.cs
  34. 3
      framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xml
  35. 30
      framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd
  36. 23
      framework/src/Volo.Abp.Json.Newtonsoft/Volo.Abp.Json.Newtonsoft.csproj
  37. 38
      framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpCamelCasePropertyNamesContractResolver.cs
  38. 116
      framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDateTimeConverter.cs
  39. 33
      framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpDefaultContractResolver.cs
  40. 18
      framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonNewtonsoftModule.cs
  41. 96
      framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializer.cs
  42. 5
      framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs
  43. 3
      framework/src/Volo.Abp.Json.SystemTextJson/FodyWeavers.xml
  44. 30
      framework/src/Volo.Abp.Json.SystemTextJson/FodyWeavers.xsd
  45. 23
      framework/src/Volo.Abp.Json.SystemTextJson/Volo.Abp.Json.SystemTextJson.csproj
  46. 16
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpDefaultJsonTypeInfoResolver.cs
  47. 37
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs
  48. 17
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializer.cs
  49. 20
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerModifiersOptions.cs
  50. 4
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs
  51. 28
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs
  52. 24
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs
  53. 0
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs
  54. 0
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs
  55. 0
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumFactory.cs
  56. 0
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs
  57. 39
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpDateTimeConverterModifier.cs
  58. 29
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpIgnorePropertiesModifiers.cs
  59. 29
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpIncludeExtraPropertiesModifiers.cs
  60. 43
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/Modifiers/AbpIncludeNonPublicPropertiesModifiers.cs
  61. 4
      framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj
  62. 66
      framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs
  63. 28
      framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs
  64. 27
      framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonOptions.cs
  65. 15
      framework/src/Volo.Abp.Json/Volo/Abp/Json/IJsonSerializerProvider.cs
  66. 51
      framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs
  67. 79
      framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerProvider.cs
  68. 32
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs
  69. 21
      framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonUnsupportedTypeMatcher.cs
  70. 2
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs
  71. 1
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj
  72. 1
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs
  73. 2
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs
  74. 2
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs
  75. 10
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs
  76. 33
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Startup.cs
  77. 7
      framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/JsonAuditSerializer_Test.cs
  78. 149
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHybridJsonSerializer_Tests.cs
  79. 73
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpIgnorePropertiesModifiers_Tests.cs
  80. 61
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpIncludeNonPublicPropertiesModifiers_Tests.cs
  81. 23
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonSerializerProvider_Tests.cs
  82. 65
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonUnsupportedTypeMatcher_Tests.cs
  83. 19
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObjectModifiers_Tests.cs
  84. 2
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs
  85. 2
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs
  86. 2
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo.Abp.FeatureManagement.Domain.Shared.csproj
  87. 13
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs
  88. 95
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/JsonConverters/NewtonsoftStringValueTypeJsonConverter.cs
  89. 2
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureGroupDefinitionRecord.cs
  90. 15
      modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/NewtonsoftStringValueJsonConverter_Tests.cs
  91. 122
      modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs
  92. 117
      modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/SystemTextJsonStringValueJsonConverter_Tests.cs
  93. 4
      nupkg/common.ps1

24
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<IJsonSerializerProvider>`)**: 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<string>`)**: 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<Action<JsonTypeInfo>>`)**: 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.

28
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}

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

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

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

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

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

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

21
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<MvcNewtonsoftJsonOptions>()
.Configure<AbpCamelCasePropertyNamesContractResolver>((options, contractResolver) =>
{
options.SerializerSettings.ContractResolver = contractResolver;
});
}
}

1
framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj

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

6
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs

@ -38,6 +38,7 @@ using Volo.Abp.GlobalFeatures;
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 class AbpAspNetCoreMvcModule : AbpModule
mvcCoreBuilder.AddAbpRazorRuntimeCompilation();
}
mvcCoreBuilder.AddAbpHybridJson();
mvcCoreBuilder.AddAbpJson();
context.Services.ExecutePreConfiguredActions(mvcBuilder);

11
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProviderOptions.cs

@ -62,19 +62,12 @@ public class 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;

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

@ -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<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
{
return await GetTextInputFormatter(context).ReadRequestBodyAsync(context, encoding);
}
protected virtual TextInputFormatter GetTextInputFormatter(InputFormatterContext context)
{
var typesMatcher = context.HttpContext.RequestServices.GetRequiredService<AbpSystemTextJsonUnsupportedTypeMatcher>();
if (!typesMatcher.Match(context.ModelType))
{
return _systemTextJsonInputFormatter;
}
return _newtonsoftJsonInputFormatter;
}
public virtual InputFormatterExceptionPolicy ExceptionPolicy => InputFormatterExceptionPolicy.MalformedInputExceptions;
}

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

@ -1,72 +0,0 @@
using System.Buffers;
using System.Text.Encodings.Web;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.ObjectPool;
using Microsoft.Extensions.Options;
namespace Volo.Abp.AspNetCore.Mvc.Json;
public class AbpHybridJsonOptionsSetup : IConfigureOptions<MvcOptions>
{
private readonly IOptions<JsonOptions> _jsonOptions;
private readonly IOptions<MvcNewtonsoftJsonOptions> _mvcNewtonsoftJsonOptions;
private readonly ILoggerFactory _loggerFactory;
private readonly ArrayPool<char> _charPool;
private readonly ObjectPoolProvider _objectPoolProvider;
public AbpHybridJsonOptionsSetup(
IOptions<JsonOptions> jsonOptions,
IOptions<MvcNewtonsoftJsonOptions> mvcNewtonsoftJsonOptions,
ILoggerFactory loggerFactory,
ArrayPool<char> charPool,
ObjectPoolProvider objectPoolProvider)
{
_jsonOptions = jsonOptions;
_mvcNewtonsoftJsonOptions = mvcNewtonsoftJsonOptions;
_loggerFactory = loggerFactory;
_charPool = charPool;
_objectPoolProvider = objectPoolProvider;
}
public void Configure(MvcOptions options)
{
var systemTextJsonInputFormatter = new SystemTextJsonInputFormatter(
_jsonOptions.Value,
_loggerFactory.CreateLogger<SystemTextJsonInputFormatter>());
var newtonsoftJsonInputFormatter = new NewtonsoftJsonInputFormatter(
_loggerFactory.CreateLogger<NewtonsoftJsonInputFormatter>(),
_mvcNewtonsoftJsonOptions.Value.SerializerSettings,
_charPool,
_objectPoolProvider,
options,
_mvcNewtonsoftJsonOptions.Value);
options.InputFormatters.RemoveType<SystemTextJsonInputFormatter>();
options.InputFormatters.RemoveType<NewtonsoftJsonInputFormatter>();
options.InputFormatters.Add(new AbpHybridJsonInputFormatter(systemTextJsonInputFormatter, newtonsoftJsonInputFormatter));
var jsonSerializerOptions = _jsonOptions.Value.JsonSerializerOptions;
if (jsonSerializerOptions.Encoder is null)
{
// If the user hasn't explicitly configured the encoder, use the less strict encoder that does not encode all non-ASCII characters.
jsonSerializerOptions = new JsonSerializerOptions(jsonSerializerOptions)
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
};
}
var systemTextJsonOutputFormatter = new SystemTextJsonOutputFormatter(jsonSerializerOptions);
var newtonsoftJsonOutputFormatter = new NewtonsoftJsonOutputFormatter(
_mvcNewtonsoftJsonOptions.Value.SerializerSettings,
_charPool,
options);
options.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>();
options.OutputFormatters.RemoveType<NewtonsoftJsonOutputFormatter>();
options.OutputFormatters.Add(new AbpHybridJsonOutputFormatter(systemTextJsonOutputFormatter, newtonsoftJsonOutputFormatter));
}
}

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

@ -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<AbpSystemTextJsonUnsupportedTypeMatcher>();
if (!typesMatcher.Match(context.ObjectType))
{
return _systemTextJsonOutputFormatter;
}
return _newtonsoftJsonOutputFormatter;
}
}

33
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpJsonOptionsSetup.cs

@ -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<JsonOptions>
{
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<AbpDateTimeConverter>());
options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService<AbpNullableDateTimeConverter>());
options.JsonSerializerOptions.Converters.Add(new AbpStringToEnumFactory());
options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter());
options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter());
}
}

48
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcJsonContractResolver.cs

@ -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<AbpJsonIsoDateTimeConverter> _dateTimeConverter;
public AbpMvcJsonContractResolver(IServiceProvider serviceProvider)
{
_dateTimeConverter = new Lazy<AbpJsonIsoDateTimeConverter>(
serviceProvider.GetRequiredService<AbpJsonIsoDateTimeConverter>,
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<DisableDateTimeNormalizationAttribute>(member) == null)
{
property.Converter = _dateTimeConverter.Value;
}
}
}

21
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/AbpMvcNewtonsoftJsonOptionsSetup.cs

@ -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<MvcNewtonsoftJsonOptions>
{
protected IServiceProvider ServiceProvider { get; }
public AbpMvcNewtonsoftJsonOptionsSetup(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}
public void Configure(MvcNewtonsoftJsonOptions options)
{
options.SerializerSettings.ContractResolver = ServiceProvider.GetRequiredService<AbpMvcJsonContractResolver>();
}
}

21
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MediaTypeHeaderValues.cs

@ -1,21 +0,0 @@
using Microsoft.Net.Http.Headers;
namespace Volo.Abp.AspNetCore.Mvc.Json;
/// <summary>
/// https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.NewtonsoftJson/src/MediaTypeHeaderValues.cs
/// </summary>
internal static class MediaTypeHeaderValues
{
public static readonly MediaTypeHeaderValue ApplicationJson = MediaTypeHeaderValue.Parse("application/json").CopyAsReadOnly();
public static readonly MediaTypeHeaderValue TextJson = MediaTypeHeaderValue.Parse("text/json").CopyAsReadOnly();
public static readonly MediaTypeHeaderValue ApplicationAnyJsonSyntax = MediaTypeHeaderValue.Parse("application/*+json").CopyAsReadOnly();
public static readonly MediaTypeHeaderValue ApplicationXml = MediaTypeHeaderValue.Parse("application/xml").CopyAsReadOnly();
public static readonly MediaTypeHeaderValue TextXml = MediaTypeHeaderValue.Parse("text/xml").CopyAsReadOnly();
public static readonly MediaTypeHeaderValue ApplicationAnyXmlSyntax = MediaTypeHeaderValue.Parse("application/*+xml").CopyAsReadOnly();
}

35
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<AbpJsonOptions>();
if (!abpJsonOptions.UseHybridSerializer)
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<MvcNewtonsoftJsonOptions>, AbpMvcNewtonsoftJsonOptionsSetup>());
builder.AddNewtonsoftJson();
return builder;
}
builder.Services.AddOptions<JsonOptions>()
.Configure<IServiceProvider>((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<IOptions<AbpSystemTextJsonSerializerModifiersOptions>>());
});
builder.Services.TryAddTransient<DefaultObjectPoolProvider>();
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<JsonOptions>, AbpJsonOptionsSetup>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<MvcNewtonsoftJsonOptions>, AbpMvcNewtonsoftJsonOptionsSetup>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, AbpHybridJsonOptionsSetup>());
return builder;
}
}

2
framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs

@ -40,7 +40,7 @@ public abstract class AbpAspNetCoreIntegratedTestBase<TStartup> : AbpTestBaseWit
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<TStartup>();
webBuilder.UseTestServer();
webBuilder.UseAbpTestServer();
})
.UseAutofac()
.ConfigureServices(ConfigureServices);

18
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;
}
}

19
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<IHostLifetime, AbpNoopHostLifetime>();
services.AddScoped<IServer, TestServer>();
});
}
}

42
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingContractResolver.cs

@ -1,42 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace Volo.Abp.Auditing;
public class AuditingContractResolver : CamelCasePropertyNamesContractResolver
{
private readonly List<Type> _ignoredTypes;
public AuditingContractResolver(List<Type> ignoredTypes)
{
_ignoredTypes = ignoredTypes;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (_ignoredTypes.Any(ignoredType => ignoredType.GetTypeInfo().IsAssignableFrom(property.PropertyType)))
{
property.ShouldSerialize = instance => false;
return property;
}
if (member.DeclaringType != null && (member.DeclaringType.IsDefined(typeof(DisableAuditingAttribute)) || member.DeclaringType.IsDefined(typeof(JsonIgnoreAttribute))))
{
property.ShouldSerialize = instance => false;
return property;
}
if (member.IsDefined(typeof(DisableAuditingAttribute)) || member.IsDefined(typeof(JsonIgnoreAttribute)))
{
property.ShouldSerialize = instance => false;
}
return property;
}
}

77
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<AbpAuditingOptions> options)
{
Options = options.Value;
}
public string Serialize(object obj)
{
return JsonSerializer.Serialize(obj, CreateJsonSerializerOptions());
}
private static readonly ConcurrentDictionary<string, JsonSerializerOptions> JsonSerializerOptionsCache =
new ConcurrentDictionary<string, JsonSerializerOptions>();
protected virtual JsonSerializerOptions CreateJsonSerializerOptions()
{
return JsonSerializerOptionsCache.GetOrAdd(nameof(JsonAuditSerializer), _ =>
{
var settings = new JsonSerializerOptions()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
{
Modifiers =
{
jsonTypeInfo =>
{
if (Options.IgnoredTypes.Any(ignoredType => ignoredType.IsAssignableFrom(jsonTypeInfo.Type)) ||
jsonTypeInfo.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;
});
}
}

43
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/JsonNetAuditSerializer.cs

@ -1,43 +0,0 @@
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Auditing;
//TODO: Rename to JsonAuditSerializer
public class JsonNetAuditSerializer : IAuditSerializer, ITransientDependency
{
protected AbpAuditingOptions Options;
public JsonNetAuditSerializer(IOptions<AbpAuditingOptions> options)
{
Options = options.Value;
}
public string Serialize(object obj)
{
return JsonConvert.SerializeObject(obj, GetSharedJsonSerializerSettings());
}
private static readonly object SyncObj = new object();
private static JsonSerializerSettings _sharedJsonSerializerSettings;
private JsonSerializerSettings GetSharedJsonSerializerSettings()
{
if (_sharedJsonSerializerSettings == null)
{
lock (SyncObj)
{
if (_sharedJsonSerializerSettings == null)
{
_sharedJsonSerializerSettings = new JsonSerializerSettings
{
ContractResolver = new AuditingContractResolver(Options.IgnoredTypes)
};
}
}
}
return _sharedJsonSerializerSettings;
}
}

1
framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj

@ -30,5 +30,6 @@
<ProjectReference Include="..\Volo.Abp.Http\Volo.Abp.Http.csproj" />
<ProjectReference Include="..\Volo.Abp.IdentityModel\Volo.Abp.IdentityModel.csproj" />
<ProjectReference Include="..\Volo.Abp.Json\Volo.Abp.Json.csproj" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>

8
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 class AbpCliCoreModule : AbpModule
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Configure<AbpSystemTextJsonSerializerOptions>(options =>
{
options.UnsupportedTypes.Add(typeof(ResourceMapping));
});
Configure<AbpCliOptions>(options =>
{
options.Commands[HelpCommand.Name] = typeof(HelpCommand);

11
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/LIbs/InstallLibsService.cs

@ -7,6 +7,7 @@ using Microsoft.Extensions.FileSystemGlobbing;
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<InstallLibsService> 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 @@ public class InstallLibsService : IInstallLibsService, ITransientDependency
{
return false;
}
using (var reader = File.OpenText(file))
{
return reader.ReadToEnd().Contains("Microsoft.NET.Sdk.Web");
@ -145,7 +143,8 @@ public class InstallLibsService : IInstallLibsService, ITransientDependency
{
var mappingFileContent = await reader.ReadToEndAsync();
var mapping = _jsonSerializer.Deserialize<ResourceMapping>(mappingFileContent
// System.Text.Json doesn't support the property name without quotes.
var mapping = Newtonsoft.Json.JsonConvert.DeserializeObject<ResourceMapping>(mappingFileContent
.Replace("module.exports", string.Empty)
.Replace("=", string.Empty).Trim().TrimEnd(';'));

18
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<System.Text.Json.Serialization.JsonPropertyNameAttribute>(true);
if (jsonPropertyNameAttribute != null)
{
return jsonPropertyNameAttribute.Name;
}
var jsonPropertyAttribute = propertyInfo.GetSingleAttributeOrNull<Newtonsoft.Json.JsonPropertyAttribute>(true);
if (jsonPropertyAttribute != null)
{
return jsonPropertyAttribute.PropertyName;
}
return null;
};
propertyInfo.GetSingleAttributeOrNull<System.Text.Json.Serialization.JsonPropertyNameAttribute>()?.Name;
}
}

3
framework/src/Volo.Abp.Json.Abstractions/FodyWeavers.xml

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

30
framework/src/Volo.Abp.Json.Abstractions/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

20
framework/src/Volo.Abp.Json.Abstractions/Volo.Abp.Json.Abstractions.csproj

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageId>Volo.Abp.Json.Abstractions</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Core\Volo.Abp.Core.csproj" />
</ItemGroup>
</Project>

8
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
{
}

21
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
{
/// <summary>
/// Formats of input JSON date, Empty string means default format.
/// </summary>
public List<string> InputDateTimeFormats { get; set; }
/// <summary>
/// Format of output json date, Null or empty string means default format.
/// </summary>
public string OutputDateTimeFormat { get; set; }
public AbpJsonOptions()
{
InputDateTimeFormats = new List<string>();
}
}

0
framework/src/Volo.Abp.Json/Volo/Abp/Json/IJsonSerializer.cs → framework/src/Volo.Abp.Json.Abstractions/Volo/Abp/Json/IJsonSerializer.cs

3
framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xml

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

30
framework/src/Volo.Abp.Json.Newtonsoft/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

23
framework/src/Volo.Abp.Json.Newtonsoft/Volo.Abp.Json.Newtonsoft.csproj

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.Json.Newtonsoft</AssemblyName>
<PackageId>Volo.Abp.Json.Newtonsoft</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Json.Abstractions\Volo.Abp.Json.Abstractions.csproj" />
<ProjectReference Include="..\Volo.Abp.Timing\Volo.Abp.Timing.csproj" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>

38
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<AbpDateTimeConverter> _dateTimeConverter;
public AbpCamelCasePropertyNamesContractResolver(IServiceProvider serviceProvider)
{
_dateTimeConverter = new Lazy<AbpDateTimeConverter>(
serviceProvider.GetRequiredService<AbpDateTimeConverter>,
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;
}
}

116
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<AbpJsonOptions> 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<DateTime>());
}
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<DateTime>());
}
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<DisableDateTimeNormalizationAttribute>(member) == null;
}
}

33
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<AbpDateTimeConverter> _dateTimeConverter;
public AbpDefaultContractResolver(IServiceProvider serviceProvider)
{
_dateTimeConverter = new Lazy<AbpDateTimeConverter>(
serviceProvider.GetRequiredService<AbpDateTimeConverter>,
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;
}
}

18
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<AbpNewtonsoftJsonSerializerOptions>()
.Configure<AbpCamelCasePropertyNamesContractResolver>((options, contractResolver) =>
{
options.JsonSerializerSettings.ContractResolver = contractResolver;
});
}
}

96
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<AbpNewtonsoftJsonSerializerOptions> Options { get; }
public AbpNewtonsoftJsonSerializer(IServiceProvider serviceProvider, IOptions<AbpNewtonsoftJsonSerializerOptions> 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<T>(string jsonString, bool camelCase = true)
{
return JsonConvert.DeserializeObject<T>(jsonString, CreateJsonSerializerOptions(camelCase));
}
public object Deserialize(Type type, string jsonString, bool camelCase = true)
{
return JsonConvert.DeserializeObject(jsonString, type, CreateJsonSerializerOptions(camelCase));
}
private static readonly ConcurrentDictionary<object, JsonSerializerSettings> JsonSerializerOptionsCache =
new ConcurrentDictionary<object, JsonSerializerSettings>();
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<AbpCamelCasePropertyNamesContractResolver>()
: ServiceProvider.GetRequiredService<AbpDefaultContractResolver>();
if (indented)
{
settings.Formatting = Formatting.Indented;
}
return settings;
});
}
}

5
framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs → 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<JsonConverter> Converters { get; }
public JsonSerializerSettings JsonSerializerSettings { get; }
public AbpNewtonsoftJsonSerializerOptions()
{
Converters = new TypeList<JsonConverter>();
JsonSerializerSettings = new JsonSerializerSettings();
}
}

3
framework/src/Volo.Abp.Json.SystemTextJson/FodyWeavers.xml

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

30
framework/src/Volo.Abp.Json.SystemTextJson/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

23
framework/src/Volo.Abp.Json.SystemTextJson/Volo.Abp.Json.SystemTextJson.csproj

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.Json.SystemTextJson</AssemblyName>
<PackageId>Volo.Abp.Json.SystemTextJson</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Json.Abstractions\Volo.Abp.Json.Abstractions.csproj" />
<ProjectReference Include="..\Volo.Abp.Timing\Volo.Abp.Timing.csproj" />
<PackageReference Include="System.Text.Json" Version="$(MicrosoftAspNetCorePackageVersion)" />
</ItemGroup>
</Project>

16
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<AbpSystemTextJsonSerializerModifiersOptions> options)
{
foreach (var modifier in options.Value.Modifiers)
{
Modifiers.Add(modifier);
}
}
}

37
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<AbpSystemTextJsonSerializerOptions>()
.Configure<IServiceProvider>((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<IOptions<AbpSystemTextJsonSerializerModifiersOptions>>());
});
context.Services.AddOptions<AbpSystemTextJsonSerializerModifiersOptions>()
.Configure<IServiceProvider>((options, serviceProvider) =>
{
options.Modifiers.Add(new AbpDateTimeConverterModifier().CreateModifyAction(serviceProvider));
});
}
}

17
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerProvider.cs → framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializer.cs

@ -6,25 +6,15 @@ using Volo.Abp.DependencyInjection;
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<AbpSystemTextJsonSerializerOptions> options,
AbpSystemTextJsonUnsupportedTypeMatcher abpSystemTextJsonUnsupportedTypeMatcher)
public AbpSystemTextJsonSerializer(IOptions<AbpSystemTextJsonSerializerOptions> 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 class AbpSystemTextJsonSerializerProvider : IJsonSerializerProvider, ITra
return JsonSerializer.Deserialize(jsonString, type, CreateJsonSerializerOptions(camelCase));
}
private readonly static ConcurrentDictionary<object, JsonSerializerOptions> JsonSerializerOptionsCache = new ConcurrentDictionary<object, JsonSerializerOptions>();
private static readonly ConcurrentDictionary<object, JsonSerializerOptions> JsonSerializerOptionsCache =
new ConcurrentDictionary<object, JsonSerializerOptions>();
protected virtual JsonSerializerOptions CreateJsonSerializerOptions(bool camelCase = true, bool indented = false)
{

20
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<Action<JsonTypeInfo>> Modifiers { get; }
public AbpSystemTextJsonSerializerModifiersOptions()
{
Modifiers = new List<Action<JsonTypeInfo>>
{
AbpIncludeExtraPropertiesModifiers.Modify,
};
}
}

4
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptions.cs → 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 class AbpSystemTextJsonSerializerOptions
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true
};
UnsupportedTypes = new TypeList();
}
}

28
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpDateTimeConverter.cs → 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 class AbpDateTimeConverter : JsonConverter<DateTime>, ITransientDependenc
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 class AbpDateTimeConverter : JsonConverter<DateTime>, ITransientDependenc
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));
}
}
}

24
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableDateTimeConverter.cs → 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 class AbpNullableDateTimeConverter : JsonConverter<DateTime?>, ITransient
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 class AbpNullableDateTimeConverter : JsonConverter<DateTime?>, ITransient
}
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));
}
}
}

0
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs → framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToBooleanConverter.cs

0
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs → framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumConverter.cs

0
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumFactory.cs → framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToEnumFactory.cs

0
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs → framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/ObjectToInferredTypesConverter.cs

39
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<JsonTypeInfo> CreateModifyAction(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
return Modify;
}
private void Modify(JsonTypeInfo jsonTypeInfo)
{
if (ReflectionHelper.GetAttributesOfMemberOrDeclaringType<DisableDateTimeNormalizationAttribute>(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<AbpDateTimeConverter>()
: _serviceProvider.GetRequiredService<AbpNullableDateTimeConverter>();
}
}
}
}

29
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<TClass, TProperty>
where TClass : class
{
private Expression<Func<TClass, TProperty>> _propertySelector;
public Action<JsonTypeInfo> CreateModifyAction(Expression<Func<TClass, TProperty>> 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<MemberExpression>().Member.Name);
}
}
}

29
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<MemberInfo>().Name == nameof(ExtensibleObject.ExtraProperties) &&
x.Set == null);
if (propertyJsonInfo != null)
{
propertyJsonInfo.Set = (extraProperties, value) =>
{
ObjectHelper.TrySetProperty(extraProperties.As<ExtensibleObject>(), x => x.ExtraProperties, () => (ExtraPropertyDictionary)value);
};
}
}
}

43
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<TClass, TProperty>
where TClass : class
{
private Expression<Func<TClass, TProperty>> _propertySelector;
public Action<JsonTypeInfo> CreateModifyAction(Expression<Func<TClass, TProperty>> propertySelector)
{
_propertySelector = propertySelector;
return Modify;
}
public void Modify(JsonTypeInfo jsonTypeInfo)
{
if (jsonTypeInfo.Type == typeof(TClass))
{
var propertyName = _propertySelector.Body.As<MemberExpression>().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);
}
}
}
}
}

4
framework/src/Volo.Abp.Json/Volo.Abp.Json.csproj

@ -15,9 +15,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Timing\Volo.Abp.Timing.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.ObjectExtending\Volo.Abp.ObjectExtending.csproj" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<ProjectReference Include="..\Volo.Abp.Json.SystemTextJson\Volo.Abp.Json.SystemTextJson.csproj" />
</ItemGroup>
</Project>

66
framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpHybridJsonSerializer.cs

@ -1,66 +0,0 @@
using System;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Json;
public class AbpHybridJsonSerializer : IJsonSerializer, ITransientDependency
{
protected AbpJsonOptions Options { get; }
protected IServiceScopeFactory ServiceScopeFactory { get; }
public AbpHybridJsonSerializer(IOptions<AbpJsonOptions> options, IServiceScopeFactory serviceScopeFactory)
{
Options = options.Value;
ServiceScopeFactory = serviceScopeFactory;
}
public string Serialize([CanBeNull] object obj, bool camelCase = true, bool indented = false)
{
using (var scope = ServiceScopeFactory.CreateScope())
{
var serializerProvider = GetSerializerProvider(scope.ServiceProvider, obj?.GetType());
return serializerProvider.Serialize(obj, camelCase, indented);
}
}
public T Deserialize<T>([NotNull] string jsonString, bool camelCase = true)
{
Check.NotNull(jsonString, nameof(jsonString));
using (var scope = ServiceScopeFactory.CreateScope())
{
var serializerProvider = GetSerializerProvider(scope.ServiceProvider, typeof(T));
return serializerProvider.Deserialize<T>(jsonString, camelCase);
}
}
public object Deserialize(Type type, [NotNull] string jsonString, bool camelCase = true)
{
Check.NotNull(jsonString, nameof(jsonString));
using (var scope = ServiceScopeFactory.CreateScope())
{
var serializerProvider = GetSerializerProvider(scope.ServiceProvider, type);
return serializerProvider.Deserialize(type, jsonString, camelCase);
}
}
protected virtual IJsonSerializerProvider GetSerializerProvider(IServiceProvider serviceProvider, [CanBeNull] Type type)
{
foreach (var providerType in Options.Providers.Reverse())
{
var provider = serviceProvider.GetRequiredService(providerType) as IJsonSerializerProvider;
if (provider.CanHandle(type))
{
return provider;
}
}
throw new AbpException($"There is no IJsonSerializerProvider that can handle '{type.GetFullNameWithAssemblyName()}'!");
}
}

28
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<IConfigureOptions<AbpSystemTextJsonSerializerOptions>, AbpSystemTextJsonSerializerOptionsSetup>());
var preActions = context.Services.GetPreConfigureActions<AbpJsonOptions>();
Configure<AbpJsonOptions>(options =>
{
options.Providers.Add<AbpNewtonsoftJsonSerializerProvider>();
if (preActions.Configure().UseHybridSerializer)
{
options.Providers.Add<AbpSystemTextJsonSerializerProvider>();
}
});
Configure<AbpNewtonsoftJsonSerializerOptions>(options =>
{
options.Converters.Add<AbpJsonIsoDateTimeConverter>();
});
}
}

27
framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonOptions.cs

@ -1,27 +0,0 @@
using Volo.Abp.Collections;
using Volo.Abp.Json.SystemTextJson;
namespace Volo.Abp.Json;
public class AbpJsonOptions
{
/// <summary>
/// Used to set default value for the DateTimeFormat.
/// </summary>
public string DefaultDateTimeFormat { get; set; }
/// <summary>
/// It will try to use System.Json.Text to handle JSON if it can otherwise use Newtonsoft.
/// Affects both AbpJsonModule and AbpAspNetCoreMvcModule.
/// See <see cref="AbpSystemTextJsonUnsupportedTypeMatcher"/>
/// </summary>
public bool UseHybridSerializer { get; set; }
public ITypeList<IJsonSerializerProvider> Providers { get; }
public AbpJsonOptions()
{
Providers = new TypeList<IJsonSerializerProvider>();
UseHybridSerializer = true;
}
}

15
framework/src/Volo.Abp.Json/Volo/Abp/Json/IJsonSerializerProvider.cs

@ -1,15 +0,0 @@
using System;
using JetBrains.Annotations;
namespace Volo.Abp.Json;
public interface IJsonSerializerProvider
{
bool CanHandle([CanBeNull] Type type);
string Serialize(object obj, bool camelCase = true, bool indented = false);
T Deserialize<T>(string jsonString, bool camelCase = true);
object Deserialize(Type type, string jsonString, bool camelCase = true);
}

51
framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpJsonIsoDateTimeConverter.cs

@ -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> 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);
}
}

79
framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerProvider.cs

@ -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<JsonConverter> Converters { get; }
public AbpNewtonsoftJsonSerializerProvider(
IOptions<AbpNewtonsoftJsonSerializerOptions> 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<T>(string jsonString, bool camelCase = true)
{
return JsonConvert.DeserializeObject<T>(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;
}
}
}

32
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonSerializerOptionsSetup.cs

@ -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<AbpSystemTextJsonSerializerOptions>
{
protected IServiceProvider ServiceProvider { get; }
public AbpSystemTextJsonSerializerOptionsSetup(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}
public void Configure(AbpSystemTextJsonSerializerOptions options)
{
options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService<AbpDateTimeConverter>());
options.JsonSerializerOptions.Converters.Add(ServiceProvider.GetRequiredService<AbpNullableDateTimeConverter>());
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;
}
}

21
framework/src/Volo.Abp.Json/Volo/Abp/Json/SystemTextJson/AbpSystemTextJsonUnsupportedTypeMatcher.cs

@ -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<AbpSystemTextJsonSerializerOptions> options)
{
Options = options.Value;
}
public virtual bool Match([CanBeNull] Type type)
{
return Options.UnsupportedTypes.Contains(type);
}
}

2
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()

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

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

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

@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Mvc.Razor;
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;

2
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonResultController_Tests.cs

@ -14,7 +14,7 @@ public class JsonResultController_Tests : AspNetCoreMvcTestBase
{
services.Configure<AbpJsonOptions>(options =>
{
options.DefaultDateTimeFormat = "yyyy*MM*dd";
options.OutputDateTimeFormat = "yyyy*MM*dd";
});
base.ConfigureServices(context, services);

2
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Json/JsonSerializer_Tests.cs

@ -21,7 +21,7 @@ public class JsonSerializer_Tests : AspNetCoreMvcTestBase
{
services.Configure<AbpJsonOptions>(options =>
{
options.DefaultDateTimeFormat = "yyyy*MM*dd";
options.OutputDateTimeFormat = "yyyy*MM*dd";
});
base.ConfigureServices(context, services);

10
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs

@ -6,6 +6,7 @@ using System.Text.Json;
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<AbpSystemTextJsonSerializerOptions>(options =>
{
options.UnsupportedTypes.Add<GetDateTimeKindModel>();
options.UnsupportedTypes.Add<GetDateTimeKindModel.GetDateTimeKindInnerModel>();
});
}
[Fact]
public async Task DateTimeKind_Test()
{

33
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 class Startup
services.AddApplication<AbpAspNetCoreMvcTestModule>(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);
});

7
framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/JsonNetAuditSerializer_Test.cs → 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 class JsonNetAuditSerializer_Test : AbpAuditingTestBase
{"input2", new Input2Dto {UserName = "admin", Password = "1q2w3E*", Birthday = DateTime.Now}}
};
var str = GetRequiredService<JsonNetAuditSerializer>().Serialize(arguments);
var str = GetRequiredService<JsonAuditSerializer>().Serialize(arguments);
str.ShouldNotContain("IdCard");
str.ShouldNotContain("1q2w3E*");
@ -51,7 +52,7 @@ public class JsonNetAuditSerializer_Test : AbpAuditingTestBase
[DisableAuditing]
public string Password { get; set; }
[Newtonsoft.Json.JsonIgnore]
[JsonIgnore]
public string PrivateEmail { get; set; }
public DateTime Birthday { get; set; }

149
framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpHybridJsonSerializer_Tests.cs

@ -1,149 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Shouldly;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json.Newtonsoft;
using Volo.Abp.Json.SystemTextJson;
using Xunit;
using JsonSerializer = Newtonsoft.Json.JsonSerializer;
namespace Volo.Abp.Json;
public class AbpHybridJsonSerializer_Tests : AbpJsonTestBase
{
private readonly IJsonSerializer _jsonSerializer;
public AbpHybridJsonSerializer_Tests()
{
_jsonSerializer = GetRequiredService<IJsonSerializer>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
services.Configure<AbpSystemTextJsonSerializerOptions>(options =>
{
options.UnsupportedTypes.Add<MyClass1>();
options.JsonSerializerOptions.Converters.Add(new SystemTextJsonConverter());
});
services.Configure<AbpNewtonsoftJsonSerializerOptions>(options =>
{
options.Converters.Add<NewtonsoftJsonConverter>();
});
}
[Fact]
public void NewtonsoftSerialize_Test()
{
var json = _jsonSerializer.Serialize(new MyClass1
{
Providers = new List<MyClass3>
{
new MyClass3()
}
});
json.ShouldContain("Newtonsoft");
}
[Fact]
public void SystemTextJsonSerialize_Test()
{
var json = _jsonSerializer.Serialize(new MyClass2
{
Providers = new List<MyClass3>
{
new MyClass3()
}
});
json.ShouldContain("SystemTextJson");
}
[Fact]
public void SystemTextJsonSerialize_With_Dictionary_Test()
{
var json = _jsonSerializer.Serialize(new MyClassWithDictionary
{
Properties =
{
{"A", "AV"},
{"B", "BV"}
}
});
var deserialized = _jsonSerializer.Deserialize<MyClassWithDictionary>(json);
deserialized.Properties.ShouldContain(p => p.Key == "A" && p.Value == "AV");
deserialized.Properties.ShouldContain(p => p.Key == "B" && p.Value == "BV");
}
public class MyClass1
{
public string Provider { get; set; }
public List<MyClass3> Providers { get; set; }
}
public class MyClass2
{
public string Provider { get; set; }
public List<MyClass3> Providers { get; set; }
}
public class MyClass3
{
public string Provider { get; set; }
}
public class MyClassWithDictionary
{
public Dictionary<string, string> Properties { get; set; }
public MyClassWithDictionary()
{
Properties = new Dictionary<string, string>();
}
}
class NewtonsoftJsonConverter : JsonConverter<MyClass1>, ITransientDependency
{
public override void WriteJson(JsonWriter writer, MyClass1 value, JsonSerializer serializer)
{
value.Provider = "Newtonsoft";
foreach (var provider in value.Providers)
{
provider.Provider = "Newtonsoft";
}
writer.WriteRawValue(JsonConvert.SerializeObject(value));
}
public override MyClass1 ReadJson(JsonReader reader, Type objectType, MyClass1 existingValue, bool hasExistingValue, JsonSerializer serializer)
{
return (MyClass1)serializer.Deserialize(reader, objectType);
}
}
class SystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter<MyClass2>, ITransientDependency
{
public override void Write(Utf8JsonWriter writer, MyClass2 value, JsonSerializerOptions options)
{
value.Provider = "SystemTextJson";
foreach (var provider in value.Providers)
{
provider.Provider = "SystemTextJson";
}
System.Text.Json.JsonSerializer.Serialize(writer, value);
}
public override MyClass2 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return (MyClass2)System.Text.Json.JsonSerializer.Deserialize(ref reader, typeToConvert);
}
}
}

73
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<IJsonSerializer>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
services.Configure<AbpSystemTextJsonSerializerModifiersOptions>(options =>
{
options.Modifiers.Add(new AbpIgnorePropertiesModifiers<FooDto, List<BarDto>>().CreateModifyAction(x => x.BarDtos));
options.Modifiers.Add(new AbpIgnorePropertiesModifiers<BarDto, string>().CreateModifyAction(x => x.Id));
});
base.AfterAddApplication(services);
}
[Fact]
public void Test()
{
var json = _jsonSerializer.Serialize(new FooDto()
{
Name = "foo",
BarDtos = new List<BarDto>
{
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<BarDto> BarDtos { get; set; }
}
class BarDto
{
public string Id { get; set; }
public string Name { get; set; }
}
}

61
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<IJsonSerializer>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
services.Configure<AbpSystemTextJsonSerializerModifiersOptions>(options =>
{
options.Modifiers.Add(new AbpIncludeNonPublicPropertiesModifiers<NonPublicPropertiesClass, string>().CreateModifyAction(x => x.Name));
options.Modifiers.Add(new AbpIncludeNonPublicPropertiesModifiers<NonPublicPropertiesClass, string>().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<NonPublicPropertiesClass>(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";
}
}
}

23
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<AbpSystemTextJsonSerializerProvider>();
JsonSerializer = GetRequiredService<AbpSystemTextJsonSerializer>();
}
public class TestExtensibleObjectClass : ExtensibleObject
@ -220,7 +220,8 @@ public class AbpSystemTextJsonSerializerProvider_DateTimeFormat_Tests : AbpSyste
{
services.Configure<AbpJsonOptions>(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 class AbpSystemTextJsonSerializerProvider_DateTimeFormat_Tests : AbpSyste
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 class AbpSystemTextJsonSerializerProvider_DateTimeFormat_Tests : AbpSyste
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\"");
}
}

65
framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpSystemTextJsonUnsupportedTypeMatcher_Tests.cs

@ -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<AbpSystemTextJsonUnsupportedTypeMatcher>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
services.Configure<AbpSystemTextJsonSerializerOptions>(options =>
{
options.UnsupportedTypes.Add<MyClass>();
options.UnsupportedTypes.Add<byte[]>();
options.UnsupportedTypes.Add<Dictionary<string, MyClass4>>();
});
}
[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<string, MyClass4>)).ShouldBeTrue();
_abpSystemTextJsonUnsupportedTypeMatcher.Match(typeof(IDictionary<string, MyClass4>)).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; }
}
}

19
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<AbpSystemTextJsonSerializer>();
var extensibleObject = jsonSerializer.Deserialize<ExtensibleObject>("{\"ExtraProperties\": {\"Test-Key\":\"Test-Value\"}}");
extensibleObject.ExtraProperties.ShouldContainKeyAndValue("Test-Key", "Test-Value");
}
}

2
framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/ExtensibleObject_Tests.cs

@ -7,7 +7,7 @@ using Xunit;
namespace Volo.Abp.Json;
public class ExtensibleObject_Tests: AbpJsonTestBase
public class ExtensibleObject_Tests : AbpJsonTestBase
{
private readonly IJsonSerializer _jsonSerializer;

2
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs

@ -21,4 +21,4 @@ public class AbpFeatureManagementApplicationContractsModule : AbpModule
options.FileSets.AddEmbedded<AbpFeatureManagementApplicationContractsModule>();
});
}
}
}

2
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo.Abp.FeatureManagement.Domain.Shared.csproj

@ -16,7 +16,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="$(MicrosoftPackageVersion)" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Json\Volo.Abp.Json.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Json.SystemTextJson\Volo.Abp.Json.SystemTextJson.csproj" />
</ItemGroup>
<ItemGroup>

13
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 class AbpFeatureManagementDomainSharedModule : AbpModule
options.MapCodeNamespace("Volo.Abp.FeatureManagement", typeof(AbpFeatureManagementResource));
});
Configure<AbpNewtonsoftJsonSerializerOptions>(options =>
{
options.Converters.Add<NewtonsoftStringValueTypeJsonConverter>();
});
var valueValidatorFactoryOptions = context.Services.GetPreConfigureActions<ValueValidatorFactoryOptions>();
Configure<ValueValidatorFactoryOptions>(options =>
{

95
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/JsonConverters/NewtonsoftStringValueTypeJsonConverter.cs

@ -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<ValueValidatorFactoryOptions> 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<Dictionary<string, object>>(
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<Dictionary<string, object>>(
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!");
}
}

2
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;

15
modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/NewtonsoftStringValueJsonConverter_Tests.cs

@ -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<AbpJsonOptions>(options =>
{
options.UseHybridSerializer = false;
});
}
}

122
modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs

@ -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<IJsonSerializer>();
}
protected override void BeforeAddApplication(IServiceCollection services)
{
services.PreConfigure<ValueValidatorFactoryOptions>(options =>
{
options.ValueValidatorFactory.Add(new ValueValidatorFactory<UrlValueValidator>("URL"));
});
base.BeforeAddApplication(services);
}
[Fact]
public void Should_Serialize_And_Deserialize()
{
var featureListDto = new GetFeatureListResultDto
{
Groups = new List<FeatureGroupDto>
{
new FeatureGroupDto
{
Name = "MyGroup",
DisplayName = "MyGroup",
Features = new List<FeatureDto>
{
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<GetFeatureListResultDto>(serialized);
featureListDto2.ShouldNotBeNull();
featureListDto2.Groups[0].Features[0].ValueType.ShouldBeOfType<FreeTextStringValueType>();
featureListDto2.Groups[0].Features[0].ValueType.Validator.ShouldBeOfType<BooleanValueValidator>();
featureListDto2.Groups[0].Features[1].ValueType.ShouldBeOfType<SelectionStringValueType>();
featureListDto2.Groups[0].Features[1].ValueType.Validator.ShouldBeOfType<AlwaysValidValueValidator>();
featureListDto2.Groups[0].Features[1].ValueType.As<SelectionStringValueType>().ItemSource.Items.ShouldBeOfType<LocalizableSelectionStringValueItem[]>();
featureListDto2.Groups[0].Features[1].ValueType.As<SelectionStringValueType>().ItemSource.Items.ShouldContain(x =>
x.Value == "TestValue" && x.DisplayText.ResourceName == "TestResourceName" &&
x.DisplayText.Name == "TestName");
featureListDto2.Groups[0].Features[2].ValueType.ShouldBeOfType<ToggleStringValueType>();
featureListDto2.Groups[0].Features[2].ValueType.Validator.ShouldBeOfType<NumericValueValidator>();
featureListDto2.Groups[0].Features[2].ValueType.Validator.As<NumericValueValidator>().MaxValue.ShouldBe(1000);
featureListDto2.Groups[0].Features[2].ValueType.Validator.As<NumericValueValidator>().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<FreeTextStringValueType>();
featureListDto2.Groups[0].Features[4].ValueType.Validator.ShouldBeOfType<UrlValueValidator>();
featureListDto2.Groups[0].Features[4].ValueType.Validator.As<UrlValueValidator>().Scheme.ShouldBe("https");
}
}

117
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<IJsonSerializer>();
}
protected override void BeforeAddApplication(IServiceCollection services)
{
services.PreConfigure<AbpJsonOptions>(options =>
services.PreConfigure<ValueValidatorFactoryOptions>(options =>
{
options.UseHybridSerializer = true;
options.ValueValidatorFactory.Add(new ValueValidatorFactory<UrlValueValidator>("URL"));
});
base.BeforeAddApplication(services);
}
[Fact]
public void Should_Serialize_And_Deserialize()
{
var featureListDto = new GetFeatureListResultDto
{
Groups = new List<FeatureGroupDto>
{
new FeatureGroupDto
{
Name = "MyGroup",
DisplayName = "MyGroup",
Features = new List<FeatureDto>
{
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<GetFeatureListResultDto>(serialized);
featureListDto2.ShouldNotBeNull();
featureListDto2.Groups[0].Features[0].ValueType.ShouldBeOfType<FreeTextStringValueType>();
featureListDto2.Groups[0].Features[0].ValueType.Validator.ShouldBeOfType<BooleanValueValidator>();
featureListDto2.Groups[0].Features[1].ValueType.ShouldBeOfType<SelectionStringValueType>();
featureListDto2.Groups[0].Features[1].ValueType.Validator.ShouldBeOfType<AlwaysValidValueValidator>();
featureListDto2.Groups[0].Features[1].ValueType.As<SelectionStringValueType>().ItemSource.Items.ShouldBeOfType<LocalizableSelectionStringValueItem[]>();
featureListDto2.Groups[0].Features[1].ValueType.As<SelectionStringValueType>().ItemSource.Items.ShouldContain(x =>
x.Value == "TestValue" && x.DisplayText.ResourceName == "TestResourceName" &&
x.DisplayText.Name == "TestName");
featureListDto2.Groups[0].Features[2].ValueType.ShouldBeOfType<ToggleStringValueType>();
featureListDto2.Groups[0].Features[2].ValueType.Validator.ShouldBeOfType<NumericValueValidator>();
featureListDto2.Groups[0].Features[2].ValueType.Validator.As<NumericValueValidator>().MaxValue.ShouldBe(1000);
featureListDto2.Groups[0].Features[2].ValueType.Validator.As<NumericValueValidator>().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<FreeTextStringValueType>();
featureListDto2.Groups[0].Features[4].ValueType.Validator.ShouldBeOfType<UrlValueValidator>();
featureListDto2.Groups[0].Features[4].ValueType.Validator.As<UrlValueValidator>().Scheme.ShouldBe("https");
}
}

4
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",

Loading…
Cancel
Save