Browse Source

Merge branch 'dev' into dev

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

122
Directory.Packages.props

@ -51,69 +51,70 @@
<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.Hybrid" Version="9.0.0-preview.7.24406.2" />
<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 +128,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 +155,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 +175,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>

3
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json

@ -251,6 +251,7 @@
"VideoCourses": "Essential Videos",
"DoYouAgreePrivacyPolicy": "By clicking <b>Subscribe</b> button you agree to the <a href=\"https://account.abp.io/Account/TermsConditions\">Terms & Conditions</a> and <a href=\"https://account.abp.io/Account/Privacy\">Privacy Policy</a>.",
"AbpConferenceDescription": "ABP Conference is a virtual event for .NET developers to learn and connect with the community.",
"Mobile": "Mobile"
"Mobile": "Mobile",
"MetaTwitterCard": "summary_large_image"
}
}

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:

99
docs/en/Community-Articles/2024-10-01-SignalR-9-New-Features/Post.md

@ -0,0 +1,99 @@
### ASP.NET Core SignalR New Features — Summary
In this article, I’ll highlight the latest .**NET 9 SignalR updates** for ASP.NET Core 9.0.
![Cover](cover.png)
### SignalR Hub Accepts Base Classes
SignalR `Hub` class can now get a base class of a polymorphic class. As you see in the example below, I can send `Animal` to `Process` method. Before .NET 9, we could only pass the derived classes: `Cat` and `Dog`.
```csharp
/*** My Base Class is Animal ***/
[JsonPolymorphic]
[JsonDerivedType(typeof(Cat), nameof(Cat))]
[JsonDerivedType(typeof(Dog), nameof(Dog))]
private class Animal
{
public string Name { get; set; }
}
/*** CAT derived from Animal ***/
private class Cat : Animal
{
public CatTypes CatType { get; set; }
}
/*** DOG derived from Animal ***/
private class Dog : Animal
{
public DogTypes DogType { get; set; }
}
public class MyHub : Hub
{
/*** We can use the base type Animal here ***/
public void Process(Animal animal)
{
if (animal is Cat) { ... }
else if (animal is Dog) { ... }
}
}
```
### Better Diagnostics and Telemetry
Microsoft focuses mainly on .NET Aspire nowadays. That’s why SignalR now integrates more deeply with the .NET Activity API, which is commonly used for distributed tracing. The enhancement is implemented for better monitoring in [.NET Aspire Dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview?tabs=bash#using-the-dashboard-with-net-aspire-projects). To support this feature:
1- Add these packages to your`csproj`:
```xml
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
```
2- Add the following startup code to your host project:
```csharp
builder.Services.AddSignalR();
/* After AddSignalR use AddOpenTelemetry() */
builder
.Services
.AddOpenTelemetry()
.WithTracing(tracing =>
{
if (builder.Environment.IsDevelopment())
{
tracing.SetSampler(new AlwaysOnSampler()); //for dev env monitor all traces
}
tracing.AddAspNetCoreInstrumentation();
tracing.AddSource("Microsoft.AspNetCore.SignalR.Server");
});
builder.Services.ConfigureOpenTelemetryTracerProvider(tracing => tracing.AddOtlpExporter());
```
Finally, you’ll see the **SignalR Hub** events on the [Aspire Dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview):
![.NET Aspire Activity Dashboard](signalr-activity-dashboard.png)
### Trimming and Native AOT Support
With .NET 9, **trimming** and **native** **Ahead Of Time** compilation are **supported**. This will improve our application performance. To support AOT, your SignalR object serialization needs to be JSON, and you must use the `System.Text.Json` s[ource generator](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation). Also on the server side, [you shouldn't use](https://github.com/dotnet/aspnetcore/issues/56179) `IAsyncEnumerable<T>` and `ChannelReader<T>` where `T` is a ValueType (`struct`) for Hub method arguments. One more limitation; [Strongly typed hubs](https://learn.microsoft.com/en-us/aspnet/core/signalr/hubs?view=aspnetcore-8.0#strongly-typed-hubs) aren't supported with Native AOT (`PublishAot`). And you should use only `Task`, `Task<T>`, `ValueTask`, `ValueTask<T>` for `async` return types.
---
That's all the new features coming to SignalR in .NET 9!
Happy coding 🧑🏽‍💻

BIN
docs/en/Community-Articles/2024-10-01-SignalR-9-New-Features/cover.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 KiB

BIN
docs/en/Community-Articles/2024-10-01-SignalR-9-New-Features/signalr-activity-dashboard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

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.
});
}
````

2
docs/en/framework/ui/blazor/branding.md

@ -24,8 +24,6 @@ namespace MyCompanyName.MyProjectName.Blazor
}
````
> Currently, setting the `AppName` is only applicable to the [Basic Theme](./basic-theme.md), it does not have any effect on the other [official themes](../../../ui-themes).
The result will be like shown below:
![branding-appname](../../../images/branding-appname.png)

2
docs/en/framework/ui/mvc-razor-pages/branding.md

@ -26,8 +26,6 @@ namespace MyProject.Web
}
````
> Currently, setting the `AppName` is only applicable to the [Basic Theme](./basic-theme.md), it does not have any effect on the other [official themes](../../../ui-themes).
The result will be like shown below:
![bookstore-added-logo](../../../images/bookstore-added-logo.png)

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

4
docs/en/modules/docs.md

@ -367,7 +367,7 @@ You can use [ABP](https://github.com/abpframework/abp/) GitHub documents to conf
For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName], [ConcurrencyStamp]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL, N'', N'12f21123e08e4f15bedbae0b2d939659')
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName], [ConcurrencyStamp]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP (GitHub)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'GitHub', N'{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs","GitHubAccessToken":"","GitHubUserAgent":""}', N'/', N'dev', N'', N'12f21123e08e4f15bedbae0b2d939659')
```
Be aware that `GitHubAccessToken` is masked. It's a private token and you must get your own token and replace the `***` string.
@ -407,7 +407,7 @@ You can use [ABP](https://github.com/abpframework/abp/) GitHub documents to conf
For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL, N'')
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName], [ConcurrencyStamp]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL, N'', N'12f21123e08e4f15bedbae0b2d939659')
```
Add one of the sample projects above and run the application. In the menu you will see `Documents` link, click the menu link to open the documents page.

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

63
docs/en/release-info/migration-guides/abp-8-2.md

@ -16,9 +16,6 @@ This document is a guide for upgrading ABP v8.x solutions to ABP v8.2. There are
Before this version, all of the projects above were targeting multiple frameworks (**netstandard2.0**, **netstandard2.1** and **net8.0**), with this version, we started to only target **net8.0** for these template projects. Note that, all other shared libraries still target multiple frameworks.
> This change should not affect your pre-existing solutions and you don't need to make any changes in your application. See the PR for more info: https://github.com/abpframework/abp/pull/19565
## Upgraded AutoMapper to 13.0.1
In this version, **AutoMapper** library version upgraded to 13.0.1. See [the release notes of AutoMapper v13.0.1](https://github.com/AutoMapper/AutoMapper/releases/tag/v13.0.1) for more information.
## Added default padding to `.tab-content` class for Basic Theme
@ -60,4 +57,62 @@ In this version, the Angular UI has been updated to use the Angular version 17.3
The **Session Management** feature allows you to prevent concurrent login and manage user sessions.
In this version, a new entity called `IdentitySession` has been added to the framework and you should create a new migration and apply it to your database.
In this version, a new entity called `IdentitySession` has been added to the framework and you should create a new migration and apply it to your database.
## Upgraded NuGet Dependencies
You can see the following list of NuGet libraries that have been upgraded with this release, if you are using one of these packages explicitly, you may consider upgrading them in your solution:
| Package | Old Version | New Version |
| ---------------------------------------------------------- | ----------- | ----------- |
| AutoMapper | 12.0.1 | 13.0.1 |
| Blazorise | 1.4.1 | 1.5.2 |
| Blazorise.Bootstrap5 | 1.4.1 | 1.5.2 |
| Blazorise.Icons.FontAwesome | 1.4.1 | 1.5.2 |
| Blazorise.Components | 1.4.1 | 1.5.2 |
| Blazorise.DataGrid | 1.4.1 | 1.5.2 |
| Blazorise.Snackbar | 1.4.1 | 1.5.2 |
| Hangfire.AspNetCore | 1.8.6 | 1.8.14 |
| Hangfire.SqlServer | 1.8.6 | 1.8.14 |
| Microsoft.AspNetCore.Authentication.JwtBearer | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.Authentication.OpenIdConnect | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.Authorization | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.Components | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.Components.Authorization | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.Components.Web | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.Components.WebAssembly | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.Components.WebAssembly.Server | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.Components.WebAssembly.Authentication | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.Components.WebAssembly.DevServer | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.DataProtection.StackExchangeRedis | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.Mvc.NewtonsoftJson | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.Mvc.Testing | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.TestHost | 8.0.0 | 8.0.4 |
| Microsoft.AspNetCore.WebUtilities | 8.0.0 | 8.0.4 |
| Microsoft.Data.SqlClient | 8.0.0 | 8.0.4 |
| Microsoft.EntityFrameworkCore | 8.0.0 | 8.0.4 |
| Microsoft.EntityFrameworkCore.Design | 8.0.0 | 8.0.4 |
| Microsoft.EntityFrameworkCore.InMemory | 8.0.0 | 8.0.4 |
| Microsoft.EntityFrameworkCore.Proxies | 8.0.0 | 8.0.4 |
| Microsoft.EntityFrameworkCore.Relational | 8.0.0 | 8.0.4 |
| Microsoft.EntityFrameworkCore.Sqlite | 8.0.0 | 8.0.4 |
| Microsoft.EntityFrameworkCore.SqlServer | 8.0.0 | 8.0.4 |
| Microsoft.EntityFrameworkCore.Tools | 8.0.0 | 8.0.4 |
| Microsoft.Extensions.DependencyInjection.Abstractions | 8.0.0 | 8.0.1 |
| Microsoft.Extensions.FileProviders.Embedded | 8.0.0 | 8.0.4 |
| Microsoft.Extensions.Logging.Abstractions | 8.0.0 | 8.0.1 |
| Microsoft.Extensions.Options | 8.0.0 | 8.0.2 |
| Microsoft.IdentityModel.Protocols.OpenIdConnect | - | 7.5.1 |
| Microsoft.IdentityModel.Tokens | - | 7.5.1 |
| Microsoft.IdentityModel.JsonWebTokens | - | 7.5.1 |
| System.IdentityModel.Tokens.Jwt | - | 7.5.1 |
| OpenIddict.Abstractions | 5.1.0 | 5.5.0 |
| OpenIddict.Core | 5.1.0 | 5.5.0 |
| OpenIddict.Server.AspNetCore | 5.1.0 | 5.5.0 |
| OpenIddict.Validation.AspNetCore | 5.1.0 | 5.5.0 |
| OpenIddict.Validation.ServerIntegration | 5.1.0 | 5.5.0 |
| Oracle.EntityFrameworkCore | 8.21.121 | 8.23.40 |
| Pomelo.EntityFrameworkCore.MySql | 8.0.0 | 8.0.2 |
| SixLabors.ImageSharp | 3.0.2 | 3.1.4 |

1
docs/en/release-info/migration-guides/pro/openiddict-mvc.md

@ -261,6 +261,7 @@ This project is renamed to **AuthServer** after v6.0.0. You can also refactor an
"RequireHttpsMetadata": "false",
"SwaggerClientId": "MyApplication_Swagger"
},
```
## See Also

3
docs/en/tutorials/microservice/index.md

@ -0,0 +1,3 @@
# Microservice Development Tutorial
This tutorial is work in progress. Please check later. You can check here to [see the draft tutorial](https://github.com/abpframework/abp/blob/microservice-tutorial/docs/en/tutorials/microservice/index.md).

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>

4
framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs

@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.Threading;
namespace Microsoft.AspNetCore.Authentication.Cookies;
@ -70,7 +71,8 @@ public static class CookieAuthenticationOptionsExtensions
var openIdConnectOptions = principalContext.HttpContext.RequestServices.GetRequiredService<IOptionsMonitor<OpenIdConnectOptions>>().Get(oidcAuthenticationScheme);
if (openIdConnectOptions.Configuration == null && openIdConnectOptions.ConfigurationManager != null)
{
openIdConnectOptions.Configuration = await openIdConnectOptions.ConfigurationManager.GetConfigurationAsync(principalContext.HttpContext.RequestAborted);
var cancellationTokenProvider = principalContext.HttpContext.RequestServices.GetRequiredService<ICancellationTokenProvider>();
openIdConnectOptions.Configuration = await openIdConnectOptions.ConfigurationManager.GetConfigurationAsync(cancellationTokenProvider.Token);
}
return openIdConnectOptions;

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>

14
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyOptions.cs

@ -19,6 +19,7 @@ using Microsoft.Net.Http.Headers;
using Volo.Abp.Http;
using Volo.Abp.Json;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
namespace Volo.Abp.AspNetCore.MultiTenancy;
@ -92,15 +93,16 @@ public class AbpAspNetCoreMultiTenancyOptions
context.Response.ContentType = resolvedContentType;
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
var cancellationTokenProvider = context.RequestServices.GetRequiredService<ICancellationTokenProvider>();
var responseStream = context.Response.Body;
if (resolvedContentTypeEncoding.CodePage == Encoding.UTF8.CodePage)
{
try
{
await JsonSerializer.SerializeAsync(responseStream, error, error.GetType(), jsonSerializerOptions, context.RequestAborted);
await responseStream.FlushAsync(context.RequestAborted);
await JsonSerializer.SerializeAsync(responseStream, error, error.GetType(), jsonSerializerOptions, cancellationTokenProvider.Token);
await responseStream.FlushAsync(cancellationTokenProvider.Token);
}
catch (OperationCanceledException) when (context.RequestAborted.IsCancellationRequested) { }
catch (OperationCanceledException) when (cancellationTokenProvider.Token.IsCancellationRequested) { }
}
else
{
@ -108,10 +110,10 @@ public class AbpAspNetCoreMultiTenancyOptions
ExceptionDispatchInfo? exceptionDispatchInfo = null;
try
{
await JsonSerializer.SerializeAsync(transcodingStream, error, error.GetType(), jsonSerializerOptions, context.RequestAborted);
await transcodingStream.FlushAsync(context.RequestAborted);
await JsonSerializer.SerializeAsync(transcodingStream, error, error.GetType(), jsonSerializerOptions, cancellationTokenProvider.Token);
await transcodingStream.FlushAsync(cancellationTokenProvider.Token);
}
catch (OperationCanceledException) when (context.RequestAborted.IsCancellationRequested) { }
catch (OperationCanceledException) when (cancellationTokenProvider.Token.IsCancellationRequested) { }
catch (Exception ex)
{
exceptionDispatchInfo = ExceptionDispatchInfo.Capture(ex);

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>

21
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs

@ -1,11 +1,13 @@
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
using Volo.Abp.Uow;
namespace Volo.Abp.AspNetCore.Mvc.Uow;
@ -37,6 +39,7 @@ public class AbpUowActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDepe
var options = CreateOptions(context, unitOfWorkAttr);
var unitOfWorkManager = context.GetRequiredService<IUnitOfWorkManager>();
var cancellationTokenProvider = context.GetRequiredService<ICancellationTokenProvider>();
//Trying to begin a reserved UOW by AbpUnitOfWorkMiddleware
if (unitOfWorkManager.TryBeginReserved(UnitOfWork.UnitOfWorkReservationName, options))
@ -44,11 +47,11 @@ public class AbpUowActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDepe
var result = await next();
if (Succeed(result))
{
await SaveChangesAsync(context, unitOfWorkManager);
await SaveChangesAsync(context, unitOfWorkManager, cancellationTokenProvider.Token);
}
else
{
await RollbackAsync(context, unitOfWorkManager);
await RollbackAsync(context, unitOfWorkManager, cancellationTokenProvider.Token);
}
return;
@ -59,11 +62,11 @@ public class AbpUowActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDepe
var result = await next();
if (Succeed(result))
{
await uow.CompleteAsync(context.HttpContext.RequestAborted);
await uow.CompleteAsync(cancellationTokenProvider.Token);
}
else
{
await uow.RollbackAsync(context.HttpContext.RequestAborted);
await uow.RollbackAsync(cancellationTokenProvider.Token);
}
}
}
@ -85,27 +88,27 @@ public class AbpUowActionFilter : IAsyncActionFilter, IAbpFilter, ITransientDepe
return options;
}
private async Task RollbackAsync(ActionExecutingContext context, IUnitOfWorkManager unitOfWorkManager)
private async Task RollbackAsync(ActionExecutingContext context, IUnitOfWorkManager unitOfWorkManager, CancellationToken cancellationToken)
{
var currentUow = unitOfWorkManager.Current;
if (currentUow != null)
{
await currentUow.RollbackAsync(context.HttpContext.RequestAborted);
await currentUow.RollbackAsync(cancellationToken);
}
}
private async Task SaveChangesAsync(ActionExecutingContext context, IUnitOfWorkManager unitOfWorkManager)
private async Task SaveChangesAsync(ActionExecutingContext context, IUnitOfWorkManager unitOfWorkManager, CancellationToken cancellationToken)
{
var currentUow = unitOfWorkManager.Current;
if (currentUow != null)
{
try
{
await currentUow.SaveChangesAsync(context.HttpContext.RequestAborted);
await currentUow.SaveChangesAsync(cancellationToken);
}
catch (Exception e)
{
await currentUow.RollbackAsync(context.HttpContext.RequestAborted);
await currentUow.RollbackAsync(cancellationToken);
throw;
}
}

21
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs

@ -1,5 +1,6 @@
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
@ -7,6 +8,7 @@ using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Filters;
using Volo.Abp.AspNetCore.Uow;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
using Volo.Abp.Uow;
namespace Volo.Abp.AspNetCore.Mvc.Uow;
@ -43,6 +45,7 @@ public class AbpUowPageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependen
var options = CreateOptions(context, unitOfWorkAttr);
var unitOfWorkManager = context.GetRequiredService<IUnitOfWorkManager>();
var cancellationTokenProvider = context.GetRequiredService<ICancellationTokenProvider>();
//Trying to begin a reserved UOW by AbpUnitOfWorkMiddleware
if (unitOfWorkManager.TryBeginReserved(UnitOfWork.UnitOfWorkReservationName, options))
@ -50,11 +53,11 @@ public class AbpUowPageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependen
var result = await next();
if (Succeed(result))
{
await SaveChangesAsync(context, unitOfWorkManager);
await SaveChangesAsync(context, unitOfWorkManager, cancellationTokenProvider.Token);
}
else
{
await RollbackAsync(context, unitOfWorkManager);
await RollbackAsync(context, unitOfWorkManager, cancellationTokenProvider.Token);
}
return;
@ -65,11 +68,11 @@ public class AbpUowPageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependen
var result = await next();
if (Succeed(result))
{
await uow.CompleteAsync(context.HttpContext.RequestAborted);
await uow.CompleteAsync(cancellationTokenProvider.Token);
}
else
{
await uow.RollbackAsync(context.HttpContext.RequestAborted);
await uow.RollbackAsync(cancellationTokenProvider.Token);
}
}
}
@ -91,27 +94,27 @@ public class AbpUowPageFilter : IAsyncPageFilter, IAbpFilter, ITransientDependen
return options;
}
private async Task RollbackAsync(PageHandlerExecutingContext context, IUnitOfWorkManager unitOfWorkManager)
private async Task RollbackAsync(PageHandlerExecutingContext context, IUnitOfWorkManager unitOfWorkManager, CancellationToken cancellationToken)
{
var currentUow = unitOfWorkManager.Current;
if (currentUow != null)
{
await currentUow.RollbackAsync(context.HttpContext.RequestAborted);
await currentUow.RollbackAsync(cancellationToken);
}
}
private async Task SaveChangesAsync(PageHandlerExecutingContext context, IUnitOfWorkManager unitOfWorkManager)
private async Task SaveChangesAsync(PageHandlerExecutingContext context, IUnitOfWorkManager unitOfWorkManager, CancellationToken cancellationToken)
{
var currentUow = unitOfWorkManager.Current;
if (currentUow != null)
{
try
{
await currentUow.SaveChangesAsync(context.HttpContext.RequestAborted);
await currentUow.SaveChangesAsync(cancellationToken);
}
catch (Exception e)
{
await currentUow.RollbackAsync(context.HttpContext.RequestAborted);
await currentUow.RollbackAsync(cancellationToken);
throw;
}
}

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>

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

Loading…
Cancel
Save