Browse Source

Merge branch 'dev' into ICancellationTokenProvider

pull/20917/head
maliming 2 years ago
parent
commit
878dce1204
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 2
      .github/workflows/build-and-test.yml
  2. 121
      Directory.Packages.props
  3. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalization.csproj
  4. 2
      docs/en/Community-Articles/2023-11-16-Upgrading-Your-Existing-Projects-to-NET8/POST.md
  5. 136
      docs/en/deployment/ssl.md
  6. 2
      docs/en/framework/architecture/modularity/basics.md
  7. 8
      docs/en/framework/fundamentals/dynamic-claims.md
  8. 6
      docs/en/get-started/console.md
  9. 6
      docs/en/get-started/wpf.md
  10. 32
      docs/en/guides/ms-multi-tenant-domain-resolving.md
  11. BIN
      docs/en/images/pen-test-alert-list-8.3.png
  12. 120
      docs/en/others/penetration-test-report.md
  13. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-entity-framework-core-migration-dialog.png
  14. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-entity-framework-core-migration.png
  15. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-new-dd-module.png
  16. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-new-ddd-module.png
  17. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-new-empty-module.png
  18. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-new-folder-command.png
  19. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-new-package.png
  20. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-2.png
  21. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-3.png
  22. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-4.png
  23. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-5.png
  24. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-6.png
  25. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-7.png
  26. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-dialog-5.png
  27. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-dialog-6.png
  28. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference.png
  29. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-added-ddd-contracts-package.png
  30. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-build-and-restart-application.png
  31. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-entity-framework-core-add-migration-order.png
  32. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-entity-framework-core-update-database.png
  33. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-graph-build.png
  34. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-import-module-for-ordering.png
  35. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-import-module-ordering.png
  36. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-import-module.png
  37. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-new-folder-dialog.png
  38. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-open-in-explorer.png
  39. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-open-with-visual-studio-main-app.png
  40. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-open-with-visual-studio.png
  41. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-ordering-swagger-ui-in-browser.png
  42. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-solution-runner-graph-build.png
  43. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-solution-runner-initial-product-page.png
  44. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-solution-runner-orders-page.png
  45. BIN
      docs/en/tutorials/modular-crm/images/abp-studio-swagger-ui-create-order-execute.png
  46. BIN
      docs/en/tutorials/modular-crm/images/sql-server-orders-database-table-filled.png
  47. BIN
      docs/en/tutorials/modular-crm/images/sql-server-orders-table-content.png
  48. BIN
      docs/en/tutorials/modular-crm/images/visual-studio-ordering-contracts.png
  49. BIN
      docs/en/tutorials/modular-crm/images/visual-studio-ordering-controller.png
  50. 2
      docs/en/tutorials/modular-crm/part-02.md
  51. 236
      docs/en/tutorials/modular-crm/part-05.md
  52. 128
      docs/en/tutorials/modular-crm/part-06.md
  53. 118
      docs/en/tutorials/modular-crm/part-07.md
  54. 2
      framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo.Abp.ApiVersioning.Abstractions.csproj
  55. 2
      framework/src/Volo.Abp.AspNetCore.Abstractions/Volo.Abp.AspNetCore.Abstractions.csproj
  56. 2
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj
  57. 2
      framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj
  58. 2
      framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo.Abp.AspNetCore.Authentication.OpenIdConnect.csproj
  59. 2
      framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Theming/Volo.Abp.AspNetCore.Components.MauiBlazor.Theming.csproj
  60. 2
      framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo.Abp.AspNetCore.Components.MauiBlazor.csproj
  61. 2
      framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Volo.Abp.AspNetCore.Components.Server.Theming.csproj
  62. 2
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj
  63. 2
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Volo.Abp.AspNetCore.Components.Web.Theming.csproj
  64. 2
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo.Abp.AspNetCore.Components.Web.csproj
  65. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.csproj
  66. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo.Abp.AspNetCore.Components.WebAssembly.csproj
  67. 2
      framework/src/Volo.Abp.AspNetCore.Components/Volo.Abp.AspNetCore.Components.csproj
  68. 2
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo.Abp.AspNetCore.MultiTenancy.csproj
  69. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo.Abp.AspNetCore.Mvc.Client.Common.csproj
  70. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj
  71. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.csproj
  72. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.csproj
  73. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo.Abp.AspNetCore.Mvc.Dapr.csproj
  74. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson.csproj
  75. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj
  76. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions.csproj
  77. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj
  78. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.csproj
  79. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo.Abp.AspNetCore.Mvc.UI.Packages.csproj
  80. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj
  81. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj
  82. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj
  83. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj
  84. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj
  85. 2
      framework/src/Volo.Abp.AspNetCore.Serilog/Volo.Abp.AspNetCore.Serilog.csproj
  86. 2
      framework/src/Volo.Abp.AspNetCore.SignalR/Volo.Abp.AspNetCore.SignalR.csproj
  87. 2
      framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj
  88. 9
      framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/WebApplicationBuilderExtensions.cs
  89. 28
      framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/WebProjectPatchHelper.cs
  90. 79
      framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs
  91. 2
      framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj
  92. 19
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/WebContentFileProvider.cs
  93. 2
      framework/src/Volo.Abp.Auditing.Contracts/Volo.Abp.Auditing.Contracts.csproj
  94. 2
      framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj
  95. 2
      framework/src/Volo.Abp.Authorization.Abstractions/Volo.Abp.Authorization.Abstractions.csproj
  96. 2
      framework/src/Volo.Abp.Authorization/Volo.Abp.Authorization.csproj
  97. 2
      framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj
  98. 2
      framework/src/Volo.Abp.Autofac.WebAssembly/Volo.Abp.Autofac.WebAssembly.csproj
  99. 2
      framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj
  100. 2
      framework/src/Volo.Abp.AzureServiceBus/Volo.Abp.AzureServiceBus.csproj

2
.github/workflows/build-and-test.yml

@ -51,7 +51,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-dotnet@master
with:
dotnet-version: 8.0.100
dotnet-version: 9.0.100-rc.1.24452.12
- name: chown
run: |

121
Directory.Packages.props

@ -51,69 +51,69 @@
<PackageVersion Include="Magick.NET-Q16-AnyCPU" Version="13.4.0" />
<PackageVersion Include="MailKit" Version="4.7.1.1" />
<PackageVersion Include="Markdig.Signed" Version="0.37.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Web" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Components" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Web" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.25" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="8.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.4" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.AspNetCore.WebUtilities" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.4" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.CommandLine" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Composite" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.4" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Localization" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="8.0.2" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.0-rc.1.24451.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.0-rc.1.24451.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0-rc.1.24451.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.0-rc.1.24451.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Proxies" Version="9.0.0-rc.1.24451.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.0-rc.1.24451.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0-rc.1.24451.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0-rc.1.24451.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0-rc.1.24451.1" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration.CommandLine" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Composite" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.Extensions.Localization" Version="9.0.0-rc.1.24452.1" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0-rc.1.24457.2" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
<PackageVersion Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="7.5.1" />
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="7.5.1" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.5.1" />
<PackageVersion Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.0.2" />
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="8.0.2" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.0.2" />
<PackageVersion Include="Minio" Version="6.0.2" />
<PackageVersion Include="MongoDB.Driver" Version="2.22.0" />
<PackageVersion Include="NEST" Version="7.17.5" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Nito.AsyncEx.Context" Version="5.1.2" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.0-rc.1" />
<PackageVersion Include="NSubstitute" Version="5.1.0" />
<PackageVersion Include="NuGet.Versioning" Version="6.7.0" />
<PackageVersion Include="NUglify" Version="1.21.0" />
@ -127,7 +127,7 @@
<PackageVersion Include="Oracle.EntityFrameworkCore" Version="8.23.40" />
<PackageVersion Include="Polly" Version="8.2.0" />
<PackageVersion Include="Polly.Extensions.Http" Version="3.0.0" />
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="9.0.0-preview.1" />
<PackageVersion Include="Quartz" Version="3.7.0" />
<PackageVersion Include="Quartz.Extensions.DependencyInjection" Version="3.7.0" />
<PackageVersion Include="Quartz.Plugins.TimeZoneConverter" Version="3.7.0" />
@ -154,17 +154,17 @@
<PackageVersion Include="Spectre.Console" Version="0.47.0" />
<PackageVersion Include="StackExchange.Redis" Version="2.7.4" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageVersion Include="System.Collections.Immutable" Version="8.0.0" />
<PackageVersion Include="System.Collections.Immutable" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
<PackageVersion Include="System.Linq.Dynamic.Core" Version="1.3.5" />
<PackageVersion Include="System.Linq.Queryable" Version="4.3.0" />
<PackageVersion Include="System.Runtime.Loader" Version="4.3.0" />
<PackageVersion Include="System.Security.Permissions" Version="8.0.0" />
<PackageVersion Include="System.Security.Permissions" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="System.Security.Principal.Windows" Version="5.0.0" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="8.0.0" />
<PackageVersion Include="System.Text.Encodings.Web" Version="8.0.0" />
<PackageVersion Include="System.Text.Json" Version="8.0.4" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="System.Text.Encodings.Web" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="System.Text.Json" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="7.5.1" />
<PackageVersion Include="TimeZoneConverter" Version="6.1.0" />
<PackageVersion Include="Unidecode.NET" Version="2.1.0" />
@ -174,5 +174,6 @@
<PackageVersion Include="coverlet.collector" Version="6.0.0" />
<PackageVersion Include="ConfigureAwait.Fody" Version="3.3.2" />
<PackageVersion Include="Fody" Version="6.8.0" />
<PackageVersion Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.8" />
</ItemGroup>
</Project>

2
abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalization.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>

2
docs/en/Community-Articles/2023-11-16-Upgrading-Your-Existing-Projects-to-NET8/POST.md

@ -52,7 +52,7 @@ For example, you can update the ASP.NET Core image as follows:
```diff
- FROM mcr.microsoft.com/dotnet/aspnet:7.0-bullseye-slim AS base
+ FROM mcr.microsoft.com/dotnet/aspnet:8.0
+ FROM mcr.microsoft.com/dotnet/aspnet:9.0
```
You can check the related images from Docker Hub and update them accordingly:

136
docs/en/deployment/ssl.md

@ -2,9 +2,11 @@
A website needs an SSL certificate in order to keep user data secure, verify ownership of the website, prevent attackers from creating a fake version of the site, and gain user trust.
This document introduces how to get and use SSL certificate(HTTPS) for your application.
This document introduces how to get and use an SSL certificate(HTTPS) for your application.
## Get a SSL Certificate from a Certificate Authority
## Get an SSL Certificate from a Certificate Authority
You can get a SSL certificate from a certificate authority (CA) such as [Let's Encrypt](https://letsencrypt.org/) or [Cloudflare](https://www.cloudflare.com/learning/ssl/what-is-an-ssl-certificate/) and so on.
@ -14,21 +16,137 @@ Once you have a certificate, you need to configure your web server to use it. Th
* [Host ASP.NET Core on Linux with Nginx: HTTPS configuration](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx)
* [How to Set Up SSL on IIS 7 or later](https://learn.microsoft.com/en-us/iis/manage/configuring-security/how-to-set-up-ssl-on-iis)
## Create a Self-Signed Certificate
You can create a self-signed certificate for testing purposes or internal use.
There is an article about [how to create a self-signed certificate](https://learn.microsoft.com/en-us/dotnet/core/additional-tools/self-signed-certificates-guide), If you are using IIS, you can use the following this document to [obtain a Certificate](https://learn.microsoft.com/en-us/iis/manage/configuring-security/how-to-set-up-ssl-on-iis#obtain-a-certificate)
### How to get a free SSL certificate from Let's Encrypt?
Let's Encrypt is **a free, automated, and open certificate authority (CA)**. It gives the digital certificates to enable HTTPS (SSL/TLS) for websites. To get a free SSL certificate, we will use [acme.sh](https://github.com/acmesh-official/acme.sh) and Cloudflare DNS API to get a free SSL certificate from [Let's Encrypt](https://letsencrypt.org/).
> If you have any problem with the following steps, you can read the [acme.sh](https://github.com/acmesh-official/acme.sh/wiki/dnsapi) tutorial.
#### Install [acme.sh](https://github.com/acmesh-official/acme.sh)
Ensure that you have `curl` command in your terminal. And run the following command on your terminal:
```bash
curl https://get.acme.sh | sh -s email=my@example.com
```
#### [Cloudflare DNS API token](https://dash.cloudflare.com/profile/api-tokens)
You will need to create an API token which either:
(i) has permission to edit a single specific DNS zone; or
(ii) has permission to edit multiple DNS zones.
You can do this via your Cloudflare profile page under the API Tokens section. When you create the token, under Permissions, select Zone > DNS > Edit, and under Zone Resources, only include the specific DNS zones within which you need to perform ACME DNS challenges.
The API token is a 40-character string that may contain uppercase letters, lowercase letters, numbers, and underscores. You must provide it to acme.sh by setting the environment variable CF_Token to its value, e.g. run export CF_Token="Y_jpG9AnfQmuX5Ss9M_qaNab6SQwme3HWXNDzRWs".
**(i) Single DNS zone**
You must give acme.sh the zone ID of the DNS zone it needs to edit. This is a 32-character hexadecimal string (e.g. 763eac4f1bcebd8b5c95e9fc50d010b4), and should not be confused with the zone name (e.g. example.com). This zone ID can be found via the Cloudflare dashboard on the zone's Overview page in the right-hand sidebar.
You provide this info by setting the environment variable CF_Zone_ID to this zone ID, e.g. run export CF_Zone_ID="763eac4f1bcebd8b5c95e9fc50d010b4".
**(ii) Multiple DNS zones**
You must give acme.sh the account ID of the Cloudflare account to which the relevant DNS zones belong. This is a 32-character hexadecimal string, and should not be confused with other account identifiers, such as the account email address (e.g. alice@example.com) or global API key (which is also a 32-character hexadecimal string). This account ID can be found via the Cloudflare dashboard, as the end of the URL when logged in, or on the Overview page of any of your zones, in the right-hand sidebar, beneath the zone ID.
You provide this info by setting the environment variable CF_Account_ID to this account ID, e.g. run export CF_Account_ID="763eac4f1bcebd8b5c95e9fc50d010b4".
#### Issue a certificate
```bash
> export CF_Token='your_token'
> export CF_Account_ID='your_account_id'
> export CF_Zone_ID='your_zone_id'
> acme.sh --issue --dns dns_cf -d getabp.net
[Info] Domains have changed.
[Info] Using CA: https://acme.zerossl.com/v2/DV90
[Info] Single domain='getabp.net'
[Info] Getting webroot for domain='getabp.net'
[Info] Adding TXT value: 1uEeVFfmwXM7N21Wi9PitgEnhJbl4W4dHeRkapGkRSs for domain: _acme-challenge.getabp.net
[Info] Adding record
[Info] Added, OK
[Info] The TXT record has been successfully added.
[Info] Let's check each DNS record now. Sleeping for 20 seconds first.
[Info] You can use '--dnssleep' to disable public dns checks.
[Info] See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck
[Info] Checking getabp.net for _acme-challenge.getabp.net
[Info] Success for domain getabp.net '_acme-challenge.getabp.net'.
[Info] All checks succeeded
[Info] Verifying: getabp.net
[Info] Processing. The CA is processing your order, please wait. (1/30)
[Info] Success
[Info] Removing DNS records.
[Info] Removing txt: 1uEeVFfmwXM7N21Wi9PitgEnhJbl4W4dHeRkapGkRSs for domain: _acme-challenge.getabp.net
[Info] Successfully removed
[Info] Verification finished, beginning signing.
[Info] Let's finalize the order.
[Info] Le_OrderFinalize='https://acme.zerossl.com/v2/DV90/order/1AP31vqE7rzxCmvpDsDgvA/finalize'
[Info] Order status is 'processing', let's sleep and retry.
[Info] Sleeping for 15 seconds then retrying
[Info] Polling order status: https://acme.zerossl.com/v2/DV90/order/1AP31vqE7rzxCmvpDsDgvA
[Info] Downloading cert.
[Info] Le_LinkCert='https://acme.zerossl.com/v2/DV90/cert/o1jBkRs8LVVBiEZShd4Yow'
[Info] Cert success.
-----BEGIN CERTIFICATE-----
MIID9jCCA3ygAwIBAgIQbJr7iNOSnkMXJjkwngvQRzAKBggqhkjOPQQDAzBLMQsw
CQYDVQQGEwJBVDEQMA4GA1UEChMHWmVyb1NTTDEqMCgGA1UEAxMhWmVyb1NTTCBF
Q0MgRG9tYWluIFNlY3VyZSBTaXRlIENBMB4XDTI0MDkyODAwMDAwMFoXDTI0MTIy
NzIzNTk1OVowFTETMBEGA1UEAxMKZ2V0YWJwLm5ldDBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABJ.....io0Kq3W2o0eAgXDVXw2QJ6RlZKi0RGha/D92u/OAqvjX0I4
YEPRRgAm6l2oLg==
-----END CERTIFICATE-----
[Info] Your cert is in: getabp.net.cer
[Info] Your cert key is in: getabp.net.key
[Info] The intermediate CA cert is in: ca.cer
[Info] And the full-chain cert is in: fullchain.cer
```
#### Convert the certificate to PFX format(IIS format)
```bash
openssl pkcs12 -export \
-in getabp.net.cer \
-inkey getabp.net.key \
-out getabp.net.pfx \
-passout pass:
```
If you want to set a password for the PFX file, you can set the password with `-passout pass:your_password`.
## Common Exceptions
If you encounter the following exceptions, it means your **certificate is not trusted by the client or the certificate is not valid**.
You will may see the following SSL certificate errors in your browser when you try to access the website.
```cs
---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch
```
## Common Problems
```cs
---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot
```
### The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot
This error may occur when using IIS. You need to trust your certificate by `Manage computer certificates`.
## References
* [ABP IIS Deployment](./index.md)
* [acme.sh](https://github.com/acmesh-official/acme.sh)
* [acme.sh DNS API](https://github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cf)
* [HTTPS in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl)
* [Let's Encrypt](https://letsencrypt.org/getting-started)
* [Cloudflare's Free SSL / TLS](https://www.cloudflare.com/application-services/products/ssl/)
* [Cloudflare's Free SSL / TLS](https://www.cloudflare.com/application-services/products/ssl/)

2
docs/en/framework/architecture/modularity/basics.md

@ -7,7 +7,7 @@ ABP was designed to support to build fully modular applications and systems wher
* This document introduces the basics of the module system.
* [Module development best practice guide](../best-practices) explains some **best practices** to develop **re-usable application modules** based on **DDD** principles and layers. A module designed based on this guide will be **database independent** and can be deployed as a **microservice** if needed.
* [Pre-built application modules](../../../modules) are **ready to use** in any kind of application.
* [Module startup template](../../../solution-templates/layered-web-application) is a jump start way to **create a new module**.
* [Module startup template](../../../solution-templates/application-module) is a jump start way to **create a new module**.
* [ABP CLI](../../../cli/index.md) has commands to support modular development.
* All other framework features are compatible to the modularity system.

8
docs/en/framework/fundamentals/dynamic-claims.md

@ -1,8 +1,8 @@
# Dynamic Claims
When a client authenticates and obtains an access token or an authentication cookie, the claims in that token or cookie are not changed unless it re-authenticates. For most of the claims, that may not be a problem since claims are not frequently changing values. However, some claims may be changed and these changes should be reflected to the current session immediately. For example, we can revoke a role from a user and that should be immediately effective, otherwise user will continue to use that role's permissions until re-login to the application.
When a client authenticates and obtains an access token or an authentication cookie, the claims in that token or cookie are not changed unless it re-authenticates. That is not a problem for most claims since the claim values do not frequently change. However, for some claims, it may be required to immediately see the impact after the claim values change in the current session. For example, if a role is revoked from a user, you want to see its effect in the next request. Otherwise, the user will continue to use that role's permissions until re-login to the application.
ABP's dynamic claims feature is used to automatically and dynamically override the configured claim values in the client's authentication token/cookie by the latest values of these claims.
ABP's dynamic claims feature dynamically overrides the configured claim values in the client's authentication token/cookie with the latest values of these claims.
## How to Use
@ -10,7 +10,7 @@ This feature is disabled by default. You should enable it for your application a
> **Beginning from the v8.0, all the [startup templates](../../solution-templates) are pre-configured and the dynamic claims feature is enabled by default. So, if you have created a solution with v8.0 and above, you don't need to make any configuration. Follow the instructions only if you've upgraded from a version lower than 8.0.**
### Enabling the Dynamic Claims
### Enabling / Disabling the Dynamic Claims
You can enable it by the following code:
@ -19,7 +19,7 @@ public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.IsDynamicClaimsEnabled = true;
options.IsDynamicClaimsEnabled = true; //set it "true" to enable "Dynamic Claims" or "false" to disable it.
});
}
````

6
docs/en/get-started/console.md

@ -10,12 +10,14 @@ First, install the [ABP CLI](../cli) if you haven't installed before:
dotnet tool install -g Volo.Abp.Studio.Cli
````
Then use the `abp new` command in an empty folder to create a new solution:
Then use the `abp new` command in an empty folder to create a new solution (with the `--old` parameter at the end of the command):
````bash
abp new Acme.MyConsoleApp -t console
abp new Acme.MyConsoleApp -t console --old
````
> **Note**: Since this startup template is not provided by the new ABP Studio Templates yet, you need to pass the `--old` parameter at the end of the command to use the old CLI & templating system for this startup template.
`Acme.MyConsoleApp` is the solution name, like *YourCompany.YourProduct*. You can use single level, two-levels or three-levels naming.
## Solution Structure

6
docs/en/get-started/wpf.md

@ -10,12 +10,14 @@ First, install the [ABP CLI](../cli) if you haven't installed before:
dotnet tool install -g Volo.Abp.Studio.Cli
````
Then use the `abp new` command in an empty folder to create a new solution:
Then use the `abp new` command in an empty folder to create a new solution (with the `--old` parameter at the end of the command):
````bash
abp new Acme.MyWpfApp -t wpf
abp new Acme.MyWpfApp -t wpf --old
````
> **Note**: Since this startup template is not provided by the new ABP Studio Templates yet, you need to pass the `--old` parameter at the end of the command to use the old CLI & templating system for this startup template.
`Acme.MyWpfApp` is the solution name, like *YourCompany.YourProduct*. You can use single level, two-levels or three-levels naming.
## Solution Structure

32
docs/en/guides/ms-multi-tenant-domain-resolving.md

@ -270,6 +270,7 @@ Your request from the browser to the subdomain will be accepted by the ingress-c
Update your charts ingress.yaml files. Ex for **administration-ingress.yaml**:
{%{
```yaml
spec:
tls:
@ -303,6 +304,7 @@ spec:
port:
number: 80
```
}%}
**Update all the application, gateway and microservice ingress.yaml files.** Eventually, when deploy the application, you will be seeing:
![updated-ingress](../images/updated-ingress.png)
@ -311,6 +313,7 @@ spec:
Navigate to applications, gateways and microservices' **x-deployment.yaml** file and override the newly introduced `TenantDomain` key:
{%{
```yaml
... Removed for brevity
- name: "TenantDomain" # Add this key
@ -319,11 +322,13 @@ Navigate to applications, gateways and microservices' **x-deployment.yaml** file
value: "{{ .Values.config.authServer.authority }}"
...
```
}%}
> **Update all the application, gateway and microservice deployment.yaml files.**
**For AuthServer, also add the WildCardDomains that is used to handle subdomain *redirect* and *post_logout redirect* URIs to the authserver-deployment.yaml file:**
{%{
```yaml
... Removed for brevity
- name: "TenantDomain"
@ -348,6 +353,7 @@ Navigate to applications, gateways and microservices' **x-deployment.yaml** file
value: "{{ .Values.wildCardDomains.productService }}"
...
```
}%}
Afterwards, update the **values.yaml** file for all the sub-charts (administration, authserver etc):
@ -383,7 +389,7 @@ wildCardDomains:
After updating the **deployment.yaml** and **values.yaml** files of all the application, gateway and microservices' navigate to the **mystore chart values.yaml** file located under the k8s/Mystore/values.yaml that overrides all the sub-charts:
**AuthServer:**
{%{
```yaml
# auth-server sub-chart override
authserver:
@ -402,11 +408,13 @@ authserver:
saasService: "https://{0}.saas.mystore.dev"
productService: "https://{0}.product.mystore.dev"
```
}%}
You may also get CORS error when authenticating SwaggerUI of your gateways or microservices. Add Override the AuthServer CORS values with the subdomain to solve this problem:
**identityService:**
{%{
```yaml
# identity-service sub-chart override
identity:
@ -416,9 +424,10 @@ identity:
... Removed for brevity
tenantDomain: "https://{0}.identity.mystore.dev"
```
}%}
**administrationService:**
{%{
```yaml
# administration-service sub-chart override
administration:
@ -428,9 +437,11 @@ administration:
... Removed for brevity
tenantDomain: "https://{0}.administration.mystore.dev"
```
}%}
**saasService:**
{%{
```yaml
# saas-service sub-chart override
saas:
@ -440,9 +451,9 @@ saas:
... Removed for brevity
tenantDomain: "https://{0}.saas.mystore.dev"
```
}%}
**productService:**
{%{
```yaml
# product-service sub-chart override
product:
@ -452,9 +463,10 @@ product:
... Removed for brevity
tenantDomain: "https://{0}.product.mystore.dev"
```
}%}
**gateway-web:**
{%{
```yaml
# saas-service sub-chart override
gateway-web:
@ -464,9 +476,10 @@ gateway-web:
... Removed for brevity
tenantDomain: "https://{0}.gateway-web.mystore.dev"
```
}%}
**gateway-web-public:**
{%{
```yaml
# gateway-web-public sub-chart override
gateway-web-public:
@ -476,9 +489,10 @@ gateway-web-public:
... Removed for brevity
tenantDomain: "https://{0}.gateway-public.mystore.dev"
```
}%}
**publicweb:**
{%{
```yaml
# Public Web application sub-chart override
publicweb:
@ -489,9 +503,10 @@ publicweb:
... Removed for brevity
tenantDomain: "https://{0}.mystore.dev"
```
}%}
**angular:**
{%{
```yaml
# Angular back-office application sub-chart override
angular:
@ -505,6 +520,7 @@ angular:
strictDiscoveryDocumentValidation: false
skipIssuerCheck: true
```
}%}
> If you are using Web or BlazorServer application for back-office, it is similar configuration with the public-web application

BIN
docs/en/images/pen-test-alert-list-8.3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

120
docs/en/others/penetration-test-report.md

@ -1,6 +1,6 @@
# ABP Penetration Test Report
The ABP Commercial MVC `v8.2.0` application template has been tested against security vulnerabilities by the [OWASP ZAP v2.14.0](https://www.zaproxy.org/) tool. The demo web application was started on the `https://localhost:44349` address. The below alerts have been reported by the pentest tool. These alerts are sorted by the risk level as high, medium, and low. The informational alerts are not mentioned in this document.
The ABP Commercial MVC `v8.3.0` application template has been tested against security vulnerabilities by the [OWASP ZAP v2.14.0](https://www.zaproxy.org/) tool. The demo web application was started on the `https://localhost:44349` address. The below alerts have been reported by the pentest tool. These alerts are sorted by the risk level as high, medium, and low. The informational alerts are not mentioned in this document.
Many of these alerts are **false-positive**, meaning the vulnerability scanner detected these issues, but they are not exploitable. It's clearly explained for each false-positive alert why this alert is a false-positive.
@ -10,14 +10,15 @@ In the next sections, you will find the affected URLs, attack parameters (reques
There are high _(red flag)_, medium _(orange flag)_, low _(yellow flag)_, and informational _(blue flag)_ alerts.
![penetration-test-8.2.0](../images/pen-test-alert-list-8.2.png)
w
![penetration-test-8.3.0](../images/pen-test-alert-list-8.3.png)
> The informational alerts are not mentioned in this document. These alerts are not raising any risks on your application and they are optional.
### Path Traversal [Risk: High] - False Positive
- *[GET] - https://localhost:44349/api/audit-logging/audit-logs?startTime=&endTime=&url=&userName=&applicationName=&clientIpAddress=&correlationId=&httpMethod=audit-logs&httpStatusCode=&maxExecutionDuration=&minExecutionDuration=&hasException=true&sorting=executionTime+desc&skipCount=0&maxResultCount=10* (attack: **httpMethod=audit-logs**)
- *[POST] - https://localhost:44349/Account/Login* (attack: **\Login**)
- *[POST] - https://localhost:44349/Account/Register* (attack: **\Register**)
- *[POST] - https://localhost:44349/Account/SecurityLogs* (attack: **\SecurityLogs**)
- *[POST] - https://localhost:44349/Identity/SecurityLogs* (attack: **\SecurityLogs**)
@ -49,6 +50,18 @@ SQL injection may be possible. SQL injection is a web security vulnerability tha
ABP uses Entity Framework Core and LINQ. **It's safe against SQL Injection because it passes all data to the database via SQL parameters.** LINQ queries are not composed by using string manipulation or concatenation, that's why they are not susceptible to traditional SQL injection attacks. Therefore, this is a **false-positive** alert.
### SQL Injection - Authentication Bypass [Risk: High] - False Positive
* *[POST] — https://localhost:44349/Account/Login* (attack: **false AND 1=1 --**)
**Description**:
SQL injection may be possible on a login page, potentially allowing the application's authentication mechanism to be bypassed.
**Solution**:
This alert indicates that we must not trust client side input (even if there is client side validation in place) and check all data on the server side. ABP Framework already does that and makes server-side validations while authenticating a user. Therefore this is a **false-positive** alert.
### Absence of Anti-CSRF Tokens [Risk: Medium] — False Positive
* *[GET] - https://localhost:44349/Account/LinkUsers/LinkUsersModal?returnUrl=/SettingManagement*
@ -113,8 +126,8 @@ Configure<AbpSecurityHeadersOptions>(options =>
### Format String Error [Risk: Medium] - False Positive
- *[GET] — https://localhost:44349/Abp/Languages/Switch?culture=ZAP%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%0A&returnUrl=%2F&uiCulture=ar*
- *[GET] — https://localhost:44349/Abp/ApplicationLocalizationScript?cultureName=ZAP%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%0A*
- *[GET] — https://localhost:44349/Abp/Languages/Switch?culture=ZAP%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%0A&returnUrl=%2F&uiCulture=ar* (with combination of different parameters)
- *[GET] — https://localhost:44349/Abp/ApplicationLocalizationScript?cultureName=ZAP%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%25n%25s%0A* (with combination of different parameters)
**Description:**
@ -148,19 +161,21 @@ Injection using XSL transformations may be possible and may allow an attacker to
**Explanation**:
This is a **false-positive** alert. v8.2.0 uses .NET 8 and the XSLT transformation is not possible on .NET5 or higher.
This is a **false-positive** alert. v8.3.0 uses .NET 8 and the XSLT transformation is not possible on .NET5 or higher.
### Application Error Disclosure [Risk: Low] — False Positive
- *[POST] — https://localhost:44349/Account/ImpersonateUser*
- *[POST] — https://localhost:44349/Saas/Host/Editions*
- *[POST] — https://localhost:44349/Saas/Host/Tenants*
**Description:**
The reported page contains an error/warning message that may disclose sensitive information like the location of the file that produced the unhandled exception. This information can be used to launch further attacks against the web application. The alert could be a false positive if the error message is found inside a documentation page.
The reported pages contain an error/warning message that may disclose sensitive information like the location of the file that produced the unhandled exception. This information can be used to launch further attacks against the web application. The alert could be a false positive if the error message is found inside a documentation page.
**Explanation:**
This vulnerability was reported as a **positive** alert because the application ran in `Development` mode. ABP Framework throws exceptions for developers in the `Development` environment. We set the environment to `Production` and re-run the test, then the server sent a *500-Internal Error* without the error disclosed. Therefore this alert is **false-positive**. Further information can be found in the following issue: [github.com/abpframework/abp/issues/14177](https://github.com/abpframework/abp/issues/14177#issuecomment-1268206947).
This vulnerability was reported as a **positive** alert because the application ran in `Development` mode. ABP throws exceptions for developers in the `Development` environment. We set the environment to `Production` and re-run the test, then the server sent a *500-Internal Error* without the error disclosed. Therefore this alert is **false-positive**. Further information can be found in the following issue: [github.com/abpframework/abp/issues/14177](https://github.com/abpframework/abp/issues/14177#issuecomment-1268206947).
### Cookie No `HttpOnly` Flag [Risk: Low] — Positive (No need for a fix)
@ -326,89 +341,10 @@ The `X-Content-Type-Options` header allows you to avoid MIME type sniffing by sa
You can add the [ABP's Security Header Middleware](../framework/ui/mvc-razor-pages/security-headers.md#security-headers-middleware) into the request pipeline to set the `X-Content-Type-Options` as *no-sniff*. Also, this middleware adds other pre-defined security headers to your application, including `X-XSS-Protection`, `X-Frame-Options` and `Content-Security-Policy` (if it's enabled). Read [Security Headers](../framework/ui/mvc-razor-pages/security-headers.md) documentation for more info.
## Other Alerts
The following alerts are reported by the community or our customers in v8.1+.
### Disclosed Microsoft Client Secret [Risk: Medium] - Positive (No need for a fix)
* *[GET] — https://localhost:44349/setting-management*
**Description**:
Secrets shall never be exposed to unauthorized parties. This exposure can result from improper storage, insecure transmission, or inadequate access controls. In this specific case the owner of the user account is authorized to read and modify the secret. In case of administrative accounts, it could lead to further damages, by performing lateral movements, by using the credentials to access other services.
**Explanation**:
The endpoint `/setting-management/` requires permission to be visited and can only be accessed via authorized users. It is the setting page to configure the application settings including the *default localization language*, *timezone*, *layout type*, *password settings* and more...
### Incorrect Session Handling – Insufficient Session Termination [Risk: Low] - Positive
* *[GET] — https://localhost:44349/Account/Logout*
**Description**:
Application logout functionality does not terminate the user's session. This increases the risk of unauthorized application access via successful session hijacking attacks, users leaving their computers unattended, and/or a local attacker utilizing the browser history. On logout, user sessions should be invalidated and all relevant session identifiers, authentication tokens and application state information deleted or overwritten both on server and on client side.
**Explanation**:
You can track the status of this case at [github.com/abpframework/abp/issues/19576](https://github.com/abpframework/abp/issues/19576).
### Information Disclosure via Configuration Scripts [Risk: Low] - Positive (No need for a fix)
## Other Alerts (Fixed)
- *[GET] — https://localhost:44349/Abp/ApplicationConfigurationScript* or *https://localhost:44349/api/abp/application-configuration*
- *[GET] — https://localhost:44349/Abp/ServiceProxyScript*
**Description**:
When users authenticate to the application, their browsers issue requests to 2 endpoints that host configuration scripts for the application framework. The first contains information about the passwords that are accepted by the application. This information can be used by the attackers to narrow down their dictionaries and only focus on the possible passwords for their
attacks. The second, on the other hand, discloses some endpoints that are unavailable to the users with low privileges.
**Explanation**:
* **Application Configuration Script**:
These 2 endpoints are used by ABP application templates. The first one `/Abp/ApplicationConfigurationScript` provides configuration and user based definitions with JSON format. This data is important for SPA based applications to get the current language, localization texts, policies, settings, user info, current tenant or time zone information. This is not a data leak. User specific data can only be accessed after user logon. Other data are application-wide used not dangerous for unauthenticated users. For more information check out the [Application Configuration](../framework/api-development/standard-apis/configuration.md) document.
* **Service Proxy Script**:
This endpoint provides auto-generated JavaScript AJAX call methods for the backend operations. This may disclosure information about the host API methods. On the other hand, it makes easy to consume the HTTP APIs from JavaScript side. ABP Application Services are automatically converted to JavaScript proxies. But it does not mean that these JavaScript methods can be executed anonymously. The attacker still needs to log in to perform operations. For more information check out the [Service Proxy Script](../framework/ui/mvc-razor-pages/dynamic-javascript-proxies.md) document. If you want to disable this functionality, check out [github.com/abpframework/abp/issues/12297](https://github.com/abpframework/abp/issues/12297)
### User E-mail Address Enumeration [Risk: Low] - Positive
* *[GET] — https://localhost:44349/Account/ForgotPassword*
**Description**:
It is possible to collect valid email addresses by interacting with the "Forgot Password" function of the
application. This vulnerability is useful to increase the efficiency of brute force attacks.
**Explanation**:
If the email is known, it is easier to find the corresponding password. With the "Forgot Password" function, the attacker can enumerate valid email addresses as the function returns `Cannot find the given email` error, when there is no user registered with the provided e-mail address. This vulnerability has been fixed with v8.2, see the related issue for more info: [github.com/abpframework/abp/issues/19588](https://github.com/abpframework/abp/issues/19588).
### Software Version Disclosure [Risk: Low] - Positive (No need for a fix)
* *[GET] — https://localhost:44349/*
**Description**:
The assessed web server discloses its version number within the HTTP response headers. This information facilitates attackers in planning future attacks and can be used in the automation of the attack process. It is unnecessary to share this information with the clients of the web application. The vulnerability can be verified by issuing HTTP requests and inspecting HTTP response headers. HTTP header "Server" contains the version information.
The following header was received in server responses: `Server: Microsoft-IIS/10.0` or `Server: Microsoft-HTTPAPI/2.0`.
**Explanation**:
This is not directly related to ABP. It's a header added by the IIS server. So you can disable this header with the `web.config` file:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<security>
<requestFiltering removeServerHeader="true" />
</security>
</system.webServer>
</configuration>
```
The following alerts were reported by the community or our customers in v8.2 and fixed:
The following issue has been opened for this vulnerability, you can follow it at [github.com/abpframework/abp/issues/19589](https://github.com/abpframework/abp/issues/19589).
* https://github.com/abpframework/abp/issues/19576
* https://github.com/abpframework/abp/issues/19588
* https://github.com/abpframework/abp/issues/19589

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-entity-framework-core-migration-dialog.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-entity-framework-core-migration.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 70 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-new-dd-module.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-new-ddd-module.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-new-empty-module.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 30 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-new-folder-command.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-new-package.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 31 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 30 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-3.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-4.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-5.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-7.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-dialog-5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference-dialog-6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-add-package-reference.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-added-ddd-contracts-package.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-build-and-restart-application.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-entity-framework-core-add-migration-order.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-entity-framework-core-update-database.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 91 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-graph-build.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 36 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-import-module-for-ordering.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 21 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-import-module-ordering.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-import-module.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 19 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-new-folder-dialog.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-open-in-explorer.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 67 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-open-with-visual-studio-main-app.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 74 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-open-with-visual-studio.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 38 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-ordering-swagger-ui-in-browser.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-solution-runner-graph-build.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 26 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-solution-runner-initial-product-page.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 79 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-solution-runner-orders-page.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 56 KiB

BIN
docs/en/tutorials/modular-crm/images/abp-studio-swagger-ui-create-order-execute.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/en/tutorials/modular-crm/images/sql-server-orders-database-table-filled.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
docs/en/tutorials/modular-crm/images/sql-server-orders-table-content.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

BIN
docs/en/tutorials/modular-crm/images/visual-studio-ordering-contracts.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
docs/en/tutorials/modular-crm/images/visual-studio-ordering-controller.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

2
docs/en/tutorials/modular-crm/part-02.md

@ -41,7 +41,7 @@ We will use the *DDD Module* template for the Product module and the *Empty Modu
Right-click the `modules` folder on the *Solution Explorer* panel, and select the *Add* -> *New Module* -> *DDD Module* command:
![abp-studio-add-new-dd-module](images/abp-studio-add-new-dd-module.png)
![abp-studio-add-new-ddd-module](images/abp-studio-add-new-ddd-module.png)
This command opens a new dialog to define the properties of the new module. You can use the following values to create a new module named `ModularCrm.Products`:

236
docs/en/tutorials/modular-crm/part-05.md

@ -232,9 +232,215 @@ After the operation completes, you can check your database to see the new `Order
![sql-server-products-database-table](images/sql-server-orders-database-table.png)
## Creating the User Interface
## Creating the Application Service
We will create an application service to manage the `Order` entities.
### Defining the Application Service Contract
We're gonna create the `IOrderAppService` interface under the `ModularCrm.Ordering.Contracts` project but first, we need to add `Volo.Abp.Ddd.Application.Contracts` package reference.
Right-click the `ModularCrm.Ordering.Contracts` project in the *Solution Explorer* panel and select the *Add Package Reference* command:
![abp-studio-add-package-reference-6](images/abp-studio-add-package-reference-6.png)
This command opens a dialog to add a new package reference:
![abp-studio-add-package-reference-dialog-5](images/abp-studio-add-package-reference-dialog-5.png)
Select the *NuGet* tab, type `Volo.Abp.Ddd.Application.Contracts` as the *Package name* and write the version of the package you want to install. Please be sure that you are installing the same version as the other ABP packages you are already using.
Click the *Ok* button. Now you can check the *Packages* under the `ModularCrm.Ordering.Contracts` project *Dependencies* to see the `Volo.Abp.Ddd.Application.Contracts` package is installed:
![abp-studio-added-ddd-contracts-package](images/abp-studio-added-ddd-contracts-package.png)
Return to your IDE, open the `ModularCrm.Ordering` module's .NET solution and create an `IOrderAppService` interface under the `Services` folder for `ModularCrm.Ordering.Contracts` project:
````csharp
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace ModularCrm.Ordering.Contracts.Services;
public interface IOrderAppService : IApplicationService
{
Task<List<OrderDto>> GetListAsync();
Task CreateAsync(OrderCreationDto input);
}
````
### Defining Data Transfer Objects
The `GetListAsync` and `CreateAsync` methods will use data transfer objects (DTOs) to communicate with the client. We will create two DTO classes for that purpose.
Create a `OrderCreationDto` class under the `ModularCrm.Ordering.Contracts` project:
````csharp
using System;
using System.ComponentModel.DataAnnotations;
namespace ModularCrm.Ordering.Contracts.Services;
public class OrderCreationDto
{
[Required]
[StringLength(150)]
public string CustomerName { get; set; }
[Required]
public Guid ProductId { get; set; }
}
````
Create a `OrderDto` class under the `ModularCrm.Ordering.Contracts` project:
````csharp
using System;
using ModularCrm.Ordering.Contracts.Enums;
namespace ModularCrm.Ordering.Contracts.Services;
public class OrderDto
{
public Guid Id { get; set; }
public string CustomerName { get; set; }
public Guid ProductId { get; set; }
public OrderState State { get; set; }
}
````
The new files under the `ModularCrm.Ordering.Contracts` project should be like the following figure:
![visual-studio-ordering-contracts](images/visual-studio-ordering-contracts.png)
### Implementing the Application Service
Before creating the `OrderAppService` class, we need to add the `Volo.Abp.Ddd.Application` and `Volo.Abp.AutoMapper` packages to the Ordering module.
Right-click the `ModularCrm.Ordering` package in the *Solution Explorer* panel and select the *Add Package Reference* command:
![abp-studio-add-package-reference-7](images/abp-studio-add-package-reference-7.png)
This command opens a dialog to add a new package reference:
![abp-studio-add-package-reference-dialog-6](images/abp-studio-add-package-reference-dialog-6.png)
Select the *NuGet* tab, enter `Volo.Abp.Ddd.Application` as the *Package name*, and specify the version of the package you wish to install. Afterward, you can add the `Volo.Abp.AutoMapper` package in the same dialog. Ensure that you install the same version as the other ABP packages you are already using.
Click the *OK* button. Now we should configure the *AutoMapper* object to map the `Order` entity to the `OrderDto` object. We will create a class named `OrderingApplicationAutoMapperProfile` under the `ModularCrm.Ordering` project:
````csharp
using AutoMapper;
using ModularCrm.Ordering.Contracts.Services;
using ModularCrm.Ordering.Entities;
namespace ModularCrm.Ordering;
public class OrderingApplicationAutoMapperProfile : Profile
{
public OrderingApplicationAutoMapperProfile()
{
CreateMap<Order, OrderDto>();
}
}
````
Since this is a non-layered module, we can use entities and repositories directly on the user interface. If you think that is not a good practice, then use the layered module template as we've already done for the *Products* module. But for the Ordering module, we will keep it very simple for this tutorial to show it is also possible.
And configure the `OrderingWebModule` class to use the `OrderingApplicationAutoMapperProfile`:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
//Add these lines
context.Services.AddAutoMapperObjectMapper<OrderingWebModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<OrderingWebModule>(validate: true);
});
}
````
Now, we can implement the `IOrderAppService` interface. Create an `OrderAppService` class under the `Services` folder of the `ModularCrm.Ordering` project:
````csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ModularCrm.Ordering.Contracts.Enums;
using ModularCrm.Ordering.Contracts.Services;
using ModularCrm.Ordering.Entities;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace ModularCrm.Ordering.Services;
public class OrderAppService : ApplicationService, IOrderAppService
{
private readonly IRepository<Order> _orderRepository;
public OrderAppService(IRepository<Order, Guid> orderRepository)
{
_orderRepository = orderRepository;
ObjectMapperContext = typeof(OrderingWebModule);
}
public async Task<List<OrderDto>> GetListAsync()
{
var orders = await _orderRepository.GetListAsync();
return ObjectMapper.Map<List<Order>, List<OrderDto>>(orders);
}
public async Task CreateAsync(OrderCreationDto input)
{
var order = new Order
{
CustomerName = input.CustomerName,
ProductId = input.ProductId,
State = OrderState.Placed
};
await _orderRepository.InsertAsync(order);
}
}
````
Open the `ModularCrmWebModule` class in the main application's solution (the `ModularCrm` solution), find the `ConfigureAutoApiControllers` method and add the following lines inside that method:
````csharp
private void ConfigureAutoApiControllers()
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.Create(typeof(ModularCrmApplicationModule).Assembly);
options.ConventionalControllers.Create(typeof(ProductsApplicationModule).Assembly);
//ADD THE FOLLOWING LINE:
options.ConventionalControllers.Create(typeof(OrderingWebModule).Assembly);
});
}
````
### Creating Example Orders
This section will create a few example orders using the [Swagger UI](../../framework/api-development/swagger.md). Thus, we will have some sample orders to show on the UI.
Now, right-click the `ModularCrm` under the `main` folder in the Solution Explorer panel and select the *Dotnet CLI* -> *Graph Build* command. This will ensure that the order module and the main application are built and ready to run.
After the build process completes, open the Solution Runner panel and click the *Play* button near the solution root. Once the `ModularCrm.Web` application runs, we can right-click it and select the *Browse* command to open the user interface.
Once you see the user interface of the web application, type `/swagger` at the end of the URL to open the Swagger UI. If you scroll down, you should see the `Orders` API:
![abp-studio-ordering-swagger-ui-in-browser](images/abp-studio-ordering-swagger-ui-in-browser.png)
Expand the `/api/app/order` API and click the *Try it out* button. Then, create a few orders by filling in the request body and clicking the *Execute* button:
![abp-studio-swagger-ui-create-order-execute](images/abp-studio-swagger-ui-create-order-execute.png)
If you check the database, you should see the entities created in the *Orders* table:
![sql-server-orders-database-table-filled](images/sql-server-orders-database-table-filled.png)
## Creating the User Interface
### Creating a `_ViewImports.cshtml` File
@ -257,28 +463,26 @@ Create an `Orders` folder under the `Pages` folder and add an `Index.cshtml` Raz
````csharp
using Microsoft.AspNetCore.Mvc.RazorPages;
using ModularCrm.Ordering.Entities;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using ModularCrm.Ordering.Contracts.Services;
namespace ModularCrm.Ordering.Pages.Orders
{
public class IndexModel : PageModel
{
public List<Order> Orders { get; set; }
public List<OrderDto> Orders { get; set; }
private readonly IRepository<Order, Guid> _orderRepository;
private readonly IOrderAppService _orderAppService;
public IndexModel(IRepository<Order, Guid> orderRepository)
public IndexModel(IOrderAppService orderAppService)
{
_orderRepository = orderRepository;
_orderAppService = orderAppService;
}
public async Task OnGetAsync()
{
Orders = await _orderRepository.GetListAsync();
Orders = await _orderAppService.GetListAsync();
}
}
}
@ -310,14 +514,6 @@ Here, we are injecting a repository to query `Order` entities from the database
This page shows a list of orders on the UI. We haven't created a UI to create new orders, and we will not do it to keep this tutorial simple. If you want to learn how to create advanced UIs with ABP, please follow the [Book Store tutorial](../book-store/index.md).
### Creating Some Sample Data
You can open the database and manually create a few order records to show on the UI:
![sql-server-orders-table-content](images/sql-server-orders-table-content.png)
You can get `ProductId` values from the `Products` table and [generate](https://www.guidgenerator.com/) some random GUIDs for other GUID fields.
### Building the Application
Now, we will run the application to see the result. Please stop the application if it is already running. Then open the *Solution Runner* panel, right-click the `ModularCrm.Web` application, and select the *Build* -> *Graph Build* command:
@ -375,11 +571,13 @@ namespace ModularCrm.Ordering
`OrderingMenuContributor` implements the `IMenuContributor` interface, which forces us to implement the `ConfigureMenuAsync` method. In that method, we can manipulate the menu items (add new menu items, remove existing menu items or change the properties of existing menu items). The `ConfigureMenuAsync` method is executed whenever the menu is rendered on the UI, so you can dynamically decide how to manipulate the menu items.
After creating such a class, we should configure the `AbpNavigationOptions` to add that contributor. Open the `OrderingWebModule` class in the `ModularCrm.Ordering` project and add the following configuration code into the `ConfigureServices` method (if there is no `ConfigureServices` method, first create it as shown below):
After creating such a class, we should configure the `AbpNavigationOptions` to add that contributor. Open the `OrderingWebModule` class in the `ModularCrm.Ordering` project and add the following configuration code into the `ConfigureServices` method:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
//... other configurations
Configure<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new OrderingMenuContributor());

128
docs/en/tutorials/modular-crm/part-06.md

@ -145,68 +145,121 @@ ABP Studio adds the package reference and arranges the [module](../../framework/
Now, we can inject and use `IProductIntegrationService` in the Ordering module codebase.
Open the `IndexModel` class (the `IndexModel.cshtml.cs` file under the `Pages/Orders` folder of the `ModularCrm.Ordering` project of the `ModularCrm.Ordering` .NET solution) and change its content as like the following code block:
Open the `OrderAppService` class (the `OrderAppService.cs` file under the `Services` folder of the `ModularCrm.Ordering` project of the `ModularCrm.Ordering` .NET solution) and change its content as like the following code block:
````csharp
using Microsoft.AspNetCore.Mvc.RazorPages;
using ModularCrm.Ordering.Entities;
using ModularCrm.Products.Integration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ModularCrm.Ordering.Contracts.Enums;
using ModularCrm.Ordering.Contracts.Services;
using ModularCrm.Ordering.Entities;
using ModularCrm.Products.Integration;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace ModularCrm.Ordering.Pages.Orders
namespace ModularCrm.Ordering.Services;
public class OrderAppService : ApplicationService, IOrderAppService
{
public class IndexModel : PageModel
private readonly IRepository<Order> _orderRepository;
private readonly IProductIntegrationService _productIntegrationService;
public OrderAppService(
IRepository<Order, Guid> orderRepository,
IProductIntegrationService productIntegrationService)
{
public List<Order> Orders { get; set; }
// Define a dictionary for Id -> Name conversion
public Dictionary<Guid, string> ProductNames { get; set; }
_orderRepository = orderRepository;
_productIntegrationService = productIntegrationService;
ObjectMapperContext = typeof(OrderingWebModule);
}
private readonly IRepository<Order, Guid> _orderRepository;
private readonly IProductIntegrationService _productIntegrationService;
public async Task<List<OrderDto>> GetListAsync()
{
var orders = await _orderRepository.GetListAsync();
public IndexModel(
IRepository<Order, Guid> orderRepository,
IProductIntegrationService productIntegrationService)
// Prepare a list of products we need
var productIds = orders.Select(o => o.ProductId).Distinct().ToList();
var products = (await _productIntegrationService
.GetProductsByIdsAsync(productIds))
.ToDictionary(p => p.Id, p => p.Name);
var result = ObjectMapper.Map<List<Order>, List<OrderDto>>(orders);
result = result.Select(a =>
{
_orderRepository = orderRepository;
_productIntegrationService = productIntegrationService;
}
a.ProductName = products[a.ProductId];
return a;
})
.ToList();
return result;
}
public async Task OnGetAsync()
public async Task CreateAsync(OrderCreationDto input)
{
var order = new Order
{
// Getting the orders from this module's database
Orders = await _orderRepository.GetListAsync();
CustomerName = input.CustomerName,
ProductId = input.ProductId,
State = OrderState.Placed
};
await _orderRepository.InsertAsync(order);
}
}
````
// Prepare a list of products we need
var productIds = Orders.Select(o => o.ProductId).Distinct().ToList();
And also, open the `OrderDto` class (the `OrderDto.cs` file under the `Services` folder of the `ModularCrm.Ordering.Contracts` project of the `ModularCrm.Ordering` .NET solution) and add a `ProductName` property to it:
// Request the related products from the product integration service
var products = await _productIntegrationService
.GetProductsByIdsAsync(productIds);
````csharp
using System;
using ModularCrm.Ordering.Contracts.Enums;
// Create a dictionary to get a product name easily by its id
ProductNames = products.ToDictionary(p => p.Id, p => p.Name);
}
namespace ModularCrm.Ordering.Contracts.Services;
public class OrderDto
{
public Guid Id { get; set; }
public string CustomerName { get; set; }
public Guid ProductId { get; set; }
public string ProductName { get; set; } // New property
public OrderState State { get; set; }
}
````
Lastly, open the `OrderingApplicationAutoMapperProfile` class (the `OrderingApplicationAutoMapperProfile.cs` file under the `Services` folder of the `ModularCrm.Ordering` project of the `ModularCrm.Ordering` .NET solution) and ignore the `ProductName` property in the mapping configuration:
````csharp
using AutoMapper;
using ModularCrm.Ordering.Contracts.Services;
using ModularCrm.Ordering.Entities;
using Volo.Abp.AutoMapper;
namespace ModularCrm.Ordering;
public class OrderingApplicationAutoMapperProfile : Profile
{
public OrderingApplicationAutoMapperProfile()
{
CreateMap<Order, OrderDto>()
.Ignore(x => x.ProductName); // New line
}
}
````
Let's see what we've changed:
* We have defined a `ProductNames` dictionary. We will use it on the UI to convert product IDs to product names. We are filling that dictionary with products from the product integration service.
* We've added a `ProductName` property to the `OrderDto` class to store the product name.
* Injecting the `IProductIntegrationService` interface so we can use it to request products.
* In the `OnGetAsync` method;
* In the `GetListAsync` method;
* First getting the orders from the ordering module's database just like done before.
* Next, we are preparing a unique list of product IDs since the `GetProductsByIdsAsync` method requests it.
* Then we are calling the `IProductIntegrationService.GetProductsByIdsAsync` method to get a `List<ProductDto>` object.
* In the last line, we are converting the product list to a dictionary, where the key is `Guid Id` and the value is `string Name`. That way, we can easily find a product's name with its ID.
* Finally, we are mapping the orders to `OrderDto` objects and setting the product name by looking up the product ID in the dictionary.
Open the `Index.cshtml` file, and change the `@order.ProductId` part by `@Model.ProductNames[order.ProductId]` to write the product name instead of the product ID. The final `Index.cshtml` content should be the following:
Open the `Index.cshtml` file, and change the `@order.ProductId` part by `@Model.ProductName` to write the product name instead of the product ID. The final `Index.cshtml` content should be the following:
````html
@page
@ -219,11 +272,11 @@ Open the `Index.cshtml` file, and change the `@order.ProductId` part by `@Model.
<abp-list-group>
@foreach (var order in Model.Orders)
{
<abp-list-group-item>
<strong>Customer:</strong> @order.CustomerName <br />
<strong>Product:</strong> @Model.ProductNames[order.ProductId] <br />
<strong>State:</strong> @order.State
</abp-list-group-item>
<abp-list-group-item>
<strong>Customer:</strong> @order.CustomerName <br />
<strong>Product:</strong> @order.ProductName <br />
<strong>State:</strong> @order.State
</abp-list-group-item>
}
</abp-list-group>
</abp-card-body>
@ -241,4 +294,3 @@ In the way explained in this section, you can easily create integration services
> **Design Tip**
>
> It is suggested that you keep that type of communication to a minimum and not couple your modules with each other. It can make your solution complicated and may also decrease your system performance. When you need to do it, think about performance and try to make some optimizations. For example, if the Ordering module frequently needs product data, you can use a kind of [cache layer](../../framework/fundamentals/caching.md), so it doesn't make frequent requests to the Products module. Especially if you consider converting your system to a microservice solution in the future, too many direct integration API calls can be a performance bottleneck.

118
docs/en/tutorials/modular-crm/part-07.md

@ -56,83 +56,87 @@ namespace ModularCrm.Ordering.Contracts.Events
### Using the `IDistributedEventBus` Service
The `IDistributedEventBus` service publishes events to the event bus. Until this point, the Ordering module has no functionality to create new orders.
In Part 3, we used ABP's Auto HTTP API Controller feature to expose HTTP APIs from application services automatically. In this section, we will create an ASP.NET Core API controller class to create a new order. In that way, you will also see that it is not different from creating a regular ASP.NET Core controller.
Open the `ModularCrm.Ordering` module's .NET solution, create a `Controllers` folder in the `ModularCrm.Ordering` project and place a controller class named `OrdersController` in that new folder. The final folder structure should be like that:
![visual-studio-ordering-controller](images/visual-studio-ordering-controller.png)
Here is the full `OrdersController` class:
The `IDistributedEventBus` service publishes events to the event bus. Until this point, the Ordering module has no functionality to create new orders. Let's change that and place an order, for that purpose open the `ModularCrm.Ordering` module's .NET solution, and update the `OrderAppService` as follows:
````csharp
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ModularCrm.Ordering.Contracts.Enums;
using ModularCrm.Ordering.Contracts.Events;
using ModularCrm.Ordering.Contracts.Services;
using ModularCrm.Ordering.Entities;
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc;
using ModularCrm.Products.Integration;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus.Distributed;
namespace ModularCrm.Ordering.Controllers
namespace ModularCrm.Ordering.Services;
public class OrderAppService : ApplicationService, IOrderAppService
{
[Route("api/orders")]
[ApiController]
public class OrdersController : AbpControllerBase
private readonly IRepository<Order> _orderRepository;
private readonly IProductIntegrationService _productIntegrationService;
private readonly IDistributedEventBus _distributedEventBus;
public OrderAppService(
IRepository<Order, Guid> orderRepository,
IProductIntegrationService productIntegrationService,
IDistributedEventBus distributedEventBus)
{
private readonly IRepository<Order, Guid> _orderRepository;
private readonly IDistributedEventBus _distributedEventBus;
_orderRepository = orderRepository;
_productIntegrationService = productIntegrationService;
_distributedEventBus = distributedEventBus;
ObjectMapperContext = typeof(OrderingWebModule);
}
public OrdersController(
IRepository<Order, Guid> orderRepository,
IDistributedEventBus distributedEventBus)
{
_orderRepository = orderRepository;
_distributedEventBus = distributedEventBus;
}
public async Task<List<OrderDto>> GetListAsync()
{
var orders = await _orderRepository.GetListAsync();
// Prepare a list of products we need
var productIds = orders.Select(o => o.ProductId).Distinct().ToList();
var products = (await _productIntegrationService
.GetProductsByIdsAsync(productIds))
.ToDictionary(p => p.Id, p => p.Name);
[HttpPost]
public async Task<IActionResult> CreateAsync(OrderCreationModel input)
var result = ObjectMapper.Map<List<Order>, List<OrderDto>>(orders);
result = result.Select(a =>
{
// Create a new Order entity
var order = new Order
{
CustomerName = input.CustomerName,
ProductId = input.ProductId,
State = OrderState.Placed
};
// Save it to the database
await _orderRepository.InsertAsync(order);
// Publish an event so other modules can be informed
await _distributedEventBus.PublishAsync(
new OrderPlacedEto
{
ProductId = order.ProductId,
CustomerName = order.CustomerName
});
return Created();
}
a.ProductName = products[a.ProductId];
return a;
})
.ToList();
public class OrderCreationModel
return result;
}
public async Task CreateAsync(OrderCreationDto input)
{
// Create a new Order entity
var order = new Order
{
public Guid ProductId { get; set; }
CustomerName = input.CustomerName,
ProductId = input.ProductId,
State = OrderState.Placed
};
[Required]
[StringLength(120)]
public string CustomerName { get; set; }
}
// Save it to the database
await _orderRepository.InsertAsync(order);
// Publish an event so other modules can be informed
await _distributedEventBus.PublishAsync(
new OrderPlacedEto
{
ProductId = order.ProductId,
CustomerName = order.CustomerName
});
}
}
````
The `OrdersController.CreateAsync` method creates a new `Order` entity, saves it to the database and finally publishes an `OrderPlacedEto` event.
The `OrderAppService.CreateAsync` method creates a new `Order` entity, saves it to the database and finally publishes an `OrderPlacedEto` event.
## Subscribing to an Event

2
framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo.Abp.ApiVersioning.Abstractions.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.ApiVersioning.Abstractions</AssemblyName>

2
framework/src/Volo.Abp.AspNetCore.Abstractions/Volo.Abp.AspNetCore.Abstractions.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore.Abstractions</AssemblyName>

2
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore.Authentication.JwtBearer</AssemblyName>

2
framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore.Authentication.OAuth</AssemblyName>

2
framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo.Abp.AspNetCore.Authentication.OpenIdConnect.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<RootNamespace />

2
framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Theming/Volo.Abp.AspNetCore.Components.MauiBlazor.Theming.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
</PropertyGroup>

2
framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor/Volo.Abp.AspNetCore.Components.MauiBlazor.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore.Components.MauiBlazor</AssemblyName>

2
framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Volo.Abp.AspNetCore.Components.Server.Theming.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<IsPackable>true</IsPackable>

2
framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<IsPackable>true</IsPackable>

2
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Volo.Abp.AspNetCore.Components.Web.Theming.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
</PropertyGroup>

2
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo.Abp.AspNetCore.Components.Web.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<RootNamespace />

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
</PropertyGroup>

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo.Abp.AspNetCore.Components.WebAssembly.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore.Components.WebAssembly</AssemblyName>

2
framework/src/Volo.Abp.AspNetCore.Components/Volo.Abp.AspNetCore.Components.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore.Components</AssemblyName>

2
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo.Abp.AspNetCore.MultiTenancy.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore.MultiTenancy</AssemblyName>

2
framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo.Abp.AspNetCore.Mvc.Client.Common.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.Client.Common</AssemblyName>

2
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.Client</AssemblyName>

2
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.Contracts</AssemblyName>

2
framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<RootNamespace />

2
framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo.Abp.AspNetCore.Mvc.Dapr.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<RootNamespace />

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<RootNamespace />

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo.Abp.AspNetCore.Mvc.UI.Packages.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>

2
framework/src/Volo.Abp.AspNetCore.Serilog/Volo.Abp.AspNetCore.Serilog.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore.Serilog</AssemblyName>

2
framework/src/Volo.Abp.AspNetCore.SignalR/Volo.Abp.AspNetCore.SignalR.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore.SignalR</AssemblyName>

2
framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore.TestBase</AssemblyName>

9
framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/WebApplicationBuilderExtensions.cs

@ -9,15 +9,16 @@ namespace Volo.Abp.AspNetCore.TestBase;
public static class WebApplicationBuilderExtensions
{
public async static Task RunAbpModuleAsync<TModule>(this WebApplicationBuilder builder, Action<AbpApplicationCreationOptions>? optionsAction = null)
public async static Task RunAbpModuleAsync<TModule>(this WebApplicationBuilder builder, Action<AbpApplicationCreationOptions>? optionsAction = null, string? applicationName = null)
where TModule : IAbpModule
{
var assemblyName = typeof(TModule).Assembly.GetName()?.Name;
if (!assemblyName.IsNullOrWhiteSpace())
applicationName = applicationName ?? typeof(TModule).Assembly.GetName()?.Name;
if (!applicationName.IsNullOrWhiteSpace())
{
// Set the application name as the assembly name of the module will automatically add assembly to the ApplicationParts of MVC application.
builder.Environment.ApplicationName = assemblyName!;
builder.Environment.ApplicationName = applicationName;
}
builder.Host.UseAutofac();
await builder.AddApplicationAsync<TModule>(optionsAction);
var app = builder.Build();

28
framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/WebProjectPatchHelper.cs

@ -0,0 +1,28 @@
using System.IO;
namespace Volo.Abp.AspNetCore.TestBase;
public static class GetWebProjectContentRootPathHelper
{
public static string Get(string webProjectName)
{
var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());
while (currentDirectory != null && Directory.GetParent(currentDirectory.FullName) != null)
{
currentDirectory = Directory.GetParent(currentDirectory.FullName);
if (currentDirectory == null)
{
continue;
}
var files = currentDirectory.GetFiles(webProjectName, SearchOption.AllDirectories);
if (files.Length > 0)
{
return files[0].DirectoryName!;
}
}
throw new AbpException($"Web project({webProjectName}) not found!");
}
}

79
framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs

@ -1,9 +1,15 @@
using System;
using System.IO;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.RequestLocalization;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.StaticAssets;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.AspNetCore.Auditing;
using Volo.Abp.AspNetCore.ExceptionHandling;
@ -11,8 +17,10 @@ using Volo.Abp.AspNetCore.Security;
using Volo.Abp.AspNetCore.Security.Claims;
using Volo.Abp.AspNetCore.Tracing;
using Volo.Abp.AspNetCore.Uow;
using Volo.Abp.AspNetCore.VirtualFileSystem;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
using Volo.Abp.VirtualFileSystem;
namespace Microsoft.AspNetCore.Builder;
@ -117,4 +125,75 @@ public static class AbpApplicationBuilderExtensions
{
return app.UseMiddleware<AbpDynamicClaimsMiddleware>();
}
/// <summary>
/// MapAbpStaticAssets is used to serve the files from the abp virtual file system embedded resources(js/css) and call the MapStaticAssets.
/// </summary>
public static StaticAssetsEndpointConventionBuilder MapAbpStaticAssets(this WebApplication app, string? staticAssetsManifestPath = null)
{
return app.As<IApplicationBuilder>().MapAbpStaticAssets(staticAssetsManifestPath);
}
/// <summary>
/// MapAbpStaticAssets is used to serve the files from the abp virtual file system embedded resources(js/css) and call the MapStaticAssets.
/// </summary>
public static StaticAssetsEndpointConventionBuilder MapAbpStaticAssets(this IApplicationBuilder app, string? staticAssetsManifestPath = null)
{
if (app is not IEndpointRouteBuilder endpoints)
{
throw new AbpException("The app(IApplicationBuilder) is not an IEndpointRouteBuilder.");
}
app.UseVirtualStaticFiles();
var options = app.ApplicationServices.GetRequiredService<IOptions<AbpAspNetCoreContentOptions>>().Value;
foreach (var folder in options.AllowedExtraWebContentFolders)
{
app.UseVirtualStaticFiles(folder);
}
return endpoints.MapStaticAssets(staticAssetsManifestPath);
}
/// <summary>
/// This static file provider is used to serve the files from the abp virtual file system embedded resources(js/css).
/// It will not serve the files from the application's wwwroot folder.
/// </summary>
public static IApplicationBuilder UseVirtualStaticFiles(this IApplicationBuilder app)
{
app.UseStaticFiles(new StaticFileOptions()
{
ContentTypeProvider = app.ApplicationServices.GetRequiredService<AbpFileExtensionContentTypeProvider>(),
FileProvider = new WebContentFileProvider(
app.ApplicationServices.GetRequiredService<IVirtualFileProvider>(),
new EmptyHostingEnvironment(),
app.ApplicationServices.GetRequiredService<IOptions<AbpAspNetCoreContentOptions>>()
)
});
return app;
}
/// <summary>
/// This static file provider is used to serve the files from the <param name="folder">folder</param>.
/// </summary>
public static IApplicationBuilder UseVirtualStaticFiles(this IApplicationBuilder app, string folder)
{
folder = folder.TrimStart('/').TrimEnd('/');
var root = Path.Combine(app.ApplicationServices.GetRequiredService<IWebHostEnvironment>().ContentRootPath, folder);
if (!Directory.Exists(root))
{
return app;
}
app.UseStaticFiles(new StaticFileOptions
{
ContentTypeProvider = app.ApplicationServices.GetRequiredService<AbpFileExtensionContentTypeProvider>(),
FileProvider = new PhysicalFileProvider(root),
RequestPath = $"/{folder}"
});
return app;
}
}

2
framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AspNetCore</AssemblyName>

19
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/WebContentFileProvider.cs

@ -85,23 +85,22 @@ public class WebContentFileProvider : IWebContentFileProvider, ISingletonDepende
return new CompositeChangeToken(
new[]
{
_fileProvider.Watch(_rootPath + filter),
_fileProvider.Watch(filter)
_fileProvider.Watch(_rootPath + filter),
_fileProvider.Watch(filter)
}
);
}
protected virtual IFileProvider CreateFileProvider()
{
var fileProviders = new List<IFileProvider>
{
new PhysicalFileProvider(_hostingEnvironment.ContentRootPath),
_virtualFileProvider
};
var fileProviders = new List<IFileProvider>();
if (!_hostingEnvironment.ContentRootPath.IsNullOrEmpty())
{
fileProviders.Add(new PhysicalFileProvider(_hostingEnvironment.ContentRootPath));
}
return new CompositeFileProvider(
fileProviders
);
fileProviders.Add(_virtualFileProvider);
return new CompositeFileProvider(fileProviders);
}
protected virtual bool ExtraAllowedFolder(string path)

2
framework/src/Volo.Abp.Auditing.Contracts/Volo.Abp.Auditing.Contracts.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.Auditing.Contracts</AssemblyName>

2
framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.Auditing</AssemblyName>

2
framework/src/Volo.Abp.Authorization.Abstractions/Volo.Abp.Authorization.Abstractions.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.Authorization.Abstractions</AssemblyName>

2
framework/src/Volo.Abp.Authorization/Volo.Abp.Authorization.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.Authorization</AssemblyName>

2
framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AutoMapper</AssemblyName>

2
framework/src/Volo.Abp.Autofac.WebAssembly/Volo.Abp.Autofac.WebAssembly.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<RootNamespace />

2
framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.Autofac</AssemblyName>

2
framework/src/Volo.Abp.AzureServiceBus/Volo.Abp.AzureServiceBus.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.AzureServiceBus</AssemblyName>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save