Browse Source

Merge branch 'dev' into openiddict6

pull/20979/head
maliming 1 year ago
parent
commit
90c206505b
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 20
      .github/workflows/auto-pr.yml
  2. 2
      .github/workflows/build-and-test.yml
  3. 113
      Directory.Packages.props
  4. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  5. 223
      docs/en/Blog-Posts/2024-10-23 v9_0_Preview/POST.md
  6. BIN
      docs/en/Blog-Posts/2024-10-23 v9_0_Preview/abp-team-raffle.jpg
  7. BIN
      docs/en/Blog-Posts/2024-10-23 v9_0_Preview/cover-image.png
  8. BIN
      docs/en/Blog-Posts/2024-10-23 v9_0_Preview/docs-image-larger.png
  9. BIN
      docs/en/Blog-Posts/2024-10-23 v9_0_Preview/dotnet-conf-2024.png
  10. BIN
      docs/en/Blog-Posts/2024-10-23 v9_0_Preview/dotnet-developer-days-2024.jpg
  11. BIN
      docs/en/Blog-Posts/2024-10-23 v9_0_Preview/studio-switch-to-preview.png
  12. BIN
      docs/en/Blog-Posts/2024-10-23 v9_0_Preview/suite-navigation-properties.png
  13. 4
      docs/en/Community-Articles/2022-11-14-How-to-add-a-custom-grant-type-in-OpenIddict/POST.md
  14. 4
      docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/How to use Aspire with ABP framework.md
  15. 63
      docs/en/Community-Articles/2024-10-09-Cookies-vs-Local-Storage/Post.md
  16. BIN
      docs/en/Community-Articles/2024-10-09-Cookies-vs-Local-Storage/cover.png
  17. 2
      docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/Post.md
  18. BIN
      docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/cited-from-microsoft-blog-post.png
  19. BIN
      docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/cover.png
  20. 138
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/POST.md
  21. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-overall-diagram.png
  22. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-add-existing-package.png
  23. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-add-new-microservice.png
  24. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-solution-runner.png
  25. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-vs-dotnet-aspire-comparison-table.png
  26. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/cover.png
  27. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/dotnet-aspire-dashboard.png
  28. BIN
      docs/en/Community-Articles/2024-10-23-Abp-Net9-Upgrade/cover.png
  29. BIN
      docs/en/Community-Articles/2024-10-23-Abp-Net9-Upgrade/dog-food.png
  30. BIN
      docs/en/Community-Articles/2024-10-23-Abp-Net9-Upgrade/ef-core-upgrade.png
  31. BIN
      docs/en/Community-Articles/2024-10-23-Abp-Net9-Upgrade/net-support-policy.png
  32. 147
      docs/en/Community-Articles/2024-10-23-Abp-Net9-Upgrade/post.md
  33. 125
      docs/en/Community-Articles/2024-11-01-Hybrid-Cache-Net-9/POST.md
  34. BIN
      docs/en/Community-Articles/2024-11-01-Hybrid-Cache-Net-9/cover-image.png
  35. BIN
      docs/en/Community-Articles/2024-11-01-Hybrid-Cache-Net-9/debug-hybrid-cache.png
  36. 5
      docs/en/cli/index.md
  37. 60
      docs/en/deployment/clustered-environment.md
  38. 4
      docs/en/deployment/configuring-openIddict.md
  39. 37
      docs/en/deployment/configuring-production.md
  40. 12
      docs/en/deployment/distributed-microservice.md
  41. 4
      docs/en/deployment/index.md
  42. 20
      docs/en/deployment/optimizing-production.md
  43. 19
      docs/en/deployment/ssl.md
  44. 80
      docs/en/docs-nav.json
  45. 6
      docs/en/framework/architecture/domain-driven-design/specifications.md
  46. 2
      docs/en/framework/architecture/modularity/extending/module-entity-extensions.md
  47. 4
      docs/en/framework/data/entity-framework-core/migrations.md
  48. 8
      docs/en/framework/fundamentals/exception-handling.md
  49. 4
      docs/en/framework/fundamentals/localization.md
  50. 2
      docs/en/framework/infrastructure/audit-logging.md
  51. 2
      docs/en/framework/infrastructure/json.md
  52. 12
      docs/en/framework/ui/angular/account-module.md
  53. 2
      docs/en/framework/ui/angular/current-user.md
  54. 6
      docs/en/framework/ui/angular/datetime-format-pipe.md
  55. 2
      docs/en/framework/ui/angular/http-error-handling.md
  56. BIN
      docs/en/framework/ui/angular/images/list-service-request-status.gif
  57. 99
      docs/en/framework/ui/angular/list-service.md
  58. 4
      docs/en/framework/ui/angular/localization.md
  59. 2
      docs/en/framework/ui/angular/sorting-navigation-elements.md
  60. 2
      docs/en/framework/ui/mvc-razor-pages/basic-theme.md
  61. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-additional-options-microservice.png
  62. BIN
      docs/en/get-started/images/abp-studio-new-solution-dialog-additional-options.png
  63. 4
      docs/en/get-started/layered-web-application.md
  64. 2
      docs/en/get-started/microservice.md
  65. BIN
      docs/en/images/my-externa-logins.png
  66. BIN
      docs/en/images/new-external-login.png
  67. BIN
      docs/en/images/require-local-password-on-social-account-linking.png
  68. 1
      docs/en/index.md
  69. 22
      docs/en/modules/account-pro.md
  70. 22
      docs/en/modules/account/impersonation.md
  71. 6
      docs/en/modules/chat.md
  72. 26
      docs/en/modules/cms-kit/marked-items.md
  73. 12
      docs/en/modules/gdpr.md
  74. 2
      docs/en/modules/openiddict-pro.md
  75. 2
      docs/en/modules/openiddict.md
  76. 2
      docs/en/modules/tenant-management.md
  77. 24
      docs/en/release-info/migration-guides/abp-8-3.md
  78. 100
      docs/en/release-info/migration-guides/abp-9-0.md
  79. 1
      docs/en/release-info/migration-guides/index.md
  80. 13
      docs/en/release-info/release-notes.md
  81. 27
      docs/en/release-info/road-map.md
  82. 22
      docs/en/samples/index.md
  83. 36
      docs/en/solution-templates/layered-web-application/deployment/azure-deployment/azure-deployment.md
  84. 174
      docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md
  85. 231
      docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step2-configuration-application.md
  86. 735
      docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md
  87. 572
      docs/en/solution-templates/layered-web-application/deployment/azure-deployment/terraform-web-app-service.md
  88. 1933
      docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md
  89. 292
      docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md
  90. 111
      docs/en/solution-templates/layered-web-application/deployment/identityserver-deployment.md
  91. 20
      docs/en/solution-templates/layered-web-application/deployment/index.md
  92. 127
      docs/en/solution-templates/layered-web-application/deployment/openiddict-deployment.md
  93. 46
      docs/en/solution-templates/microservice/how-to-use-with-abp-suite.md
  94. BIN
      docs/en/solution-templates/microservice/images/abp-suite-products-pages.png
  95. BIN
      docs/en/studio/images/solution-explorer/abp-solution.png
  96. BIN
      docs/en/studio/images/solution-explorer/create-new-microservice-nolayers-additional-options.png
  97. BIN
      docs/en/studio/images/solution-explorer/create-new-microservice-nolayers-enable-integration.png
  98. BIN
      docs/en/studio/images/solution-explorer/create-new-module.png
  99. BIN
      docs/en/studio/images/solution-explorer/folder-context-menu.png
  100. BIN
      docs/en/studio/images/solution-explorer/imported-module.png

20
.github/workflows/auto-pr.yml

@ -1,13 +1,13 @@
name: Merge branch dev with prerel-9.0
name: Merge branch dev with rel-9.0
on:
push:
branches:
- prerel-9.0
- rel-9.0
permissions:
contents: read
jobs:
merge-dev-with-prerel-9-0:
merge-dev-with-rel-9-0:
permissions:
contents: write # for peter-evans/create-pull-request to create branch
pull-requests: write # for peter-evans/create-pull-request to create a PR
@ -18,19 +18,19 @@ jobs:
ref: dev
- name: Reset promotion branch
run: |
git fetch origin prerel-9.0:prerel-9.0
git reset --hard prerel-9.0
git fetch origin rel-9.0:rel-9.0
git reset --hard rel-9.0
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
branch: auto-merge/prerel-9-0/${{github.run_number}}
title: Merge branch dev with prerel-9.0
body: This PR generated automatically to merge dev with prerel-9.0. Please review the changed files before merging to prevent any errors that may occur.
branch: auto-merge/rel-9-0/${{github.run_number}}
title: Merge branch dev with rel-9.0
body: This PR generated automatically to merge dev with rel-9.0. Please review the changed files before merging to prevent any errors that may occur.
reviewers: maliming
token: ${{ github.token }}
- name: Merge Pull Request
env:
GH_TOKEN: ${{ secrets.BOT_SECRET }}
run: |
gh pr review auto-merge/prerel-9-0/${{github.run_number}} --approve
gh pr merge auto-merge/prerel-9-0/${{github.run_number}} --merge --auto --delete-branch
gh pr review auto-merge/rel-9-0/${{github.run_number}} --approve
gh pr merge auto-merge/rel-9-0/${{github.run_number}} --merge --auto --delete-branch

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

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

113
Directory.Packages.props

@ -6,7 +6,7 @@
<PackageVersion Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="3.0.0" />
<PackageVersion Include="aliyun-net-sdk-sts" Version="3.1.2" />
<PackageVersion Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageVersion Include="AsyncKeyedLock" Version="7.0.1" />
<PackageVersion Include="AsyncKeyedLock" Version="7.0.2" />
<PackageVersion Include="Autofac" Version="8.1.0" />
<PackageVersion Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
<PackageVersion Include="Autofac.Extras.DynamicProxy" Version="7.1.0" />
@ -51,60 +51,60 @@
<PackageVersion Include="Magick.NET-Q16-AnyCPU" Version="13.4.0" />
<PackageVersion Include="MailKit" Version="4.8.0" />
<PackageVersion Include="Markdig.Signed" Version="0.37.0" />
<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.Authentication.JwtBearer" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.Components" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Web" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.33" />
<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.AspNetCore.TestHost" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.AspNetCore.WebUtilities" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
<PackageVersion Include="Microsoft.CSharp" Version="4.7.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.Data.Sqlite" Version="9.0.0-rc.2.24474.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.0-rc.2.24474.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0-rc.2.24474.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.0-rc.2.24474.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Proxies" Version="9.0.0-rc.2.24474.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.0-rc.2.24474.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0-rc.2.24474.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0-rc.2.24474.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0-rc.2.24474.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.Extensions.Caching.Memory" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Configuration.CommandLine" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Composite" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.Extensions.Localization" Version="9.0.0-rc.2.24474.3" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0-rc.1.24457.2" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0-rc.2.24508.2" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.1.0" />
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="8.1.0" />
@ -114,7 +114,7 @@
<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="9.0.0-rc.1" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.0-rc.2" />
<PackageVersion Include="NSubstitute" Version="5.1.0" />
<PackageVersion Include="NuGet.Versioning" Version="6.11.1" />
<PackageVersion Include="NUglify" Version="1.21.9" />
@ -155,17 +155,18 @@
<PackageVersion Include="Spectre.Console" Version="0.49.1" />
<PackageVersion Include="StackExchange.Redis" Version="2.8.16" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.8.1" />
<PackageVersion Include="System.Collections.Immutable" Version="9.0.0-rc.1.24431.7" />
<PackageVersion Include="System.Collections.Immutable" Version="9.0.0-rc.2.24473.5" />
<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.4.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="9.0.0-rc.1.24431.7" />
<PackageVersion Include="System.Security.Permissions" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="System.Security.Principal.Windows" Version="5.0.0" />
<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.Text.Encoding.CodePages" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="System.Text.Encodings.Web" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="System.Text.Json" Version="9.0.0-rc.2.24473.5" />
<PackageVersion Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.1.0" />
<PackageVersion Include="TimeZoneConverter" Version="6.1.0" />
<PackageVersion Include="Unidecode.NET" Version="2.1.0" />

5
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json

@ -446,6 +446,7 @@
"PackageDetailPage_InstallingUsingPMCDescription1": "Open the <strong>Package Manager Console</strong> in Visual Studio (Tools -> Nuget Package Manager -> Package Manager Console) and execute the following command",
"UIOptions": "UI Options",
"Testimonials": "Testimonials",
"TestimonialsDescription": "Our clients' feedback is invaluable to us. Discover what they have to say about their experience working with us.",
"CoolestCompaniesUseABPFramework": "Coolest Companies Use <span class=\"fw-bold\">ABP Framework</span>",
"Index_Page_Testimonial_1": "ABP Framework is not just a tool but a catalyst that has accelerated my growth as a developer. It has made it possible for me to build new features faster than ever before, reminiscent of the experiences of other users. The unified coding pattern has streamlined my projects, giving me more time to focus on creating rather than troubleshooting.\nI would say the ABP Framework has been the cornerstone of my early professional journey. It has facilitated my transition from an aspiring developer to a confident professional ready to make a mark in the software world. I am looking forward to the exciting projects that await me, knowing that ABP will be there to guide me. It is more than just a product; it's a partner in success.",
"Index_Page_Testimonial_2": "ABP Framework is not only a framework, it is also a guidance for project development/management, because it provides DDD, GenericRepository, DI, Microservice, Modularity trainings. Even if you are not going to use framework itself, you can develop yourself with abp.io/docs which is well and professionally prepared. (OpenIddict, Redis, Quartz etc.)\nBecause many thing pre-built, it shortens project development time significantly. (Such as login page, exception handling, data filtering-seeding, audit logging, localization, auto api controller etc.)\nAs an example from our app, i have used Local Event Bus for stock control. So, I am able to manage order movements by writing stock handler.\nIt is wonderful not to lose time for CreationTime, CreatorId. They are filled automatically.",
@ -549,7 +550,7 @@
"CommercialLicenses": "Commercial Licenses",
"WhatIsDifferencePaidLicenses": "What is the difference between a personal license and other types of paid licenses?",
"DifferencePaidLicenseExplanation1": "A non-personal paid license is the standard licensing option for enterprises and commercial entities. Licenses are purchased by the company and can be used by anyone within the organization.",
"DifferencePaidLicenseExplanation2": "Personal License; on the other hand, is a type of license for private individuals/freelancers/independent developers who purchase licenses with their own funds and solely for their own use. The Personal License has some limitations. In this plan, there can only be 1 developer working on the ABP project and no additional developers are allowed to be added later to the project. Downloading the source-code of PRO modules is not allowed in the personal license plan. Also, there is no microservice template and tier (layered) architecture in this plan. Personal License holders can only use the following modules: <a href=\"/modules/Volo.Account.Pro\">Account</a>, <a href=\"/modules/Volo.AuditLogging.Ui\">Audit Logging UI</a>, <a href=\"/modules/Volo.Gdpr\">GDPR</a>, <a href=\"/modules/Volo.Identity.Pro\">Identity</a>, <a href=\"/modules/Volo.LanguageManagement\">Language Management</a>, <a href=\"/modules/Volo.Abp.LeptonXTheme.Pro\">LeptonX PRO</a>, <a href=\"/modules/Volo.OpenIddict.Pro\">OpenIddict UI</a> and <a href=\"/modules/Volo.Saas\">SaaS</a>. Personal License holders cannot use the following modules: <a href=\"/modules/Volo.Chat\">Chat</a>, <a href=\"/modules/Volo.CmsKit.Pro\">CMS-Kit PRO</a>, <a href=\"/modules/Volo.FileManagement\">File Management</a>, <a href=\"/modules/Volo.Forms\">Forms</a>, <a href=\"/modules/Volo.Payment\">Payment</a>, <a href=\"/modules/Volo.TextTemplateManagement\">Text Template Management</a>, and <a href=\"/modules/Volo.Abp.Sms.Twilio\">Twilio SMS</a>. You can access the full module list at <a href=\"/modules\">abp.io/modules</a>.",
"DifferencePaidLicenseExplanation2": "Personal License; on the other hand, is a type of license for private individuals/freelancers/independent developers who purchase licenses with their own funds and solely for their own use. The Personal License has some limitations. In this plan, there can only be 1 developer working on the ABP project and no additional developers are allowed to be added later to the project. Downloading the source-code of PRO modules is not allowed in the personal license plan. There is no microservice template in this plan. There is no tier architecture (Web and HTTP API layers are physically separated) in this plan. Personal License holders can only use the following modules: <a href=\"/modules/Volo.Account.Pro\">Account</a>, <a href=\"/modules/Volo.AuditLogging.Ui\">Audit Logging UI</a>, <a href=\"/modules/Volo.Gdpr\">GDPR</a>, <a href=\"/modules/Volo.Identity.Pro\">Identity</a>, <a href=\"/modules/Volo.LanguageManagement\">Language Management</a>, <a href=\"/modules/Volo.Abp.LeptonXTheme.Pro\">LeptonX PRO</a>, <a href=\"/modules/Volo.OpenIddict.Pro\">OpenIddict UI</a> and <a href=\"/modules/Volo.Saas\">SaaS</a>. Personal License holders cannot use the following modules: <a href=\"/modules/Volo.Chat\">Chat</a>, <a href=\"/modules/Volo.CmsKit.Pro\">CMS-Kit PRO</a>, <a href=\"/modules/Volo.FileManagement\">File Management</a>, <a href=\"/modules/Volo.Forms\">Forms</a>, <a href=\"/modules/Volo.Payment\">Payment</a>, <a href=\"/modules/Volo.TextTemplateManagement\">Text Template Management</a>, and <a href=\"/modules/Volo.Abp.Sms.Twilio\">Twilio SMS</a>. You can access the full module list at <a href=\"/modules\">abp.io/modules</a>.",
"ReadyToStart": "Ready to start?",
"TransformYourIdeasIntoRealityWithOurProfessionalNETDevelopmentServices": "Transform your ideas into reality with our professional .NET development services.",
"ReadyToUpgrade": "Ready to upgrade?",
@ -1868,4 +1869,4 @@
"GeneratePriceQuote": "Generate a Price Quote",
"Qa:QuestionPageTitle": "Support"
}
}
}

223
docs/en/Blog-Posts/2024-10-23 v9_0_Preview/POST.md

@ -0,0 +1,223 @@
# ABP Platform 9.0 Has Been Released Based on .NET 9.0
![](cover-image.png)
Today, we are happy to release the [ABP](https://abp.io/) version **9.0 RC** (Release Candidate). This blog post introduces the new features and important changes in this new version.
Try this version and provide feedback for a more stable version of ABP v9.0! Thanks to all of you.
## Get Started with the 9.0 RC
You can check the [Get Started page](https://abp.io/get-started) to see how to get started with ABP. You can either download [ABP Studio](https://abp.io/get-started#abp-studio-tab) (**recommended**, if you prefer a user-friendly GUI application - desktop application) or use the [ABP CLI](https://abp.io/docs/latest/cli).
By default, ABP Studio uses stable versions to create solutions. Therefore, if you want to create a solution with a preview version, first you need to create a solution and then switch your solution to the preview version from the ABP Studio UI:
![](studio-switch-to-preview.png)
## Migration Guide
There are a few breaking changes in this version that may affect your application. Please read the migration guide carefully, if you are upgrading from v8.x: [ABP Version 9.0 Migration Guide](https://abp.io/docs/9.0/release-info/migration-guides/abp-9-0)
## What's New with ABP v9.0?
In this section, I will introduce some major features released in this version.
Here is a brief list of titles explained in the next sections:
* Upgraded to .NET 9.0
* Introducing the **Extension Property Policy**
* Allow wildcards for Redirect Allowed URLs
* Docs Module: Show larger images on the same page
* Google Cloud Storage BLOB Provider
* Removed React Native mobile option from free templates
* Suite: Better naming for multiple navigation properties to the same entity
* CMS Kit Pro: Feedback feature improvements
### Upgraded to .NET 9.0
We've upgraded ABP to .NET 9.0, so you need to move your solutions to .NET 9.0 if you want to use ABP 9.0. You can check [Microsoft’s Migrate from ASP.NET Core 8.0 to 9.0 documentation](https://learn.microsoft.com/en-us/aspnet/core/migration/80-90), to see how to update an existing ASP.NET Core 8.0 project to ASP.NET Core 9.0.
> **Note:** Since the stable version of .NET 9 hasn't been released yet, we upgraded ABP to .NET v9.0-rc.2. We will update the entire ABP Platform to .NET 9 stable, after Microsoft releases it on November 13-14 with the stable ABP 9.0 release.
### Introducing the Extension Property Policy
ABP provides a module entity extension system, which is a high level extension system that allows you to define new properties for existing entities of the depended modules. This is a powerful way to dynamically add additional properties to entities without modifying the core structure. However, managing these properties across different modules and layers can become complex, especially when different policies or validation rules are required.
**Extension Property Policy** feature allows developers to define custom policies for these properties, such as access control, validation, and data transformation, directly within ABP.
**Example:**
```csharp
ObjectExtensionManager.Instance.Modules().ConfigureIdentity(identity =>
{
identity.ConfigureUser(user =>
{
user.AddOrUpdateProperty<string>( //property type: string
"SocialSecurityNumber", //property name
property =>
{
//validation rules
property.Attributes.Add(new RequiredAttribute());
property.Attributes.Add(new StringLengthAttribute(64) {MinimumLength = 4});
//Global Features
property.Policy.GlobalFeatures = new ExtensionPropertyGlobalFeaturePolicyConfiguration()
{
Features = new[] {"GlobalFeatureName1", "GlobalFeatureName2"},
RequiresAll = true
};
//Features
property.Policy.Features = new ExtensionPropertyFeaturePolicyConfiguration()
{
Features = new[] {"FeatureName1", "FeatureName2"},
RequiresAll = false
};
//Permissions
property.Policy.Permissions = new ExtensionPropertyPermissionPolicyConfiguration()
{
PermissionNames = new[] {"AbpTenantManagement.Tenants.Update", "AbpTenantManagement.Tenants.Delete"},
RequiresAll = true
};
}
);
});
});
```
### Allow Wildcards for RedirectAllowedURLs
In this version, we made an improvement to the `RedirectAllowedUrls` configuration, which now allows greater flexibility in defining redirect URLs. Previously, developers faced restrictions when configuring URL redirects. Specifically, the `RedirectAllowedUrls` did not support using **wildcards (*)**, limiting how developers could specify which URLs were permissible for redirects.
With the new changes in [#20628](https://github.com/abpframework/abp/pull/20628), the restriction has been relaxed, allowing developers to define redirect URLs that include wildcards. This makes it easier to handle scenarios where a broad range of URLs need to be allowed, without explicitly listing each one.
```json
{
"App": {
//...
"RedirectAllowedUrls": "http://*.domain,http://*.domain:4567"
}
```
### Docs Module: Show Larger Images
As developers, we rely heavily on clear documentation to understand complex concepts and workflows. Often, an image is worth more than a thousand words, especially when explaining intricate user interfaces, workflows, or code structures. In recognition of this, we recently rolled out an improvement to the Docs Module that enables larger images to be displayed more effectively.
![](docs-image-larger.png)
Before this enhancement, images embedded in documentation were often limited in size, which sometimes made it difficult to see the details in the diagrams, screenshots, or other visual contents. Now, images can be displayed at a larger size, offering better clarity and usability.
> See [https://github.com/abpframework/abp/pull/20557](https://github.com/abpframework/abp/pull/20557) for more information.
### Google Cloud Storage BLOB Provider
ABP provides a BLOB Storing System, which allows you to work with BLOBs. This system is typically used to store file contents in a project and read these file contents when they are needed. Since ABP provides an abstraction to work with BLOBs, it also provides some pre-built storage providers such as [Azure](https://abp.io/docs/latest/framework/infrastructure/blob-storing/azure), [Aws](https://abp.io/docs/latest/framework/infrastructure/blob-storing/aws) and [Aliyun](https://abp.io/docs/latest/framework/infrastructure/blob-storing/aliyun).
In this version, we have introduced a new BLOB Storage Provider for Google Cloud Storage: [`Volo.Abp.BlobStoring.Google`](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Google)
You can [read the documentation](https://abp.io/docs/9.0/framework/infrastructure/blob-storing/google) for configurations and use Google Cloud Storage as your BLOB Storage Provider easily.
### Removed React Native Mobile Option From Free Templates
In this version, we removed the **React Native** mobile option from the open source templates due to maintaining reasons. We updated the related documents and the ABP CLI (both old & new CLI) for this change, and with v9.0, you will not be able to create a free template with react-native as the mobile option.
> **Note:** Pro templates still provide the **React Native** as the mobile option and we will continue supporting it.
If you want to access the open-source React-Native template, you can visit the abp-archive repository from [here](https://github.com/abpframework/abp-archive).
### Suite: Better Naming For Multiple Navigation Properties
Prior to this version, when you defined multiple (same) navigation properties to same entity, then ABP Suite was renaming them with a duplicate number.
As an example,let's assume that you have a book with an author and coauthor, prior to this version ABP Suite was creating a DTO class as below:
```csharp
public class BookWithNavigationPropertiesDto
{
public BookDto Book { get; set; }
public AuthorDto Author { get; set; }
public AuthorDto Author1 { get; set; }
}
```
Notice, that since the book entity has two same navigation properties, ABP Suite renamed them with a duplicate number. In this version, ABP Suite will ask you to define a propertyName for the **navigation properties** and you'll be able to specify a meaningful name such as (*CoAuthor*, in this example):
```csharp
public class BookWithNavigationPropertiesDto
{
public BookDto Book { get; set; }
public AuthorDto Author { get; set; }
//used the specified property name
public AuthorDto CoAuthor { get; set; }
}
```
ABP Suite respects the specified property name for the related navigation property and generates codes regarding that (by removing the *Id* postfix for the related places):
![](suite-navigation-properties.png)
### CMS Kit Pro: Feedback Feature Improvements
In this version, we revised the [CMS Kit's Feedback Feature](https://abp.io/docs/9.0/modules/cms-kit-pro/page-feedback) and as a result, we made the following improvements:
* A new **auto-handle** setting has been added to the settings page. When this feature is enabled, if feedback is submitted without a user note, the feedback is automatically marked as handled.
* You can now require users to enter a note when submitting negative feedback. This can be configured in the settings page, ensuring that users provide context when they submit critical feedback.
* We've added a feedback user ID that is saved in local storage. This allows you to track the number of unique users submitting feedback or determine if the same user is sending new feedback on updated documents.
> For further information about the Page Feedback System, please refer to the [documentation](https://abp.io/docs/9.0/modules/cms-kit-pro/page-feedback).
## Community News
### Join ABP at the .NET Conf 2024!
ABP is excited to sponsor the [14th annual .NET Conf](https://www.dotnetconf.net/)! We've proudly supported the .NET community for years and recognize the importance of this premier virtual event. Mark your calendars for November 12-14, 2024, and join us for 3 incredible days of learning, networking, and fun.
![](dotnet-conf-2024.png)
Also, don't miss out on the co-founder of [Volosoft](https://volosoft.com/) and Lead Developer of [ABP](https://abp.io/), [Halil Ibrahim Kalkan](https://x.com/hibrahimkalkan)'s talk about "Building Modular Monolith Applications with ASP.NET Core and ABP Studio" at 10:00 - 10:30 AM GMT+3 on Thursday, November 14.
### ABP Team Attended the .NETDeveloperDays 2024
We are thrilled to announce that we sponsored the [.NETDevelopersDays 2024](https://developerdays.eu/warsaw/) event. It's one of the premier conferences for .NET developers with **over 1.000 attendees**, **50+ expert speakers**, and **40+ sessions and workshops**.
![](dotnet-developer-days-2024.jpg)
Core team members of the ABP Framework, [Halil Ibrahim Kalkan](https://twitter.com/hibrahimkalkan), [İsmail Çağdaş](https://x.com/ismcagdas), [Enis Necipoğlu](https://x.com/EnisNecipoglu), and [Tarık Özdemir](https://x.com/mtozdemir) attended [.NETDevelopersDays 2024](https://developerdays.eu/warsaw/) on October 22-23, 2024 at Warsaw, Poland.
These 2 days with the team were all about chatting and having fun with amazing attendees and speakers. We met with talented and passionate software developers and introduced the [ABP](https://github.com/abpframework/abp) - web application framework built on ASP.NET Core - to them.
Also, we made a raffle and gifted an Xbox Series S to the lucky winner at the event:
![](abp-team-raffle.jpg)
Thanks to everyone who joined the fun and visited at our booth :)
### New ABP Community Articles
There are exciting articles contributed by the ABP community as always. I will highlight some of them here:
* [Alper Ebiçoğlu](https://twitter.com/alperebicoglu) has created **five** new community articles:
* [When to Use Cookies, When to Use Local Storage?](https://abp.io/community/articles/when-to-use-cookies-when-to-use-local-storage-uexsjunf)
* [.NET 9 Performance Improvements Summary](https://abp.io/community/articles/.net-9-performance-improvements-summary-gmww3gl8)
* [ASP.NET Core SignalR New Features — Summary](https://abp.io/community/articles/asp.net-core-signalr-new-features-summary-kcydtdgq)
* [Difference Between "Promise" and "Observable" in Angular](https://abp.io/community/articles/difference-between-promise-and-observable-in-angular-bxv97pkc)
* [ASP.NET Core Blazor 9.0 New Features Summary 🆕](https://abp.io/community/articles/asp.net-core-blazor-9.0-new-features-summary--x0fovych)
* [Mohammad AlMohammad AlMahmoud](https://abp.io/community/members/Mohammad97Dev) has created **two** new community articles:
* [Implementing Multi-Language Functionality With ABP Framework](https://abp.io/community/articles/implementing-multilanguage-functionality-with-abp-framework-loq7kfx4)
* [Configure Quartz.Net in Abp FrameWork](https://abp.io/community/articles/configure-quartz.net-in-abp-framework-3bveq4y1)
* [.NET Aspire vs ABP Studio: Side by Side](https://abp.io/community/articles/.net-aspire-vs-abp-studio-side-by-side-t1c73d1l) by [Halil İbrahim Kalkan](https://twitter.com/hibrahimkalkan)
* [PoC of using GrapesJS for ABPs CMS Kit](https://abp.io/community/articles/poc-of-using-grapesjs-for-abps-cms-kit-1rmv4q41) by [Jack Fistelmann](https://abp.io/community/members/jfistelmann)
* [ABP-Powered Web App with Inertia.js, React, and Vite](https://abp.io/community/articles/abppowered-web-app-with-inertia.js-react-and-vite-j7cccvad) by [Anto Subash](https://antosubash.com/)
* [Multi-Tenancy Support in Angular Apps with ABP.IO](https://abp.io/community/articles/multitenancy-support-in-angular-apps-with-abp.io-lw9l36c5) by [HeadChannel Team](https://headchannel.co.uk/)
Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://abp.io/community/posts/submit) to the ABP Community.
## Conclusion
This version comes with some new features and a lot of enhancements to the existing features. You can see the [Road Map](https://abp.io/docs/9.0/release-info/road-map) documentation to learn about the release schedule and planned features for the next releases. Please try ABP v9.0 RC and provide feedback to help us release a more stable version.
Thanks for being a part of this community!

BIN
docs/en/Blog-Posts/2024-10-23 v9_0_Preview/abp-team-raffle.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

BIN
docs/en/Blog-Posts/2024-10-23 v9_0_Preview/cover-image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 KiB

BIN
docs/en/Blog-Posts/2024-10-23 v9_0_Preview/docs-image-larger.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

BIN
docs/en/Blog-Posts/2024-10-23 v9_0_Preview/dotnet-conf-2024.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 KiB

BIN
docs/en/Blog-Posts/2024-10-23 v9_0_Preview/dotnet-developer-days-2024.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

BIN
docs/en/Blog-Posts/2024-10-23 v9_0_Preview/studio-switch-to-preview.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
docs/en/Blog-Posts/2024-10-23 v9_0_Preview/suite-navigation-properties.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

4
docs/en/Community-Articles/2022-11-14-How-to-add-a-custom-grant-type-in-OpenIddict/POST.md

@ -73,10 +73,10 @@ public class MyTokenExtensionGrant : ITokenExtensionGrant
claimsPrincipal.SetResources(await GetResourcesAsync(context, principal.GetScopes()));
//abp version < 7.3
await context.HttpContext.RequestServices.GetRequiredService<AbpOpenIddictClaimDestinationsManager>().SetAsync(principal);
await context.HttpContext.RequestServices.GetRequiredService<AbpOpenIddictClaimDestinationsManager>().SetAsync(claimsPrincipal);
//For abp version >= 7.3
await context.HttpContext.RequestServices.GetRequiredService<AbpOpenIddictClaimsPrincipalManager>().HandleAsync(context.Request, principal);
await context.HttpContext.RequestServices.GetRequiredService<AbpOpenIddictClaimsPrincipalManager>().HandleAsync(context.Request, claimsPrincipal);
return new SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, claimsPrincipal);
}

4
docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/How to use Aspire with ABP framework.md

@ -300,3 +300,7 @@ After making all our changes, we can run the `AspirationalAbp.AppHost` project.
## Conclusion
Combining .NET Aspire with the ABP framework creates a powerful setup for building robust, observable, and feature-rich applications. By integrating Aspire's observability and cloud capabilities with ABP's approach of focusing on your business without repeating yourself, you can develop feature-rich, scalable applications with enhanced monitoring and seamless cloud integration. This guide provides a clear path to set up and configure these technologies, ensuring your applications are well-structured, maintainable, and ready for modern cloud environments.
## See Also
* [.NET Aspire vs ABP Studio: Side by Side](https://abp.io/community/articles/.net-aspire-vs-abp-studio-side-by-side-t1c73d1l)

63
docs/en/Community-Articles/2024-10-09-Cookies-vs-Local-Storage/Post.md

@ -0,0 +1,63 @@
# When to Use Cookies, When to Use Local Storage?
![cover](cover.png)
## Cookies vs Local Storage
When you want to save client-side data on browsers, you can use `Cookies` or `Local Storage` of the browser. While these methods look similar, they have different behaviors. You need to decide based on the specific use-case, security concerns and the data size being stored. I'll clarify the differences between these methods.
## When to use Cookies 🍪?
1. **Server Communication (e.g: Authentication Tokens):** Cookies are ideal when you need to send data automatically with HTTP requests to the server, such as authentication tokens (JWTs) or session IDs. Cookies can be configured to be sent only to specific domains or paths, making them useful for session management.
2. **Cross-Domain Communication:** Cookies can be shared across subdomains, which is useful when working with multiple subdomains under the same parent domain for microservice architecture.
3. **Expiration Control:** Cookies come with built-in expiration times. You don’t need to manually remove them after a certain period that should expire.
4. **Security:** Cookies can be marked as `HttpOnly` which makes them accessible **only via the server**, not via JavaScript! Also, when you set a cookie attribute, `Secure` it can be sent only over HTTPS, which forces enhanced security for sensitive data.
### Considerations for Cookies
- **Size Limitation:** Cookies are generally limited to around 4KB of data.
- **Security Risks:** Cookies are susceptible to cross-site scripting (XSS) attacks unless marked `HttpOnly`.
---
## When to use Local Storage🗄️?
1. **Client-Side Data Storage:** Local storage is ideal for storing large amounts of data (up to 5–10 MB) that doesn’t need to be sent to the server with every request. For example; *user preferences*, *settings*, or *cached data*.
2. **Persistence:** Data in local storage persists even after the browser is restarted. This behavior makes it useful for long-term storage needs.
3. **No Automatic Server Transmission:** Local storage data is never automatically sent to the server, which can be a security advantage if you don’t want certain data to be exposed to the server or included in the requests.
### Considerations for Local Storage
- **Security Risks:** Local storage is accessible via JavaScript, making it vulnerable to XSS attacks. Sensitive data should not be stored in local storage unless adequately encrypted.
- **No Expiration Mechanism:** Local storage does not have a built-in expiration mechanism. You must manually remove the data when it’s no longer needed.
---
## Summary
### Use Cookies
- For data that needs to be sent to the server with HTTP requests, particularly for session management or authentication purposes.
### Use Local Storage
- For storing large amounts of client-side data that doesn’t need to be automatically sent to the server and for data that should persist across browser sessions.
In many cases, you might use both cookies and local storage, depending on the specific requirements of different parts of your application. There are also other places where you can store the client-side data. You can check out [this article](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage) for more information.
Happy coding 🧑🏽‍💻

BIN
docs/en/Community-Articles/2024-10-09-Cookies-vs-Local-Storage/cover.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 KiB

2
docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/Post.md

@ -6,6 +6,8 @@ With every release, .NET becomes faster & faster! You get these improvements for
It’s very interesting that **20% of these improvements** are implemented by **open-source volunteers** rather than Microsoft employees. These improvements mostly focus on cloud-native and high-throughput applications. I’ll briefly list them below.
![From Microsoft Blog Post](cited-from-microsoft-blog-post.png)
## 1. Dynamic PGO with JIT Compiler

BIN
docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/cited-from-microsoft-blog-post.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/cover.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 441 KiB

After

Width:  |  Height:  |  Size: 432 KiB

138
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/POST.md

@ -0,0 +1,138 @@
# .NET Aspire vs ABP Studio: Side by Side
In this article, I will compare [.NET Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/) by [ABP Studio](https://abp.io/docs/latest/studio) by explaining their similarities and differences.
![cover](cover.png)
## Introduction
While .NET Aspire and ABP Studio are tools for different purpose with different scope and they have different approaches to solve the problems, many developers still may confuse since they also have some similar functionalities and solves some common problems.
In this article, I will clarify all, and you will have a clear understanding of what are the similarities and differences of them. Let's start by briefly define what are .NET Aspire and ABP Studio.
### What is .NET Aspire?
**[.NET Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/)** is a **cloud-ready framework** designed to simplify building distributed, observable, and production-ready applications. It provides a set of opinionated tools and NuGet packages tailored for cloud-native concerns like **orchestration**, **service integration** (e.g., Redis, PostgreSQL), and **telemetry**. Aspire focuses on the **local development experience**, making it easier to manage complex, multi-service apps by **abstracting away configuration details**.
Here, a screenshot from [.NET Aspire dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview) that is used for application monitoring and inspection:
![dotnet-aspire-dashboard](dotnet-aspire-dashboard.png)
### What is ABP Studio?
**[ABP Studio](https://abp.io/docs/latest/studio)** is a cross-platform **desktop application** designed to **simplify development** on the ABP Framework by **automating various tasks** and offering a streamlined, **integrated development environment**. It allows developers to **build**, **run**, **test**, **monitor**, and **deploy applications** more efficiently. With features like Kubernetes integration and support for complex multi-application systems, ABP Studio **enhances productivity**, especially in **microservice or modular monolith architectures**.
Here, a screenshot from the ABP Studio [Solution Runner panel](https://abp.io/docs/latest/studio/running-applications) that is used to run, browse, monitor and inspect applications:
![abp-studio-solution-runner](abp-studio-solution-runner.png)
## A Brief Comparison
Before deep diving details, I want to show a **table of features** to compare ABP Studio and .NET Aspire side by side:
![abp-studio-vs-net-aspire-comparison-table](abp-studio-vs-dotnet-aspire-comparison-table.png)
## Comparing the Features
In the next sections, I will go through each feature and explain differences and similarities.
### Integration Packages
ABP Framework has tens of integration packages to 3rd-party libraries and services. .NET Aspire also has some library integrations. But these integrations have different purposes:
* **ABP Framework**'s integrations (like [MongoDB](https://abp.io/docs/latest/framework/data/mongodb), [RabbitMQ](https://abp.io/docs/latest/framework/infrastructure/background-jobs/rabbitmq), [Dapr](https://abp.io/docs/latest/framework/dapr), etc) are integrations for its abstractions and aimed to be **used directly by your application code**. They are complete and sophisticated integrations with the ABP Framework and your codebase.
* **.NET Aspire**'s integrations (like [MongoDB](https://learn.microsoft.com/en-us/dotnet/aspire/database/mongodb-integration), [RabbitMQ](https://learn.microsoft.com/en-us/dotnet/aspire/messaging/rabbitmq-integration), [Dapr](https://learn.microsoft.com/en-us/dotnet/aspire/frameworks/dapr), etc), on the other hand, for simplifying configuration, service discovery, orchestration and monitoring of these tools within .NET Aspire host. Basically, these are mostly for **integrating to .NET Aspire**, not for integrating to your application.
For example, ABP's [MongoDB](https://abp.io/docs/latest/framework/data/mongodb) integration allows you to use MongoDB over [repository services](https://abp.io/docs/latest/framework/architecture/domain-driven-design/repositories), automatically handles database transactions, [audit logs](https://abp.io/docs/latest/framework/infrastructure/audit-logging), [event publishing](https://abp.io/docs/latest/framework/infrastructure/event-bus/distributed) on data saves, dynamic [connection string](https://abp.io/docs/latest/framework/fundamentals/connection-strings) management, [multi-tenancy](https://abp.io/docs/latest/framework/architecture/multi-tenancy) integration and so on.
On the other hand, .NET Aspire's [MongoDB](https://learn.microsoft.com/en-us/dotnet/aspire/database/mongodb-integration) integration basically adds [MongoDB driver library](https://www.nuget.org/packages/MongoDB.Driver/) to your .NET Aspire host application and configures it so you can discover MongoDB server on runtime, use a MongoDB Docker container and see its health status, logs and traces on .NET Aspire dashboard.
### Starter Templates
Both of ABP Studio and .NET Aspire provide **startup solution templates for new applications**. However, there are huge differences between these startup solution templates and their purpose are completely different.
* ABP Studio provides **production-ready** and [advanced solution templates](https://abp.io/docs/latest/solution-templates) for **layered**, **modular** or **microservice** solution development. They are well configured for **local development** and deploying to **Kubernetes** and other **production environments**. They provide different **UI and database options**, many optional modules and configuration. For example, you can check the [microservice solution template](https://abp.io/docs/latest/solution-templates/microservice/overview) to see how **sophisticated** it is.
* .NET Aspire's [project templates](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/setup-tooling?tabs=windows&pivots=visual-studio#net-aspire-project-templates)' main purpose is to provide a minimal application structure that is **pre-integrated to .NET Aspire** libraries and configured for **local development** environment.
So, when you start with .NET Aspire project template, you will need to deal with a lot of work to make your solution production and enterprise ready. On the other hand, ABP Studio's solution templates are ready to launch your system from the first day and they provide you a perfect starting point for your new business idea.
### Monitoring & Application Running
Monitoring applications and services is an important requirement for building **complex distributed systems**. Both of ABP Studio and .NET Aspire provide **excellent tools** for that purpose.
* ABP Studio's [Solution Runner panel](https://abp.io/docs/latest/studio/running-applications) provides a powerful UI to run and monitor applications and services. You can see all HTTP requests, distributed events, exceptions and detailed application logs, trace and find problems in your system. You can use its fully functional built-in browser to navigate application UIs easily. You can also create multiple profiles to group and configure the applications for different teams.
* .NET Aspire's [dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview) can be used to see the states of the running applications and containers, explore their console output, logs, traces and metrics to understand what is happing in your distributed system.
Both tools are pretty useful for monitoring. In addition to monitoring, **ABP Studio offers an advanced UI to control the running applications**, build, start and stop individually or by a group of applications.
### Architecting / Building Solutions
One of the unique features of **ABP Studio** is that it **is an architectural tool** that helps you create the structure and architecture of your solution. You can create any kind of application, from **single-layer** simple web applications to **layered multi-application** solutions, from **monolith modular** to **microservice** systems. In the next section, I will briefly explains these architectural features.
#### Building Modular Monolith Solutions
With ABP Studio, you can create a new solution, **create modules and establish relations** (dependencies) between modules to architect your overall **modular monolith system** easily.
Here, a screenshot where we are adding an existing package reference to the Products module of a modular CRM solution:
![abp-studio-add-existing-package](abp-studio-add-existing-package.png)
You can see the [Modular Application Development tutorial](https://abp.io/docs/latest/tutorials/modular-crm) to learn how to build such an application step by step.
#### Building Microservice Solutions
ABP Studio provides a full featured [microservice startup solution template](https://abp.io/docs/latest/solution-templates/microservice) and the fundamental tooling to build **large-scale microservice systems**.
Here a screenshot that shows how to add new microservices, API gateways or web applications to a microservice solution:
![abp-studio-add-new-microservice](abp-studio-add-new-microservice.png)
.NET Aspire has no such a feature and has no such a plan to provide that kind of architectural solution building experience.
### Kubernetes Integration
Another great ABP Studio feature is [Kubernetes Integration](https://abp.io/docs/latest/studio/kubernetes). It allows you to develop your distributed / microservice solutions as integrated to [Kubernetes](https://kubernetes.io/).
Here, a few tasks you can accomplish using ABP Studio's Kubernetes integration:
* **Build docker images** of your applications and services
* **Install and uninstall Helm charts** to your Kubernetes cluster
* **Connect to internal services** of your Kubernetes cluster
* **Monitor** services and applications that are running in your Kubernetes cluster
* **Intercept traffic** of a service and redirect requests to your local machine. In that way, you can develop, test and run individual services or applications in your local computer that is **fully integrated** to other services and applications running in Kubernetes.
ABP Studio's Kubernetes Integration makes microservice development so easy and comfortable. On the other hand, .NET Aspire has no such a Kubernetes integrated development experience.
## The ABP Platform
Until now, I directly compared ABP Studio and .NET Aspire features. .NET Aspire is directly built on .NET and ASP.NET Core. However, ABP Studio is not a standalone tool that is built on .NET and ASP.NET Core. It is built on the [ABP Platform](https://abp.io/) (which is built on .NET and ASP.NET Core).
The following diagram shows ABP Platform components at a glance:
![abp-overall-diagram](abp-overall-diagram.png)
So, when you use ABP Studio, you also take full power of the [open source ABP Framework](https://github.com/abpframework/abp) and other ABP Platform features.
## ABP and .NET Aspire Integration
I have a good news to you. It is actually possible and pretty easy to make ABP Platform and .NET Aspire working together.
You can check [@berkansasmaz](https://abp.io/community/members/berkansasmaz)'s great article: **[How to use .NET Aspire with ABP framework](https://abp.io/community/articles/how-to-use-.net-aspire-with-abp-framework-h29km4kk)**.
## Licensing
ABP Studio has a Community Edition which is completely free and available to everyone. It includes many of the features I mentioned here. There is also a commercial edition that is included in [commercial ABP licenses](https://abp.io/pricing). You can [check that blog post](https://abp.io/blog/announcing-abp-studio-general-availability) which clearly explains the license differences and introduces the fundamental ABP Studio features.
On the other hand, .NET Aspire is a free tool developed and published by Microsoft. It has no commercial version.
## Conclusion
Both .NET Aspire and ABP Studio serve distinct purposes, catering to different types of development environments. While .NET Aspire excels in simplifying cloud-native application setups and observability, ABP Studio provides a comprehensive framework for modular monoliths and microservice architectures with full-fledged enterprise level production-ready startup solution templates and integrated tools.
In the previous section, it was mentioned that it is possible to [use them together](https://abp.io/community/articles/how-to-use-.net-aspire-with-abp-framework-h29km4kk). You don't have to select one of them. However, in my opinion, when you use ABP Studio, you won't need .NET Aspire since ABP Studio can do everything and much more. If you have budget, I suggest to purchase a commercial ABP Studio [license](https://abp.io/pricing) so you can fully unlock its power.
## Resources / Further Reading
* [ABP Studio documentation](https://abp.io/docs/latest/studio)
* [.NET Aspire documentation](https://learn.microsoft.com/en-us/dotnet/aspire/)
* [How to use .NET Aspire with ABP framework](https://abp.io/community/articles/how-to-use-.net-aspire-with-abp-framework-h29km4kk)

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-overall-diagram.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-add-existing-package.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-add-new-microservice.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-solution-runner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-vs-dotnet-aspire-comparison-table.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/cover.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

BIN
docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/dotnet-aspire-dashboard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
docs/en/Community-Articles/2024-10-23-Abp-Net9-Upgrade/cover.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
docs/en/Community-Articles/2024-10-23-Abp-Net9-Upgrade/dog-food.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
docs/en/Community-Articles/2024-10-23-Abp-Net9-Upgrade/ef-core-upgrade.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
docs/en/Community-Articles/2024-10-23-Abp-Net9-Upgrade/net-support-policy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

147
docs/en/Community-Articles/2024-10-23-Abp-Net9-Upgrade/post.md

@ -0,0 +1,147 @@
# ABP Now Supports .NET 9
![Cover image](cover.png)
**.NET 9.0.100-rc.2** has been released on **October 8, 2024**. To align with the latest .NET, we also released the ABP Platform [9.0.0-rc.1](https://github.com/abpframework/abp/releases/tag/9.0.0-rc.1) version.
**With this release, ABP now supports .NET 9.**
The .NET 9 stable version is planned to be released on **November 12, 2024** before the [.NET Conf 2024](https://www.dotnetconf.net/) event. The ABP 9.0 stable version is planned to be released on November 19, 2024.
---
- **Download the .NET 9 runtime** and SDK from the following link:
[https://dotnet.microsoft.com/en-us/download/dotnet/9.0](https://dotnet.microsoft.com/en-us/download/dotnet/9.0)
- There are many enhancements and bug fixes with ABP 9.0. Read the ABP 9 announcement:
https://abp.io/blog/announcing-abp-9-0-release-candidate
-
Read **our migration ABP 9.0 migration guide** from the following link:
[abp.io/docs/9.0/release-info/migration-guides/abp-9-0](https://abp.io/docs/9.0/release-info/migration-guides/abp-9-0)
- The following is the **PR is for the .NET 9 upgrade** in the ABP source code:
[https://github.com/abpframework/abp/pull/20803](https://github.com/abpframework/abp/pull/20803)
---
## .NET 9 Releases
In the following link, you can find **a list of all .NET 9 releases** with direct links to release notes and announcements/discussions:
* https://github.com/dotnet/core/discussions/9234
---
## ABP Supports Both .NET 8 & .NET 9
The ABP 9.0 version fully supports .NET 9 within our new templates and modules. For developers who want to update their ABP packages to the latest but want to keep them in .NET 8, **we support both .NET 8 and .NET 9** in ABP 9. In your host application, you can choose your target framework.
So you can decide which version you want to use in your startup Host Application’s `<TargetFramework>` tag.
In [this link](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp/Volo.Abp.csproj#L7) you can see that netstandard2.0/2.1 and net8/9 are supported.
```xml
<Project Sdk="Microsoft.NET.Sdk">
<TargetFrameworks>
netstandard2.0;netstandard2.1;net8.0;net9.0
</TargetFrameworks>
</Project>
```
### New ASP.NET Core Middleware: Static Asset Delivery
`MapStaticAssets` is a new middleware that helps optimize the delivery of static assets in any ASP.NET Core app, including Blazor apps. With this change, some `JavaScript/CSS/Images` files exist in the [Virtual File System](https://abp.io/docs/latest/framework/infrastructure/virtual-file-system?_redirected=B8ABF606AA1BDF5C629883DF1061649A), but the new ASP.NET Core 9 `MapStaticAssets` can't handle them. You need to add `StaticFileMiddleware` to serve these files. In ABP 9, we added `MapAbpStaticAssetsan `extension method to support the new `MapStaticAssets`. You can read about this new feature at [this link](https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-9.0?view=aspnetcore-8.0#static-asset-delivery-optimization).
ABP’s new extension method is available [here](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs#L129-L198).
---
## How to Upgrade from .NET 8 to .NET 9:
Install the latest .NET 9 SDK from [this link](https://dotnet.microsoft.com/en-us/download/dotnet/9.0).
Upgrade [dotnet-ef](https://learn.microsoft.com/en-us/ef/core/cli/dotnet) tool version with the following command:
```bash
dotnet tool uninstall --global dotnet-ef && dotnet tool install --global dotnet-ef
```
![EF Core Upgrade](ef-core-upgrade.png)
1. Change all `TargetFramework` tags from `net8.0` to `net9.0`.
2. Upgrade all Microsoft NuGet packages to `9.0.0`.
3. If you have `global.json`, update `dotnet`version to `9.0.0` .
4. Replace`app.UseStaticFiles()` to `app.MapAbpStaticAssets()` in your module classes and startup projects.
[See the related changes in the repository.](https://github.com/abpframework/abp/commit/0f34f6dfcdbeb5d27fd63cf764f1ef13eb9cdfcd)
---
## What’s new with .NET 9
**.NET 9 Blazor New Features**
- https://abp.io/community/articles/asp.net-core-blazor-9.0-new-features-summary--x0fovych
**.NET 9 Performance Improvements Summary**
- https://abp.io/community/articles/.net-9-performance-improvements-summary-gmww3gl8
**What’s new in .NET 9 (Microsoft’s post)**
- https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-9/overview
---
## We Are Eating Our Own Dog Food
Before we release any version of ABP, **we test our upcoming version** on our sample apps and live website https://abp.io. The ABP.io website is also built on top of the ABP Framework, and you can see that we have already started to use .NET 9-rc.2 on our live website.
![Eating our own dog food](dog-food.png)
---
## Microsoft .NET Support Policy
Lastly, I want to mention Microsoft's .NET support policy.
- **.NET 7** support has been **finished** on **May 2024**.
- **.NET 8** will be supported until **November 2026**.
- **.NET 9** is on the standard term support, which means Microsoft will release patches until **May 2026**.
Find detailed information about the .NET support policy at [this link.](https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core)
![.NET Core Official Support Policy](net-support-policy.png)
---
## Finally
.NET 9 is making a significant impact. It introduces features like Native AOT for faster applications, enhanced AI integration and improved tools for cloud-native and cross-platform development, all aimed at simplifying developers’ work. Whether you’re handling small projects or large-scale enterprise applications, it offers enhancements that **elevate your productivity by just upgrading your .NET version to 9.0**

125
docs/en/Community-Articles/2024-11-01-Hybrid-Cache-Net-9/POST.md

@ -0,0 +1,125 @@
# Hybrid Cache in .NET 9
.NET 9 introduces an exciting feature: **HybridCache**, an advanced caching mechanism that seamlessly combines multiple caching strategies to maximize performance and scalability.
It offers a flexible caching solution that combines the best aspects of local and distributed caching. **HybridCache** is particularly useful in scenarios where quick, in-memory access is desirable but data consistency across multiple application instances is also a requirement.
In this article, we’ll explore **HybridCache** in .NET 9 and how it integrates with ABP Framework using `AbpHybridCache`. This new feature offers a robust solution for applications that need to scale while maintaining efficient caching strategies.
## What is HybridCache?
**HybridCache** is designed to merge different caching layers, commonly including an in-memory cache (for high-speed access) and a distributed cache (for scalability across multiple instances). This hybrid approach allows for:
* **Improved Performance**: Frequently accessed data is stored in-memory, reducing latency.
* **Increased Scalability**: Cached data can still be shared across distributed environments, essential for load-balanced applications.
* **Automatic Synchronization**: Changes in distributed cache automatically update the in-memory cache, ensuring data consistency.
## Using HybridCache with ABP
> For more information about the implementation in the ABP side, you can refer to the pull request [here](https://github.com/abpframework/abp/pull/20859).
ABP's support for **HybridCache** is available starting from version 9.0 through the [`AbpHybridCache`](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/Hybrid/AbpHybridCache.cs) implementation. By leveraging this feature, developers using ABP can implement hybrid caching in a way that aligns with ABP’s modular and extensible architecture.
To demonstrate how to use **HybridCache** in ABP, let's start with a simple example.
> You can create an ABP-based application with v9.0+, and then follow the next steps for using hybrid caching in your application.
### Configuring the `AbpHybridCacheOptions` (Optional)
First, you can configure the hybrid cache options in your module class as below (it's optional):
```csharp
using Microsoft.Extensions.Caching.Hybrid;
using Volo.Abp.Caching.Hybrid;
public class YourModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//...
Configure<AbpHybridCacheOptions>(options =>
{
//configuring the global hybrid cache options
options.GlobalHybridCacheEntryOptions = new HybridCacheEntryOptions()
{
Expiration = TimeSpan.FromMinutes(20),
LocalCacheExpiration = TimeSpan.FromMinutes(10)
};
});
}
}
```
* You can configure the `AbpHybridCacheOptions` to set *keyPrefix* for your cache keys, throw or hide exceptions for the distributed cache (by default *it hides errors*), or configure cache for specific cache item keys and more...
* By setting the `GlobalHybridCacheEntryOptions`, you specify the caching options globally in your application. Thanks to that, you don't need to manually pass the related options whenever you use the `IHybridCache` service.
### Using the `IHybridCache` Service
After the configuration, now you can inject the `IHybridCache` and use it to set and retrieve cache values:
```csharp
using Volo.Abp.Caching.Hybrid;
public class BookAppService : ApplicationService, IBookAppService
{
private readonly IHybridCache<BookCacheItem> _hybridCache;
public BookAppService(IHybridCache<BookCacheItem> hybridCache)
{
_hybridCache = hybridCache;
}
public async Task<BookCacheItem> GetBookWithPageCountAsync(string name)
{
var cacheKey = "cacheKey:book-" + name;
// Retrieve data from hybrid cache
return await _hybridCache.GetOrCreateAsync(cacheKey, async () =>
{
// Simulating getting and returning the data if not exist in the cache
return new BookCacheItem
{
Name = name,
PageCount = 100
};
});
}
}
public class BookCacheItem
{
public string Name { get; set; }
public int PageCount { get; set; }
}
```
* You can use the `IHybridCache<TCacheItem>` or `IHybridCache<TCacheItem, TCacheKey>` service to leverage the hybrid caching. If you use `IHybridCache<TCacheItem>`as the service, then you should pass the cache key as *string* like in the example above.
* In this example, you used the `GetOrCreateAsync` method, which first tries to get the cache item with the provided cache key, if there is no cache with the specified key, then it runs the factory method and add the returned data to the cache.
* Alternatively, you can use the `SetAsync` method to set the cache item.
### Debugging the `IHybridCache` Service (deep-dive)
When you debug the `IHybridCache` service, you'll notice the L1 and L2 cache stores. (L1 is in-memory cache store and L2 is the distributed cache store):
![](debug-hybrid-cache.png)
As you can see from the figure, it only set the cache item to the **LocalCache** (`MemoryCache`) and did not set the **BackendCache** (`DistributedCache`) because I did not configure the distributed cache and not running my application in multiple instances. But as you can notice, even without an `IDistributedCache` configuration, the `HybridCache` service will still provide in-process caching.
**Note:** If you configure distributed caching options, `HybridCache` service uses the distributed cache and sets the **BackendCache**.
## Conclusion
The **HybridCache** library in .NET 9 provides a powerful tool for applications needing both high-speed caching and consistency in distributed environments.
With ABP Framework’s `AbpHybridCache` support, integrating this feature into an ABP-based application becomes straightforward. This setup helps ensure that cached data remains synchronized across instances, bringing a new level of flexibility to caching in .NET 9 applications.
> For more information, you can refer to the [Microsoft's official document](https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-9.0?view=aspnetcore-9.0#new-hybridcache-library).
## References
- https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-9.0?view=aspnetcore-9.0#new-hybridcache-library
- https://www.youtube.com/watch?v=TDyZc11cJfA
- https://github.com/abpframework/abp/pull/20803
- https://github.com/abpframework/abp/pull/20859

BIN
docs/en/Community-Articles/2024-11-01-Hybrid-Cache-Net-9/cover-image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 KiB

BIN
docs/en/Community-Articles/2024-11-01-Hybrid-Cache-Net-9/debug-hybrid-cache.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

5
docs/en/cli/index.md

@ -2,7 +2,7 @@
ABP CLI (Command Line Interface) is a command line tool to perform some common operations for ABP based solutions or ABP Studio features.
> 🛈 With **v8.2+**, the old/legacy ABP CLI has been replaced with a new CLI system to align with the new templating system and [ABP Studio](../studio/index.md). The new ABP CLI commands are explained in this documentation. However, if you want to learn more about the differences between the old and new CLIs, want to learn the reason for the change, or need guidance to use the old ABP CLI, please refer to the [Old vs New CLI](differences-between-old-and-new-cli.md) documentation.
> With **v8.2+**, the old/legacy ABP CLI has been replaced with a new CLI system to align with the new templating system and [ABP Studio](../studio/index.md). The new ABP CLI commands are explained in this documentation. However, if you want to learn more about the differences between the old and new CLIs, want to learn the reason for the change, or need guidance to use the old ABP CLI, please refer to the [Old vs New CLI](differences-between-old-and-new-cli.md) documentation.
>
> You may need to remove the Old CLI before installing the New CLI, by running the following command: `dotnet tool uninstall -g Volo.Abp.Cli`
@ -142,6 +142,9 @@ For more samples, go to [ABP CLI Create Solution Samples](new-command-samples.md
* `angular`: Angular UI. There are some additional options for this template:
* `--tiered`: The Auth Server project comes as a separate project and runs at a different endpoint. It separates the Auth Server from the API Host application. If not specified, you will have a single endpoint in the server side. (*Available for* ***Team*** *or higher licenses*)
* `--progressive-web-app` or `-pwa`: Specifies the project as Progressive Web Application.
* `blazor-webapp`: Blazor Web App UI. There are some additional options for this template:
* `--tiered`: The Auth Server and the API Host project comes as separate projects and run at different endpoints. It has 3 startup projects: *HttpApi.Host*, *AuthServer* and *Blazor* and and each runs on different endpoints. If not specified, you will have a single endpoint for your web project.
* `--progressive-web-app` or `-pwa`: Specifies the project as Progressive Web Application.
* `blazor`: Blazor UI. There are some additional options for this template:
* `--tiered`The Auth Server project comes as a separate project and runs at a different endpoint. It separates the Auth Server from the API Host application. If not specified, you will have a single endpoint in the server side. (*Available for* ***Team*** *or higher licenses*)
* `--progressive-web-app` or `-pwa`: Specifies the project as Progressive Web Application.

60
docs/en/deployment/clustered-environment.md

@ -1,14 +1,15 @@
# Deploying to a Clustered Environment
This document introduces the topics that you should consider when you are deploying your application to a clustered environment where **multiple instances of your application run concurrently**, and explains how you can deal with these topics in your ABP based application.
This document explains the topics that you should consider when deploying your application to a clustered environment where multiple instances of your application run concurrently.
It explains how you can deal with these topics in your ABP application.
> This document is valid regardless you have a monolith application or a microservice solution. The Application term is used for a process. An application can be a monolith web application, a service in a microservice solution, a console application, or another kind of an executable process.
>
> For example, if you are deploying your application to Kubernetes and configure your application or service to run in multiple pods, then your application or service runs in a clustered environment.
> This document is eligible for both monolith and microservice solutions.
> The Application term is used for a process. An application can be a monolith web application, a service in a microservice solution, a console application, or another executable process.
> For example, if you are deploying your application to Kubernetes and configuring your application or service to run in multiple pods, then your application or service runs in a clustered environment.
## Understanding the Clustered Environment
> You can skip this section if you are already familiar with clustered deployment and load balancers.
> You can skip this section if you are familiar with clustered deployment and load balancers.
### Single Instance Deployment
@ -16,11 +17,15 @@ Consider an application deployed as a **single instance**, as illustrated in the
![deployment-single-instance](../images/deployment-single-instance.png)
Browsers and other client applications can directly make HTTP requests to your application. You can put a web server (e.g. IIS or NGINX) between the clients and your application, but you still have a single application instance running in a single server or container. Single-instance configuration is **limited to scale** since it runs in a single server and you are limited with the server's capacity.
Browsers and other client applications can directly make HTTP requests to your application.
You can locate a web server (e.g. IIS or NGINX) between the clients and your application, but you still have a single application instance running in a single server or container.
A single instance configuration is **limited by scale** because it runs on a single server, and the capacity of the server may limit the application's performance.
### Clustered Deployment
**Clustered deployment** is the way of running **multiple instances** of your application **concurrently** in a single or multiple servers. In this way, different instances can serve different requests and you can scale by adding new servers to the system. The following figure shows a typical implementation of clustering using a **load balancer**:
**Clustered deployment** is the way of running **multiple instances** of your application **concurrently** in a single or multiple servers.
In this architecture, different instances can serve different requests, and you can scale them by adding new servers to the system.
The following figure shows a typical implementation of clustering using a **load balancer**:
![deployment-clustered](../images/deployment-clustered.png)
@ -28,53 +33,56 @@ Browsers and other client applications can directly make HTTP requests to your a
[Load balancers](https://en.wikipedia.org/wiki/Load_balancing_(computing)) have a lot of features, but they fundamentally **forward an incoming HTTP request** to an instance of your application and return your response back to the client application.
Load balancers can use different algorithms for selecting the application instance while determining the application instance that is used to deliver the incoming request. **Round Robin** is one of the simplest and most used algorithms. Requests are delivered to the application instances in rotation. First instance gets the first request, second instance gets the second, and so on. It returns to the first instance after all the instances are used, and the algorithm goes like that for the next requests.
Load balancers can use different algorithms to route the requests to an application instance. [Round Robin](https://en.wikipedia.org/wiki/Round-robin_scheduling) is one of the simplest and most used algorithms. Requests are delivered to the application instances in rotation. The first instance gets the first request; the second instance gets the second, and so on. It returns to the first instance after all the instances are used, and the algorithm iterates like this until the next request.
### Potential Problems
Once multiple instances of your application run in parallel, you should carefully consider the following topics:
* Any **state (data) stored in memory** of your application will become a problem when you have multiple instances. A state stored in memory of an application instance may not be available in the next request since the next request will be handled by a different application instance. While there are some solutions (like sticky sessions) to overcome this problem user-basis, it is a **best practice to design your application as stateless** if you want to run it in a cluster, container or/and cloud.
* Any **state (data) stored in memory** of your application will become a problem when you have multiple instances. A state stored in the memory of an application instance may not be available in the next request since the next request will be handled by a different application instance. While there are some solutions (like sticky sessions) to overcome this problem on a user basis, it is a **best practice to design your application as stateless** if you want to run it in a cluster, container or/and cloud.
* **In-memory caching** is a kind of in-memory state and should not be used in a clustered application. You should use **distributed caching** instead.
* You shouldn't store data in the **local file system**. It should be available to all instances of your application. Different application instance may run in different containers or servers and they may not be able to have access to the same file system. You can use a **cloud or external storage provider** as a solution.
* If you have **background workers** or **job queue managers**, you should be careful since multiple instances may try to execute the same job or perform the same work concurrently. As a result, you may have the same work done multiple times or you may get a lot of errors while trying to access and change the same resources.
* If you have **background workers** or **job queue managers**, you should be careful since multiple instances may try to execute the same job or perform the same work concurrently. As a result, you may have the same work done multiple times, or you may get a lot of errors while trying to access and change the same resources.
You may have more problems with clustered deployment, but these are the most common ones. ABP has been designed to be compatible with the clustered deployment scenario. The following sections explain what you should do when you are deploying your ABP based application to a clustered environment.
## Switching to a Distributed Cache
ASP.NET Core provides different kind of caching features. [In-memory cache](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/memory) stores your objects in the memory of the local server and is only available to the application that stored the object. Non-sticky sessions in a clustered environment should use the [distributed caching](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) except some specific scenarios (for example, you can cache a local CSS file into memory. It is read-only data and it is the same in all application instances. You can cache it in memory for performance reasons without any problem).
ASP.NET Core provides different kinds of caching features. [In-memory cache](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/memory) stores your objects in the memory of the local server and is only available to the application that stores the object. Non-sticky sessions in a clustered environment should use the [distributed caching](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) except for some specific scenarios (for example, you can cache a local CSS file into memory. It is read-only data and it is the same in all application instances. You can cache it in memory for performance reasons without any problem).
[ABP's Distributed Cache](../framework/fundamentals/caching.md) extends [ASP.NET Core's distributed cache](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) infrastructure. It works in-memory by default. You should configure an actual distributed cache provider when you want to deploy your application to a clustered environment.
[ABP's Distributed Cache](../framework/fundamentals/caching.md) extends [ASP.NET Core's distributed cache](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) infrastructure. It works in memory by default. You should configure an actual distributed cache provider when you want to deploy your application to a clustered environment.
> You should configure the cache provider for clustered deployment, even if your application doesn't directly use `IDistributedCache`. Because the ABP and the pre-built [application modules](../modules) are using distributed cache.
> You should configure the cache provider for clustered deployment, even if your application doesn't directly use `IDistributedCache`.
> The ABP and the pre-built [application modules](../modules) use distributed cache.
ASP.NET Core provides multiple integrations to use as your distributed cache provider, like [Redis](https://redis.io/) and [NCache](https://www.alachisoft.com/ncache/). You can follow [Microsoft's documentation](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) to learn how to use them in your applications.
If you decided to use Redis as your distributed cache provider, **follow [ABP's Redis Cache Integration document](../framework/fundamentals/redis-cache.md)** for the steps you need to follow to install it into your application and setup your Redis configuration.
> Based on your preferences while creating a new ABP solution, Redis cache might be pre-installed in your solution. For example, if you have selected the *Tiered* option with the MVC UI, Redis cache comes as pre-installed. Because, in this case, you have two applications in your solution and they should use the same cache source to be consistent.
> Depending on your preferences when creating a new ABP solution, Redis cache might be pre-installed.
> For example, if you select the *Tiered* option with the MVC UI, the Redis cache will be pre-installed by default.
> Because, in this case, you have two applications in your solution that should use the same cache source to be consistent.
## Using a Proper BLOB Storage Provider
If you have used ABP's [BLOB Storing](../framework/infrastructure/blob-storing) feature with the [File System provider](../framework/infrastructure/blob-storing/file-system.md), you should use another provider in your clustered environment since the File System provider uses the application's local file system.
If you use ABP's [BLOB Storing](../framework/infrastructure/blob-storing) feature with the [File System provider](../framework/infrastructure/blob-storing/file-system.md), you should use another provider in your clustered environment since the File System provider uses the application's local file system.
The [Database BLOB provider](../framework/infrastructure/blob-storing/database.md) is the easiest way since it uses your application's main database (or another database if you configure) to store BLOBs. However, you should remember that BLOBs are large objects and may quickly increase your database's size.
The [Database BLOB provider](../framework/infrastructure/blob-storing/database.md) is the easiest way since it uses your application's main database (or another database if you configure it) to store BLOBs. However, you should remember that BLOBs are large objects and may quickly increase your database's size.
> [ABP](https://abp.io/) startup solution templates come with the database BLOB provider as pre-installed, and stores BLOBs in the application's database.
> [ABP](https://abp.io/) startup solution templates come with the database BLOB provider as pre-installed and store BLOBs in the application's database.
Check the [BLOB Storing](../framework/infrastructure/blob-storing) document to see all the available BLOB storage providers.
## Configuring Background Jobs
ABP's [background job system](../framework/infrastructure/background-jobs) is used to queue tasks to be executed in the background. Background job queue is persistent and a queued task is guaranteed to be executed (it is re-tried if it fails).
ABP's [background job system](../framework/infrastructure/background-jobs) queues tasks to be executed in the background. The background job queue is persistent, and a queued task is guaranteed to be executed (it will retry if it fails).
ABP's default background job manager is compatible with clustered environments. It uses a [distributed lock](../framework/infrastructure/distributed-locking.md) to ensure that the jobs are executed only in a single application instance at a time. See the *Configuring a Distributed Lock Provider* section below to learn how to configure a distributed lock provider for your application, so the default background job manager properly works in a clustered environment.
ABP's default background job manager is compatible with clustered environments. It uses a [distributed lock](../framework/infrastructure/distributed-locking.md) to ensure that the jobs are executed only in a single application instance at a time. See the *Configuring a Distributed Lock Provider* section below to learn how to configure a distributed lock provider for your application. Hence, the default background job manager properly works in a clustered environment.
If you don't want to use a distributed lock provider, you may go with the following options:
* Stop the background job manager (set `AbpBackgroundJobOptions.IsJobExecutionEnabled` to `false`) in all application instances except one of them, so only the single instance executes the jobs (while other application instances can still queue jobs).
* Stop the background job manager (set `AbpBackgroundJobOptions.IsJobExecutionEnabled` to `false`) in all application instances and create a dedicated application (maybe a console application running in its own container or a Windows Service running in the background) to execute all the background jobs. This can be a good option if your background jobs consume high system resources (CPU, RAM or Disk), so you can deploy that background application to a dedicated server and your background jobs don't affect your application's performance.
* Stop the background job manager (set `AbpBackgroundJobOptions.IsJobExecutionEnabled` to `false`) in all application instances and create a dedicated application (maybe a console application running in its own container or a Windows Service running in the background) to execute all the background jobs. This can be a good option if your background jobs consume high system resources (CPU, RAM, disk), you can deploy that background application to a dedicated server and your background jobs don't affect your application's performance.
> If you are using an external background job integration (e.g. [Hangfire](../framework//infrastructure/background-workers/hangfire.md) or [Quartz](../framework//infrastructure/background-workers/quartz.md)) instead of the default background job manager, then please refer to your provider's documentation to learn how it should be configured for a clustered environment.
@ -82,13 +90,13 @@ If you don't want to use a distributed lock provider, you may go with the follow
ABP provides a distributed locking abstraction with an implementation made with the [DistributedLock](https://github.com/madelson/DistributedLock) library. A distributed lock is used to control concurrent access to a shared resource by multiple applications to prevent corruption of the resource because of concurrent writes. The ABP and some pre-built [application modules](../modules) are using distributed locking for several reasons.
However, the distributed lock system works in-process by default. That means it is not distributed actually, unless you configure a distributed lock provider. So, please follow the [distributed lock](../framework/infrastructure/distributed-locking.md) document to configure a provider for your application, if it is not already configured.
However, the distributed lock system works in-process by default. That means it is not actually distributed unless you configure a distributed lock provider. So, please follow the [distributed lock](../framework/infrastructure/distributed-locking.md) document to configure a provider for your application if it is not already configured.
## Configuring SignalR
ABP provides [SignalR](../framework/real-time/signalr.md) integration packages to simplify integration and usage. SignalR can be used whenever you need to add real-time web functionality (real-time messaging, real-time notification etc.) into your application.
SignalR requires that all HTTP requests for a specific connection be handled (needs to keep track of all its connections) by the same server process. So, when SignalR is running on a clustered environment (with multiple servers) **"sticky sessions"** must be used.
SignalR requires that all HTTP requests for a specific connection be handled (needs to keep track of all its connections) using the same server process. So, when SignalR is running on a clustered environment (with multiple servers), **"sticky sessions"** must be used.
If you are considering [scaling out](https://learn.microsoft.com/en-us/aspnet/core/signalr/scale?view=aspnetcore-6.0#scale-out) your servers and don't want to have inconsistency with the active socket connections, you can use [Azure SignalR Service](https://learn.microsoft.com/en-us/aspnet/core/signalr/scale?view=aspnetcore-6.0#azure-signalr-service) or [Redis backplane](https://learn.microsoft.com/en-us/aspnet/core/signalr/scale?view=aspnetcore-6.0#redis-backplane).
@ -100,10 +108,10 @@ ASP.NET Core provides [hosted services](https://docs.microsoft.com/en-us/aspnet/
If your application has tasks running in the background, you should consider how they will behave in a clustered environment, especially if your background tasks are using the same resources. You should design your background tasks so that they continue to work properly in the clustered environment.
Assume that your background worker in your SaaS application checks user subscriptions and sends emails if their subscription renewal date approaches. If the background task runs in multiple application instances, it is probable to send the same email many times to some users, which will disturb them.
Suppose your SaaS application checks user subscriptions in the background and sends emails to those whose subscription renewal dates are approaching. If the background task runs on multiple application instances, users may get duplicate e-mails.
We suggest you to use one of the following approaches to overcome the problem:
Use one of the following approaches to overcome the **multiple workers same pool problem**:
* Implement your background workers so that they work in a clustered environment without any problem. Using the [distributed lock](../framework/infrastructure/distributed-locking.md) to ensure concurrency control is a way of doing that. A background worker in an application instance may handle a distributed lock, so the workers in other application instances will wait for the lock. In this way, only one worker does the actual work, while others wait in idle. If you implement this, your workers run safely without caring about how the application is deployed.
* Implement your background workers so that they work in a clustered environment without any problems. Using the [distributed lock](../framework/infrastructure/distributed-locking.md) to ensure concurrency control is a way of doing that. A background worker in an application instance may handle a distributed lock, so the workers in other application instances will wait for the lock. In this way, only one worker does the actual work while others wait in an idle state. If you implement this, your workers run safely without caring about how the application is deployed.
* Stop the background workers (set `AbpBackgroundWorkerOptions.IsEnabled` to `false`) in all application instances except one of them, so only the single instance runs the workers.
* Stop the background workers (set `AbpBackgroundWorkerOptions.IsEnabled` to `false`) in all application instances and create a dedicated application (maybe a console application running in its own container or a Windows Service running in the background) to execute all the background tasks. This can be a good option if your background workers consume high system resources (CPU, RAM or Disk), so you can deploy that background application to a dedicated server and your background tasks don't affect your application's performance.
* Stop the background workers (set `AbpBackgroundWorkerOptions.IsEnabled` to `false`) in all application instances and create a dedicated application (maybe a console application running in its own container or a Windows Service running in the background) to execute all the background tasks. This can be a good option if your background workers consume high system resources (CPU, RAM, disk), so you can deploy that background application to a dedicated server and your background tasks don't affect your application's performance.

4
docs/en/deployment/configuring-openIddict.md

@ -26,7 +26,7 @@ public override void PreConfigureServices(ServiceConfigurationContext context)
## Development Environment
We've enabled `AddDevelopmentEncryptionAndSigningCertificate` by default on the development environment. It registers (and generates if necessary) a user-specific development encryption/development signing certificate. This is a certificate used for signing and encrypting the tokens and for **development environment only**.
`AddDevelopmentEncryptionAndSigningCertificate` is enabled by default on the development environment. It registers (and also generates, if necessary, a user-specific development encryption/development signing certificate. This is a certificate used for signing and encrypting the tokens and for **development environment only**.
`AddDevelopmentEncryptionAndSigningCertificate` cannot be used in applications deployed on IIS or Azure App Service: trying to use them on IIS or Azure App Service will result in an exception being thrown at runtime (unless the application pool is configured to [load a user profile](https://learn.microsoft.com/en-us/iis/manage/configuring-security/application-pool-identities#user-profile)).
@ -34,7 +34,7 @@ To avoid that, consider creating self-signed certificates and storing them in th
## Production Environment
We've disabled `AddDevelopmentEncryptionAndSigningCertificate` in the production environment and tried to setup signing and encrypting certificates using `openiddict.pfx` file.
`AddDevelopmentEncryptionAndSigningCertificate` is disabled in production environment. Signing and encryption of certificates is done using `openiddict.pfx` file in production environment.
You can use the `dotnet dev-certs https -v -ep openiddict.pfx -p 00000000-0000-0000-0000-000000000000` command to generate the `authserver.pfx` certificate.

37
docs/en/deployment/configuring-production.md

@ -1,10 +1,13 @@
# Configuring Your Application for Production Environments
ABP has a lot of options to configure and fine-tune its features. They are all explained in their own documents. Default values for these options are pretty well for most of the deployment environments. However, you may need to care about some options based on how you've structured your deployment environment. In this document, we will highlight these kind of options. So, it is highly recommended to read this document in order to not have unexpected behaviors in your system in production.
ABP predefines the configurations for the best performance for common deployment scenarios.
However, depending on how you have structured your deployment environment, you may need to consider some extra options. This document highlights these options.
It is highly recommended that you read it to prevent unexpected behaviors in your production environment.
## Distributed Cache Prefix
ABP's [distributed cache infrastructure](../framework/fundamentals/caching.md) provides an option to set a key prefix for all of your data that is saved into your distributed cache provider. The default value of this option is not set (it is `null`). If you are using a distributed cache server that is shared by different applications, then you can set a prefix value to isolate an application's cache data from others.
ABP's [distributed cache infrastructure](../framework/fundamentals/caching.md) provides an option to set a key prefix for all your data saved into your distributed cache provider.
The default value of this option is not set (it is `null`). If you are using a distributed cache server that is shared by different applications, then you can set a prefix value to isolate an application's cache data from others.
````csharp
Configure<AbpDistributedCacheOptions>(options =>
@ -13,19 +16,21 @@ Configure<AbpDistributedCacheOptions>(options =>
});
````
That's all. ABP, then will add this prefix to all of your cache keys in your application as along as you use ABP's `IDistributedCache<TCacheItem>` or `IDistributedCache<TCacheItem,TKey>` services. See the [Caching documentation](../framework/fundamentals/caching.md) if you are new to distributed caching.
That's all! This prefix will be added to all cache keys in your application, as long as you use ABP's `IDistributedCache<TCacheItem>` or `IDistributedCache<TCacheItem,TKey>` services.
If you are new to distributed caching, check out the [caching documentation](../framework/fundamentals/caching.md).
> **Warning**: If you use ASP.NET Core's standard `IDistributedCache` service, it's your responsibility to add the key prefix (you can get the value by injecting `IOptions<AbpDistributedCacheOptions>`). ABP can not do it.
> **Warning**: If you use ASP.NET Core's standard `IDistributedCache` [service](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.caching.distributed.idistributedcache), it is your responsibility to add the key prefix (you can get the value by injecting `IOptions<AbpDistributedCacheOptions>`). ABP can not do it anymore.
> **Warning**: Even if you have never used distributed caching in your own codebase, ABP still uses it for some features. So, you should always configure this prefix if your caching server is shared among multiple systems.
> **Warning**: If you are building a microservice system, then you will have multiple applications that share the same distributed cache server. In such systems, all applications (or services) should normally use the same cache prefix, because you want all the applications to use the same cache data to have consistency between them.
> **Warning**: If you are building a microservice architecture, then you will have multiple applications that share the same distributed cache server. All applications (sub-services) in these systems should use the same cache prefix and cache values to have application-wide consistency.
> **Warning**: Some of ABP's startup templates are pre-configured to set a prefix value for the distributed cache. So, please check your application code if it is already configured.
> **Warning**: Some of ABP's startup templates are pre-configured to set a prefix value for the distributed cache. If your application code is already configured, please check it.
## Distributed Lock Prefix
ABP's [distributed locking infrastructure](../framework/infrastructure/distributed-locking.md) provides an option to set a prefix for all the keys you are using in the distributed lock server. The default value of this option is not set (it is `null`). If you are using a distributed lock server that is shared by different applications, then you can set a prefix value to isolate an application's lock from others.
ABP's [distributed locking infrastructure](../framework/infrastructure/distributed-locking.md) provides an option to set a prefix for all the keys you use in the distributed lock server. The default value of this option is not set (it is `null`). If you use a distributed lock server shared by different applications, you can set a prefix value to isolate an application's lock from others.
````csharp
Configure<AbpDistributedLockOptions>(options =>
@ -34,29 +39,31 @@ Configure<AbpDistributedLockOptions>(options =>
});
````
That's all. ABP, then will add this prefix to all of your keys in your application. See the [Distributed Locking documentation](../framework/infrastructure/distributed-locking.md) if you are new to distributed locking.
That's all! ABP will add this prefix to all of your keys in your application. See the [Distributed Locking documentation](../framework/infrastructure/distributed-locking.md) if you are new to distributed locking.
> **Warning**: Even if you have never used distributed locking in your own codebase, ABP still uses it for some features. So, you should always configure this prefix if your distributed lock server is shared among multiple systems.
> **Warning**: If you are building a microservice system, then you will have multiple applications that share the same distributed locking server. In such systems, all applications (or services) should normally use the same lock prefix, because you want to globally lock your resources in your system.
> **Warning**: Some of ABP's startup templates are pre-configured to set a prefix value for distributed locking. So, please check your application code if it is already configured.
> **Warning**: Some of ABP's startup templates are pre-configured to set a prefix value for distributed locking. Please check your application code to see if it has already been configured.
## Email Sender
ABP's [Email Sending](../framework/infrastructure/emailing.md) system abstracts sending emails from your application and module code and allows you to configure the email provider and settings in a single place.
Email service is configured to write email contents to the standard [application log](../framework/fundamentals/logging.md) in development environment. You should configure the email settings to be able to send emails to users in your production environment.
For the development environment, ABP will not send real emails. The email service is configured to write email contents in the development environment's standard [application log](../framework/fundamentals/logging.md). By default, it will write to the `Logs.txt` in your host project's `Logs` folder. You should configure the email settings to be able to send emails to users in your production environment.
Please see the [Email Sending](../framework/infrastructure/emailing.md) document to learn how to configure its settings to really send emails.
See the [Sending Email](../framework/infrastructure/emailing.md) document to learn what settings to configure to send actual email without writing to the logs.
> **Warning**: If you don't configure the email settings, you will get errors while trying to send emails. For example, the [Account module](../modules/account.md)'s *Password Reset* feature sends email to the users to reset their passwords if they forget it.
## SMS Sender
ABP's [SMS Sending abstraction](../framework/infrastructure/sms-sending.md) provides a unified interface to send SMS to users. However, its implementation is left to you. Because, typically a paid SMS service is used to send SMS, and ABP doesn't depend on a specific SMS provider.
ABP's [SMS Sending abstraction](../framework/infrastructure/sms-sending.md) provides a unified interface for sending SMS to users.
However, its implementation is left to you. Typically, a paid SMS service is used to send SMS, and ABP doesn't depend on a specific SMS provider.
> PRO users can use the [Twilio SMS module](../modules/twilio-sms.md) to send SMS.
So, if you are using the `ISmsSender` service, you must implement it yourself, as shown in the following code block:
In the following code-block you can see where to implement the `ISmsSender` service:
````csharp
public class MySmsSender : ISmsSender, ITransientDependency
@ -89,11 +96,11 @@ Configure<AbpStringEncryptionOptions>(options =>
});
````
Note that ABP CLI automatically sets the password to a random value on a new project creation. However, it is stored in the `appsettings.json` file and is generally added to your source control. It is suggested to use [User Secrets](https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets) or [Environment Variables](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration) to set that value.
Note that ABP CLI automatically sets the password to a random value on new project creation. However, it is stored in the `appsettings.json` file and is generally added to your source control. It is suggested to use [User Secrets](https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets) or [Environment Variables](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration) to set that value.
## Logging
ABP uses .NET's standard [Logging services](../framework/fundamentals/logging.md). So, it is compatible with any logging provider that works with .NET. ABP's startup solution templates come with [Serilog](https://serilog.net/) pre-installed and configured for you. It writes logs to file system and console with the initial configuration. File system is useful for development environment, but it is suggested you to use a different provider for your production environment, like Elasticsearch, database or any other provider that can properly work.
ABP uses .NET's standard [Logging services](../framework/fundamentals/logging.md). So, it is compatible with any logging provider that works with .NET. ABP's startup solution templates come with [Serilog](https://serilog.net/) pre-installed and configured for you. It writes logs to the file system and console with the initial configuration. The file system is useful for the development environment, but it is suggested you use a different provider for your production environment, like Elasticsearch, database or any other provider that can properly work.
## The Swagger UI

12
docs/en/deployment/distributed-microservice.md

@ -1,6 +1,6 @@
# Deploying Distributed / Microservice Solutions
The ABP is designed to consider distributed and microservice systems, where you have multiple applications and/or services communicating internally. All of its features are compatible with distributed scenarios. This document highlights some points you should care about when you deploy your distributed or microservice solution.
ABP is designed for distributed and microservice systems, where multiple applications and/or services communicate internally. All of its features are compatible with distributed scenarios. This document highlights some points you should consider when deploying your distributed or microservice solution.
## Application Name & Instance Id
@ -9,7 +9,7 @@ ABP provides the `IApplicationInfoAccessor` service that provides the following
* `ApplicationName`: A human-readable name for an application. It is a unique value for an application.
* `InstanceId`: A random (GUID) value generated by the ABP each time you start the application.
These values are used by the ABP in several places to distinguish the application and the application instance (process) in the system. For example, the [audit logging](../framework/infrastructure/audit-logging.md) system saves the `ApplicationName` in each audit log record written by the related application, so you can understand which application has created the audit log entry. So, if your system consists of multiple applications saving audit logs to a single point, you should be sure that each application has a different `ApplicationName`.
ABP uses these values in several places to distinguish the application and the application instance (process) in the system. For example, the [audit logging](../framework/infrastructure/audit-logging.md) system saves the `ApplicationName` in each audit log record written by the related application so you can understand which application has created the audit log entry. So, if your system consists of multiple applications saving audit logs to a single point, you should be sure that each application has a different `ApplicationName`.
The `ApplicationName` property's value is set automatically from the **entry assembly's name** (generally, the project name in a .NET solution) by default, which is proper for most cases, since each application typically has a unique entry assembly name.
@ -32,13 +32,13 @@ await builder.AddApplicationAsync<OrderingServiceHttpApiHostModule>(options =>
## Using a Distributed Event Bus
ABP's [Distributed Event Bus](../framework/infrastructure/event-bus/distributed) system provides a standard interface to communicate with other applications and services. While the name is "distributed", the default implementation is in-process. That means, your applications / services can not communicate with each other unless you explicitly configure a distributed event bus provider.
ABP's [Distributed Event Bus](../framework/infrastructure/event-bus/distributed) system provides a standard interface for communicating with other applications and services. While the name is "distributed," the default implementation is in process. That means your applications/services can not communicate with each other unless you explicitly configure a distributed event bus provider.
If you are building a distributed system, then the applications should communicate through an external distributed messaging server. Please follow the [Distributed Event Bus](../framework/infrastructure/event-bus/distributed) document to learn how to install and configure your distributed event bus provider.
The applications should communicate through an external distributed messaging server if you are building a distributed system. Please follow the [Distributed Event Bus](../framework/infrastructure/event-bus/distributed) document to learn how to install and configure your distributed event bus provider.
> **Warning**: Even if you don't use the distributed event bus directly in your application code, the ABP and some of the modules you are using may use it. So, if you are building a distributed system, always configure a distributed event bus provider.
> **Warning**: Even if you do not use the distributed event bus directly in your application code, ABP and some of the modules you are using may use it. So, if you are building a distributed system, always configure a distributed event bus provider.
> **Info**: [Clustered deployment](./clustered-environment.md) of a single application is not considered as a distributed system. So, if you only have a single application with multiple instances serving behind a load balancer, a real distributed messaging server may not be needed.
> **Info**: [Clustered deployment](./clustered-environment.md) of a single application is not considered as distributed system. So, a real distributed messaging server may not be needed if you only have a single application with multiple instances serving behind a load balancer.
## See Also

4
docs/en/deployment/index.md

@ -1,6 +1,6 @@
# Deployment
Deploying an ABP application is not different than deploying any .NET or ASP.NET Core application. You can deploy it to a cloud provider (e.g. Azure, AWS, Google Could) or on-premise server, IIS or any other web server. ABP's documentation doesn't contain much information on deployment. You can refer to your provider's documentation.
Deploying an ABP application is not different than deploying any .NET or ASP.NET Core application. You can deploy it to a cloud provider (e.g., Azure, AWS, Google Could) or an on-premise server, IIS or any other web server. ABP's documentation doesn't contain much information on deployment. You can refer to your provider's documentation.
However, there are some topics that you should care about when you are deploying your applications. Most of them are general software deployment considerations, but you should understand how to handle them within your ABP based applications. We've prepared guides for this purpose and we suggest you to read these guides carefully before designing your deployment configuration.
@ -9,6 +9,6 @@ However, there are some topics that you should care about when you are deploying
* [Configuring SSL certificate(HTTPS)](./ssl.md): Explains how to configure SSL certificate(HTTPS) for your application.
* [Configuring OpenIddict](./configuring-openIddict.md): Notes for some essential configurations for OpenIddict.
* [Configuring for Production](./configuring-production.md): Notes for some essential configurations for production environments.
* [Optimization for Production](./optimizing-production.md): Tips and suggestions for optimizing your application on production environments.
* [Optimization for Production](./optimizing-production.md): Tips and suggestions for optimizing your application in production environments.
* [Deploying to a Clustered Environment](./clustered-environment.md): Explains how to configure your application when you want to run multiple instances of your application concurrently.
* [Deploying Distributed / Microservice Solutions](./distributed-microservice.md): Deployment notes for solutions consisting of multiple applications and/or services.

20
docs/en/deployment/optimizing-production.md

@ -1,22 +1,26 @@
# Optimizing Your Application for Production Environments
ABP and the startup solution templates are configured well to get the maximum performance on production environments. However, there are still some points you need to pay attention to in order to optimize your system in production. In this document, we will mention some of these topics.
ABP and the startup solution templates are configured well to get the maximum performance on production environments.
However, you still need to pay attention to some points to optimize your system in production.
This document will explain optimization points for the production environment.
## Caching Static Contents
The following items are contents that can be cached in the client side (typically in the Browser) or in a CDN server:
The following items are contents that can be cached on the client side (typically in the Browser) or in a CDN server:
* **Static images** can always be cached. Here, you should be careful that if you change an image, use a different file name, or use a versioning query-string parameter, so the browser (or CDN) understands it's been changed.
* **CSS and JavaScript files**. ABP's [bundling & minification](../framework/ui/mvc-razor-pages/bundling-minification.md) system always uses a query-string versioning parameter and a hash value in the files names of the CSS & JavaScript files for the [MVC (Razor Pages)](../framework/ui/mvc-razor-pages/overall.md) UI. So, you can safely cache these files in the client side or in a CDN server.
* **Static images** can always be cached. Here, you should be careful that if you change an image, use a different file name, or use a versioning query-string parameter so the browser (or CDN) understands it's been changed.
* **CSS and JavaScript files**. ABP's [bundling & minification](../framework/ui/mvc-razor-pages/bundling-minification.md) system always uses a query-string versioning parameter and a hash value in the files names of the CSS & JavaScript files for the [MVC (Razor Pages)](../framework/ui/mvc-razor-pages/overall.md) UI. So you can safely cache these files on the client side or on a CDN server.
* **Application bundle files** of an [Angular UI](../framework/ui/angular/quick-start.md) application.
* **[Application Localization Endpoint](../framework/api-development/standard-apis/localization.md)** can be cached per culture (it already has a `cultureName` query string parameter) if you don't use dynamic localization on the server-side. ABP's [Language Management](https://abp.io/modules/Volo.LanguageManagement) module provides dynamic localization. If you're using it, you can't cache that endpoint forever. However, you can still cache it for a while. Applying dynamic localization text changes to the application can delay for a few minutes, even for a few hours in a real life scenario.
* **[Application Localization Endpoint](../framework/api-development/standard-apis/localization.md)** can be cached per culture (it already has a `cultureName` query string parameter) if you don't use dynamic localization on the server-side. ABP's [Language Management](https://abp.io/modules/Volo.LanguageManagement) module provides dynamic localization. If you're using it, you can't cache that endpoint forever. However, you can still cache it for a while. Applying dynamic localization text changes to the application can delay a few minutes, even a few hours, in a real-life scenario.
There may be more ways based on your solution structure and deployment environment, but these are the essential points you should consider to client-side cache in a production environment.
There may be more ways based on your solution structure and deployment environment, but these are the essential points you should consider for client-side cache in a production environment.
## Bundling & Minification for MVC (Razor Pages) UI
ABP's [bundling & minification](../framework/ui/mvc-razor-pages/bundling-minification.md) system automatically bundles, minifies and versions your CSS and JavaScript files in production environment. Normally, you don't need to do anything, if you haven't disabled it yourself in your application code. It is important to follow the [bundling & minification](../framework/ui/mvc-razor-pages/bundling-minification.md) document and truly use the system to get the maximum optimization.
ABP's [bundling & minification](../framework/ui/mvc-razor-pages/bundling-minification.md) system automatically bundles, minifies and versions your CSS and JavaScript files in the production environment.
Normally, you don't need to do anything if you have not disabled it yourself in your application code.
It is important to follow the [bundling & minification](../framework/ui/mvc-razor-pages/bundling-minification.md) document and truly use the system to get the maximum optimization.
## Background Jobs
ABP's [Background Jobs](../framework/infrastructure/background-jobs) system provides an abstraction with a basic implementation to enqueue jobs and execute them in a background thread. ABP's Default Background Job Manager may not be enough if you are adding too many jobs to the queue and want them to be executed in parallel by multiple servers with a high performance. If you need these, you should consider to configure a dedicated background job software, like [Hangfire](https://www.hangfire.io/). ABP has a pre-built [Hangfire integration](../framework/infrastructure/background-jobs/hangfire.md), so you can switch to Hangfire without changing your application code.
ABP's [Background Jobs](../framework/infrastructure/background-jobs) system provides an abstraction with a basic implementation to enqueue jobs and execute them in a background thread. ABP's Default Background Job Manager may not be enough if you are adding too many jobs to the queue and want them to be executed in parallel by multiple servers with a high performance. If you need these, you should consider configuring a dedicated background job software, like [Hangfire](https://www.hangfire.io/). ABP has a pre-built [Hangfire integration](../framework/infrastructure/background-jobs/hangfire.md), so you can switch to Hangfire without changing your application code.

19
docs/en/deployment/ssl.md

@ -1,10 +1,8 @@
# Configuring SSL certificate(HTTPS)
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 an SSL certificate(HTTPS) for your application.
A website needs an SSL certificate to keep user data secure, verify ownership, prevent attackers from creating a fake version of the site, and gain user trust.
This document introduces how to get and use an SSL certificate (HTTPS) for your application.
## Get an SSL Certificate from a Certificate Authority
@ -16,16 +14,12 @@ 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)
### 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:
@ -34,11 +28,8 @@ Ensure that you have `curl` command in your terminal. And run the following comm
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
@ -58,8 +49,6 @@ You must give acme.sh the account ID of the Cloudflare account to which the rele
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
@ -123,8 +112,6 @@ openssl pkcs12 -export \
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**.
@ -140,8 +127,6 @@ You will may see the following SSL certificate errors in your browser when you t
---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot
```
## References
* [ABP IIS Deployment](./index.md)

80
docs/en/docs-nav.json

@ -23,19 +23,19 @@
"text": "Others",
"items": [
{
"text": "Empty ASP.NET Core MVC / Razor Pages Application",
"text": "Empty ASP.NET Core Application",
"path": "get-started/empty-aspnet-core-application.md"
},
{
"text": "MAUI Application Startup Template",
"text": "MAUI Application",
"path": "get-started/maui.md"
},
{
"text": "WPF Application Startup Template",
"text": "WPF Application",
"path": "get-started/wpf.md"
},
{
"text": "Console Application Startup Template",
"text": "Console Application",
"path": "get-started/console.md"
}
]
@ -67,7 +67,7 @@
]
},
{
"text": "Web Application Development",
"text": "Book Store Application",
"items": [
{
"text": "Overview",
@ -657,7 +657,7 @@
"path": "framework/architecture"
},
{
"text": "Module Development Best Practices & Conventions",
"text": "Module Development Best Practices",
"items": [
{
"text": "Overview",
@ -1648,14 +1648,59 @@
},
{
"text": "Layered Solution",
"path": "solution-templates/layered-web-application"
"path": "solution-templates/layered-web-application",
"items": [
{
"text": "Deployment",
"path": "solution-templates/layered-web-application/deployment",
"items": [
{
"text": "Docker Deployment",
"path": "solution-templates/layered-web-application/deployment/deployment-docker-compose.md"
},
{
"text": "Azure Deployment",
"items": [
{
"text": "Deploy to Azure Web App Service",
"path": "solution-templates/layered-web-application/deployment/azure-deployment/azure-deployment.md"
},
{
"text": "Creating an Azure Web App Service Environment",
"path": "solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md"
},
{
"text": "Customizing the Configuration of Your ABP Application",
"path": "solution-templates/layered-web-application/deployment/azure-deployment/step2-configuration-application.md"
},
{
"text": "Deploying Application With GitHub Actions",
"path": "solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md"
}
]
},
{
"text": "IIS Deployment",
"path": "solution-templates/layered-web-application/deployment/deployment-iis.md"
},
{
"text": "IdentityServer Deployment",
"path": "solution-templates/layered-web-application/deployment/identityserver-deployment.md"
},
{
"text": "OpenIddict Deployment",
"path": "solution-templates/layered-web-application/deployment/openiddict-deployment.md"
}
]
}
]
},
{
"text": "Microservice Solution",
"path": "solution-templates/microservice"
},
{
"text": "Module Solution",
"text": "Application Module",
"path": "solution-templates/application-module"
}
]
@ -1673,7 +1718,16 @@
},
{
"text": "Account (Pro)",
"path": "modules/account-pro.md"
"items": [
{
"text": "Overview",
"path": "modules/account-pro.md"
},
{
"text": "Tenant impersonation & User impersonation",
"path": "modules/account/impersonation.md"
}
]
},
{
"text": "Audit Logging",
@ -1886,13 +1940,17 @@
"text": "Overview",
"path": "samples"
},
{
"text": "EventHub",
"path": "https://github.com/abpframework/eventhub"
},
{
"text": "eShopOnAbp",
"path": "https://github.com/abpframework/eShopOnAbp"
},
{
"text": "EventHub",
"path": "https://github.com/abpframework/eventhub"
"text": "CMS Kit Demo",
"path": "https://github.com/abpframework/cms-kit-demo"
},
{
"text": "Easy CRM",

6
docs/en/framework/architecture/domain-driven-design/specifications.md

@ -81,7 +81,7 @@ namespace MyProject
{
public class CustomerService : ITransientDependency
{
public async Task BuyAlcohol(Customer customer)
public async Task BookRoom(Customer customer)
{
if (!new Age18PlusCustomerSpecification().IsSatisfiedBy(customer))
{
@ -120,7 +120,7 @@ namespace MyProject
_customerRepository = customerRepository;
}
public async Task<List<Customer>> GetCustomersCanBuyAlcohol()
public async Task<List<Customer>> GetCustomersCanBookRoom()
{
var queryable = await _customerRepository.GetQueryableAsync();
var query = queryable.Where(
@ -254,4 +254,4 @@ Some benefits of using specifications:
### When To Not Use?
- **Non business expressions**: Do not use specifications for non business-related expressions and operations.
- **Reporting**: If you are just creating a report, do not create specifications, but directly use `IQueryable` & LINQ expressions. You can even use plain SQL, views or another tool for reporting. DDD does not necessarily care about reporting, so the way you query the underlying data store can be important from a performance perspective.
- **Reporting**: If you are just creating a report, do not create specifications, but directly use `IQueryable` & LINQ expressions. You can even use plain SQL, views or another tool for reporting. DDD does not necessarily care about reporting, so the way you query the underlying data store can be important from a performance perspective.

2
docs/en/framework/architecture/modularity/extending/module-entity-extensions.md

@ -48,7 +48,7 @@ public static void ConfigureExtraProperties()
* `AddOrUpdateProperty` gets a second argument (the `property =>` lambda expression) to configure additional options for the new property.
* We can add data annotation attributes like shown here, just like adding a data annotation attribute to a class property.
#### Create & Update Forms
### Create & Update Forms
Once you define a property, it appears in the create and update forms of the related entity:

4
docs/en/framework/data/entity-framework-core/migrations.md

@ -4,7 +4,7 @@ This document begins by **introducing the default structure** provided by [the a
> This document is for who want to fully understand and customize the database structure comes with [the application startup template](../../../solution-templates/layered-web-application). If you simply want to create entities and manage your code first migrations, just follow [the startup tutorials](../../../tutorials/book-store/part-01.md).
### Source Code
## Source Code
You can find the source code of the example project referenced by this document [here](https://github.com/abpframework/abp-samples/tree/master/EfCoreMigrationDemo). However, you need to read and understand this document in order to understand the example project's source code.
@ -554,4 +554,4 @@ This document explains how to split your databases and manage your database migr
## Source Code
You can find the source code of the example project referenced by this document [here](https://github.com/abpframework/abp-samples/tree/master/EfCoreMigrationDemo). You can also find the changes explained in this document as a [single commit](https://github.com/abpframework/abp-samples/pull/95/commits/c2ffd76175e0a6fdfcf6477bbaea23dc2793fedd).
You can find the source code of the example project referenced by this document [here](https://github.com/abpframework/abp-samples/tree/master/EfCoreMigrationDemo). You can also find the changes explained in this document as a [single commit](https://github.com/abpframework/abp-samples/pull/95/commits/c2ffd76175e0a6fdfcf6477bbaea23dc2793fedd).

8
docs/en/framework/fundamentals/exception-handling.md

@ -31,7 +31,7 @@ Error Message is an instance of the `RemoteServiceErrorResponse` class. The simp
There are **optional fields** those can be filled based upon the exception that has occurred.
##### Error Code
#### Error Code
Error **code** is an optional and unique string value for the exception. Thrown `Exception` should implement the `IHasErrorCode` interface to fill this field. Example JSON value:
@ -46,7 +46,7 @@ Error **code** is an optional and unique string value for the exception. Thrown
Error code can also be used to localize the exception and customize the HTTP status code (see the related sections below).
##### Error Details
#### Error Details
Error **details** in an optional field of the JSON error message. Thrown `Exception` should implement the `IHasErrorDetails` interface to fill this field. Example JSON value:
@ -60,7 +60,7 @@ Error **details** in an optional field of the JSON error message. Thrown `Except
}
```
##### Validation Errors
#### Validation Errors
**validationErrors** is a standard field that is filled if the thrown exception implements the `IHasValidationErrors` interface.
@ -340,4 +340,4 @@ Here, a list of the options you can configure:
## See Also
* [Video tutorial](https://abp.io/video-courses/essentials/exception-handling)
* [Video tutorial](https://abp.io/video-courses/essentials/exception-handling)

4
docs/en/framework/fundamentals/localization.md

@ -183,7 +183,7 @@ public class MyService : ITransientDependency
}
````
##### Format Arguments
### Format Arguments
Format arguments can be passed after the localization key. If your message is `Hello {0}, welcome!`, then you can pass the `{0}` argument to the localizer like `_localizer["HelloMessage", "John"]`.
@ -255,4 +255,4 @@ See the following documents to learn how to reuse the same localization texts in
* [Localization for the MVC / Razor Pages UI](../ui/mvc-razor-pages/javascript-api/localization)
* [Localization for the Blazor UI](../ui/blazor/localization.md)
* [Localization for the Angular UI](../ui/angular/localization.md)
* [Video tutorial](https://abp.io/video-courses/essentials/localization)
* [Video tutorial](https://abp.io/video-courses/essentials/localization)

2
docs/en/framework/infrastructure/audit-logging.md

@ -14,7 +14,7 @@ An **audit log object** (see the Audit Log Object section below) is typically cr
> [Startup templates](../../solution-templates) are configured for the audit logging system which is suitable for most of the applications. Use this document for a detailed control over the audit log system.
### Database Provider Support
## Database Provider Support
* Fully supported by the [Entity Framework Core](../data/entity-framework-core) provider.
* Entity change logging is not supported by the [MongoDB](../data/mongodb) provider. Other features work as expected.

2
docs/en/framework/infrastructure/json.md

@ -63,7 +63,7 @@ Properties:
Add [Volo.Abp.Json.Newtonsoft](https://www.nuget.org/packages/Volo.Abp.Json.Newtonsoft) package and depends on `AbpJsonNewtonsoftModule` to replace the `System Text Json`.
#### AbpNewtonsoftJsonSerializerOptions
### AbpNewtonsoftJsonSerializerOptions
- **JsonSerializerSettings(`Newtonsoft.Json.JsonSerializerSettings`)**: Global options for Newtonsoft library operations. See [here](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonSerializerSettings.htm) for reference.

12
docs/en/framework/ui/angular/account-module.md

@ -7,7 +7,7 @@ If you add the account module to your project;
- "My account" link in the current user dropdown on the top bar will redirect the user to a page in the account module.
- You can switch the authentication flow to the resource owner password flow.
### Account Module Implementation
## Account Module Implementation
Install the `@abp/ng.account` NPM package by running the below command:
@ -49,7 +49,7 @@ const routes: Routes = [
export class AppRoutingModule {}
```
### Account Public Module Implementation for Commercial Templates
## Account Public Module Implementation for Commercial Templates
The pro startup template comes with `@volo/abp.ng.account` package. You should update the package version to v4.3 or higher version. The package can be updated by running the following command:
@ -97,11 +97,11 @@ const routes: Routes = [
export class AppRoutingModule {}
```
### My Account Page
## My Account Page
Before v4.3, the "My account" link in the current user dropdown on the top bar redirected the user to MVC's profile management page. As of v4.3, if you added the account module to your project, the same link will land on a page in the Angular UI account module instead.
### Personal Info Page Confirm Message
## Personal Info Page Confirm Message
When the user changes their own data on the personal settings tab in My Account, The data can not update the CurrentUser key of Application-Configuration. The information of the user is stored in claims. The only way to apply this information to the CurrentUser of Application-Configuration is user should log out and log in. When the Refresh-Token feature is implemented, it will be fixed. So We've added a confirmation alert.
@ -119,11 +119,11 @@ const routes: Routes = [
export class AppRoutingModule {}
```
### Security Logs Page [COMMERCIAL]
## Security Logs Page [COMMERCIAL]
Before v4.3, the "Security Logs" link in the current user dropdown on the top bar redirected the user to MVC's security logs page. As of v4.3, if you added the account module to your project, the same link will land on a page in the Angular UI account public module instead.
### Resource Owner Password Flow
## Resource Owner Password Flow
OAuth is preconfigured as authorization code flow in Angular application templates by default. If you added the account module to your project, you can switch the flow to resource owner password flow by changing the OAuth configuration in the _environment.ts_ files as shown below:

2
docs/en/framework/ui/angular/current-user.md

@ -2,7 +2,7 @@
The current user information stored in Config State.
### How to Get a Current User Information Configuration
## How to Get a Current User Information Configuration
You can use the `getOne` or `getOne$` method of `ConfigStateService` to get a specific configuration property. For that, the property name should be passed to the method as parameter.

6
docs/en/framework/ui/angular/datetime-format-pipe.md

@ -11,21 +11,21 @@ Example
ShortDate, ShortTime and ShortDateTime format data like angular's data pipe but easier. Also the pipes get format from config service by culture.
# ShortDate Pipe
## ShortDate Pipe
```html
<span> {{today | shortDate }}</span>
```
# ShortTime Pipe
## ShortTime Pipe
```html
<span> {{today | shortTime }}</span>
```
# ShortDateTime Pipe
## ShortDateTime Pipe
```html
<span> {{today | shortDateTime }}</span>

2
docs/en/framework/ui/angular/http-error-handling.md

@ -1,6 +1,6 @@
# HTTP Error Handling
### Error Configurations
## Error Configurations
ABP offers a configurations for errors handling like below

BIN
docs/en/framework/ui/angular/images/list-service-request-status.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

99
docs/en/framework/ui/angular/list-service.md

@ -139,35 +139,85 @@ You may use observables in combination with [AsyncPipe](https://angular.io/guide
<!-- DO NOT WORRY, ONLY ONE REQUEST WILL BE MADE -->
```
...or...
## Handle request status
To handle the request status `ListService` provides a `requestStatus$` observable. This observable emits the current status of a request, which can be one of the following values: `idle`, `loading`, `success` or `error`. These statuses allow you to easily manage the UI flow based on the request's state.
![RequestStatus](./images/list-service-request-status.gif)
```js
@Select(BookState.getBooks)
books$: Observable<BookDto[]>;
import { ListService } from '@abp/ng.core';
import { AsyncPipe } from '@angular/common';
import { Component, inject } from '@angular/core';
import { BookDto, BooksService } from './books.service';
@Select(BookState.getBookCount)
bookCount$: Observable<number>;
@Component({
standalone: true,
selector: 'app-books',
templateUrl: './books.component.html',
providers: [ListService, BooksService],
imports: [AsyncPipe],
})
export class BooksComponent {
list = inject(ListService);
booksService = inject(BooksService);
ngOnInit() {
this.list.hookToQuery((query) => this.store.dispatch(new GetBooks(query))).subscribe();
items = new Array<BookDto>();
count = 0;
//It's an observable variable
requestStatus$ = this.list.requestStatus$;
ngOnInit(): void {
this.list
.hookToQuery(() => this.booksService.getList())
.subscribe(response => {
this.items = response.items;
this.count = response.totalCount;
});
}
}
```
{%{
```html
<!-- simplified representation of the template -->
<ngx-datatable
[rows]="(books$ | async) || []"
[count]="(bookCount$ | async) || 0"
[list]="list"
default
>
<!-- column templates here -->
</ngx-datatable>
<div class="card">
<div class="card-header">
@if (requestStatus$ | async; as status) {
@switch (status) {
@case ('loading') {
<div style="height: 62px">
<div class="spinner-border" role="status" id="loading">
<span class="visually-hidden">Loading...</span>
</div>
</div>
}
@case ('error') {
<h4>Error occured</h4>
}
@default {
<h4>Books</h4>
}
}
}
</div>
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
@for (book of items; track book.id) {
<tr>
<td>{{ book.id }}</td>
<td>{{ book.name }}</td>
</tr>
}
</tbody>
</table>
</div>
```
> We do not recommend using the NGXS store for CRUD pages unless your application needs to share list information between components or use it later on in another page.
}%}
## How to Refresh Table on Create/Update/Delete
@ -183,15 +233,6 @@ You may use observables in combination with [AsyncPipe](https://angular.io/guide
});
```
...or...
```js
this.store.dispatch(new DeleteBook(id)).subscribe(this.list.get);
```
> We do not recommend using the NGXS store for CRUD pages unless your application needs to share list information between components or use it later on in another page.
## How to Implement Server-Side Search in a Table
`ListService` exposes a `filter` property that will trigger a request with the current query and the given search string. All you need to do is to bind it to an input element with two-way binding.

4
docs/en/framework/ui/angular/localization.md

@ -215,7 +215,7 @@ The localizations above can be used like this:
As of v2.9 ABP has RTL support. If you are generating a new project with v2.9 and above, everything is set, you do not need to do any changes. If you are migrating your project from an earlier version, please follow the 2 steps below:
#### Step 1. Create Chunks for Bootstrap LTR and RTL
### Step 1. Create Chunks for Bootstrap LTR and RTL
Find [styles configuration in angular.json](https://angular.io/guide/workspace-config#style-script-config) and make sure the chunks in your project has `bootstrap-rtl.min` and `bootstrap-ltr.min` as shown below.
@ -257,7 +257,7 @@ Find [styles configuration in angular.json](https://angular.io/guide/workspace-c
}
```
#### Step 2. Clear Lazy Loaded Fontawesome in AppComponent
### Step 2. Clear Lazy Loaded Fontawesome in AppComponent
If you have created and injected chunks for Fontawesome as seen above, you no longer need the lazy loading in the `AppComponent` which was implemented before v2.9. Simply remove them. The `AppComponent` in the template of the new version looks like this:

2
docs/en/framework/ui/angular/sorting-navigation-elements.md

@ -5,7 +5,7 @@ This documentation describes how the navigation elements are sorted and how to c
- When you want to add the `Navigation Element` you can use the `RoutesService`. For more details, see the [document](../angular/modifying-the-menu.md).
- However, in this documentation, we will talk more about how to sort the navigation elements.
### Order Property
## Order Property
- Normally, you are able to sort your routes with this property. But you can customize our default sorting algorithm.

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

@ -85,7 +85,7 @@ See the [User Interface Customization Guide](customization-user-interface.md) to
You can run the following [ABP CLI](../../../cli) command in **Web** project directory to copy the source code to your solution:
`abp add-module Volo.BasicTheme --with-source-code --add-to-solution-file`
`abp add-source-code Volo.Abp.BasicTheme`
----

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-additional-options-microservice.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 83 KiB

BIN
docs/en/get-started/images/abp-studio-new-solution-dialog-additional-options.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 88 KiB

4
docs/en/get-started/layered-web-application.md

@ -41,7 +41,7 @@ The following tools should be installed on your development machine:
## Creating a New Solution
> 🛈 This document uses [ABP Studio](../studio/index.md) to create new ABP solutions. **ABP Studio** is in the beta version now. If you have any issues, you can use the [ABP CLI](../cli/index.md) to create new solutions. You can also use the [getting started page](https://abp.io/get-started) to easily build ABP CLI commands for new project creations.
> This document uses [ABP Studio](../studio/index.md) to create new ABP solutions. **ABP Studio** is in the beta version now. If you have any issues, you can use the [ABP CLI](../cli/index.md) to create new solutions. You can also use the [getting started page](https://abp.io/get-started) to easily build ABP CLI commands for new project creations.
> ABP startup solution templates have many options for your specific needs. If you don't understand an option that probably means you don't need it. We selected common defaults for you, so you can leave these options as they are.
@ -119,7 +119,7 @@ Here, you can select the database management systems (DBMS){{ if DB == "EF" }} a
![abp-studio-new-solution-dialog-additional-options](images/abp-studio-new-solution-dialog-additional-options.png)
If you uncheck the *Kubernetes Configuration* option, the solution will not include the Kubernetes configuration files, such as Helm charts and other Kubernetes-related files. You can also specify *Social Logins*; if you uncheck this option, the solution will not be configured for social login.
If you uncheck the *Kubernetes Configuration* option, the solution will not include the Kubernetes configuration files, such as Helm charts and other Kubernetes-related files. You can also specify *Social Logins*; if you uncheck this option, the solution will not be configured for social login. Lastly, you can specify the *Include Tests* option to include or exclude the test projects from the solution.
Now, we are ready to allow ABP Studio to create our solution. Just click the *Create* button and let the ABP Studio do the rest for you. After clicking the Create button, the dialog is closed and your solution is loaded into ABP Studio:

2
docs/en/get-started/microservice.md

@ -71,7 +71,7 @@ Click the Next button to see *Additional Options* selection:
![abp-studio-new-solution-dialog-additional-options](images/abp-studio-new-solution-dialog-additional-options-microservice.png)
If you unchecked the *Kubernetes Configuration* option, the solution will not include the Kubernetes configuration files which include the Helm charts and other Kubernetes related files. You can also specify *Social Logins*; if you uncheck this option, the solution will not be configured for social login.
If you unchecked the *Kubernetes Configuration* option, the solution will not include the Kubernetes configuration files which include the Helm charts and other Kubernetes related files. You can also specify *Social Logins*; if you uncheck this option, the solution will not be configured for social login. Lastly, you can specify the *Include Tests* option to include the test projects in the solution.
Now, we are ready to allow ABP Studio to create our solution. Just click the *Create* button and let the ABP Studio do the rest for you. After clicking the Create button, the dialog is closed and your solution is loaded into ABP Studio:

BIN
docs/en/images/my-externa-logins.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

BIN
docs/en/images/new-external-login.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
docs/en/images/require-local-password-on-social-account-linking.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

1
docs/en/index.md

@ -2,6 +2,7 @@
ABP offers an **opinionated architecture** to build enterprise software solutions with **best practices** on top of the **.NET** and the **ASP.NET Core** platforms. It provides the fundamental infrastructure, production-ready startup templates, pre-built application modules, UI themes, tooling, guides and documentation to implement that architecture properly and **automate the details** and repetitive works as much as possible.
## Why ABP Platform?
The following pages outline why you should use the ABP Platform and how it is used:
* [Why choose ABP?](https://abp.io/why-choose-abp)

22
docs/en/modules/account-pro.md

@ -119,7 +119,7 @@ Follow the steps below to install a new external/social login. We will show Face
#### Add the NuGet Package
Add the [Microsoft.AspNetCore.Authentication.Facebook](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.Facebook) package to your project. Based on your architecture, this can be `.Web`, `.IdentityServer` (for tiered setup) or `.Host` project.
Add the [Microsoft.AspNetCore.Authentication.Facebook](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.Facebook) package to your project. Based on your architecture, this can be `.Web`, `.AuthServer` (for tiered setup) or `.Host` project.
#### Configure the Provider
@ -194,12 +194,26 @@ context.Services.AddAuthentication()
context.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureAccountExternalProviderOptions<OpenIdConnectOptions>, OpenIdConnectPostConfigureAccountExternalProviderOptions>());
````
#### For Tiered / Separate IdentityServer Solutions
#### For Tiered / Separate AuthServer Solutions
If your `.IdentityServer` is separated from the `.Host` project, then the `.Host` project should also be configured.
If your `.AuthServer` is separated from the `.Host` project, then the `.Host` project should also be configured.
* Add the [Microsoft.AspNetCore.Authentication.Facebook](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.Facebook) package to your `.Host` project.
* Add `WithDynamicOptions<FacebookOptions>()` configuration into the `ConfigureServices` method of your module (just copy the all code above and remove the `.AddFacebook(...)` part since it is only needed in the IdentityServer side).
* Add `WithDynamicOptions<FacebookOptions>()` configuration into the `ConfigureServices` method of your module (just copy the all code above and remove the `.AddFacebook(...)` part since it is only needed in the AuthServer side).
## Manage External Logins
You can link an external login in `Account/ExternalLogins` page of `Account` module.
![my-externa-logins](../images/my-externa-logins.png)
![new-external-login](../images/new-external-login.png)
### Social Account Security Setting
Users who register via both local registration and external/social login using the same email address will be required to enter their local password on the first external/social login.
![require-local-password-on-social-account-linking](../images/require-local-password-on-social-account-linking.png)
## Internals

22
docs/en/modules/account/impersonation.md

@ -71,7 +71,7 @@ No need to do anything here.
#### Web
1. Depends `AbpAccountPublicWebImpersonationModule(Volo.Abp.Account.Pro.Public.Web.Impersonation)` on your `WebModule`
2. Chnage the base class of `AccountController` to `AbpAccountImpersonationChallengeAccountController`
2. Change the base class of `AccountController` to `AbpAccountImpersonationChallengeAccountController`
```cs
public class AccountController : AbpAccountImpersonationChallengeAccountController
@ -197,7 +197,7 @@ No need to do anything here.
1. Depends `AbpAccountPublicWebImpersonationModule(Volo.Abp.Account.Pro.Public.Web.Impersonation)` and `AbpAccountPublicBlazorServerModule(Volo.Abp.Account.Pro.Public.Blazor.Server)` on your `BlazorModule`
2. Chnage the base class of `AccountController` to `AbpAccountImpersonationChallengeAccountController`
2. Change the base class of `AccountController` to `AbpAccountImpersonationChallengeAccountController`
```cs
public class AccountController : AbpAccountImpersonationChallengeAccountController
{
@ -258,6 +258,20 @@ if (!consoleAndAngularClientId.IsNullOrWhiteSpace())
}
```
Add `impersonation: { userImpersonation: true, tenantImpersonation: true}` object to `oAuthConfig` of `environment` if not exits.
```js
export const environment = {
//Other props..
oAuthConfig: {
//Other props..
impersonation: {
userImpersonation: true,
tenantImpersonation: true,
},
},
```
### Blazor WASM
It is currently not supported.
@ -287,7 +301,7 @@ public override void ConfigureServices(ServiceConfigurationContext context)
#### Web
1. Depends `AbpAccountPublicWebImpersonationModule(Volo.Abp.Account.Pro.Public.Web.Impersonation)` on your `WebModule`
2. Chnage the base class of `AccountController` to `AbpAccountImpersonationChallengeAccountController`
2. Change the base class of `AccountController` to `AbpAccountImpersonationChallengeAccountController`
```cs
public class AccountController : AbpAccountImpersonationChallengeAccountController
@ -353,7 +367,7 @@ public override void ConfigureServices(ServiceConfigurationContext context)
1. Depends `AbpAccountPublicWebImpersonationModule(Volo.Abp.Account.Pro.Public.Web.Impersonation)` and `AbpAccountPublicBlazorServerModule(Volo.Abp.Account.Pro.Public.Blazor.Server)` on your `BlazorModule`
2. Chnage the base class of `AccountController` to `AbpAccountImpersonationChallengeAccountController`
2. Change the base class of `AccountController` to `AbpAccountImpersonationChallengeAccountController`
```cs
public class AccountController : AbpAccountImpersonationChallengeAccountController
{

6
docs/en/modules/chat.md

@ -100,19 +100,19 @@ You can visit [Chat module package list page](https://abp.io/packages?moduleName
## User interface
#### Manage chat feature
### Manage chat feature
Chat module defines the chat feature, you need to enable the chat feature to use chat.
![chat-feature](../images/chat-feature.png)
#### Chat page
### Chat page
This is the page that users send messages to each other.
![chat-page](../images/chat-page.png)
#### Chat icon on navigation bar
### Chat icon on navigation bar
An icon that shows unread message count of the user and leads to chat page when clicked is added to navigation menu.

26
docs/en/modules/cms-kit/marked-items.md

@ -58,6 +58,32 @@ The marking system provides a toggle widget to allow users to add/remove the mar
* `entityId` should be the unique id of the product, in this example. If you have a Product entity, you can use its Id here.
* `needsConfirmation` An optional parameter to let the user confirm when removing the mark.
### Filtering on Marked Items
Users can filter their marked items to easily find their favorites. Here's how to utilize the `GetEntityIdsFilteredByUserAsync` method to filter the user's marked items within your repository queries:
```csharp
List<string> entityIdFilters = null;
if (userId.HasValue)
{
entityIdFilters = await UserMarkedItemRepository.GetEntityIdsFilteredByUserAsync(
userId.Value,
entityType,
cancellationToken: cancellationToken
);
}
var queryable = (await GetDbSetAsync())
.WhereIf(entityIdFilters != null, x => entityIdFilters.Contains(x.Id.ToString()));
// Additional query logic...
```
- `GetEntityIdsFilteredByUserAsync`: Retrieves a list of entity IDs marked by the user for the given entity type.
- `userId`: The ID of the user performing the filtering.
- `entityType`: The type of entity being filtered (e.g., "product").
- `entityIdFilters`: A list of marked entity IDs that will be used to filter the items in the database.
# Internals
## Domain Layer

12
docs/en/modules/gdpr.md

@ -236,9 +236,17 @@ This [Event Transfer Object](../framework/infrastructure/event-bus/distributed#e
Cookie Consent can be used to inform the users of the application, before saving any specific data about the users.
This feature is enabled by default for the [Application](../solution-templates/layered-web-application) and [Application Single Layer](../solution-templates/single-layer-web-application) Startup Templates.
This feature is enabled by default for the [Application](../solution-templates/layered-web-application) and [Application Single Layer](../solution-templates/single-layer-web-application) Startup Templates. You can easily enable/disable showing Cookie Consent by configuring the `AbpCookieConsentOptions`
> You can easily enable/disable to show the Cookie Consent by configuring the `AbpCookieConsentOptions`, which explained above.
If you want to override the texts in the Cookie Consent component, you just need to define the following localization keys in your localization resource files and change text as you wish:
```json
"ThisWebsiteUsesCookie": "This website uses cookies to ensure you get the best experience on the website.",
"CookieConsentAgreePolicies": "If you continue to browse, then you agree to our {0} and {1}.",
"CookieConsentAgreePolicy": "If you continue to browse, then you agree to our {0}.",
```
> Refer to the [Localization documentation](../framework/fundamentals/localization.md) for more info about defining localization resources and overriding existing localization entries that comes from pre-built modules.
### Configuring the Cookie Consent

2
docs/en/modules/openiddict-pro.md

@ -333,7 +333,7 @@ LogoutController -> connect/logout
UserInfoController -> connect/userinfo
```
#### AbpOpenIddictAspNetCoreOptions
### AbpOpenIddictAspNetCoreOptions
`AbpOpenIddictAspNetCoreOptions` can be configured in the `PreConfigureServices` method of your OpenIddict [module](../framework/architecture/modularity/basics.md).

2
docs/en/modules/openiddict.md

@ -516,7 +516,7 @@ In the module's `app` directory there are six projects(including `angular`)
* `OpenIddict.Demo.Client.BlazorWASM:` ASP NET Core Blazor application using `OidcAuthentication` for authentication.
* `angular`: An angular application that integrates the abp ng modules and uses oauth for authentication.
#### How to run?
### How to run?
Confirm the connection string of `appsettings.json` in the `OpenIddict.Demo.Server` project. Running the project will automatically create the database and initialize the data.
After running the `OpenIddict.Demo.API` project, then you can run the rest of the projects to test.

2
docs/en/modules/tenant-management.md

@ -6,7 +6,7 @@
> Please **refer to the [Multi-Tenancy](../framework/architecture/multi-tenancy) documentation** to understand the multi-tenancy system of the ABP. This document focuses on the Tenant Management module.
### About the ABP SaaS Module
## About the ABP SaaS Module
The [SaaS Module](https://abp.io/modules/Volo.Saas) is an alternative implementation of this module with more features and possibilities. It is distributed as a part of the [ABP](https://abp.io/) subscription.

24
docs/en/release-info/migration-guides/abp-8-3.md

@ -49,10 +49,32 @@ However, notice this package is used by the `@abp/aspnetcore.mvc.ui.theme.shared
See the PR for more info: https://github.com/abpframework/abp/pull/19340
### `ApplyAbpConcepts` to Entities Whose Navigation Properties Changed
In this version, we have started updating entities' `EntityVersion`, `ModificationAuditProperties`, and `ConcurrencyStamp` properties whenever their navigation property changes. Normally, this should not affect your code, however, you may need to fix your tests or codebase for this change. Please see [#20012](https://github.com/abpframework/abp/pull/20012#issuecomment-2438383059) for more information.
### Angular UI
We wish to formally inform you that ABP version 8.3 has been upgraded to incorporate Angular version 18. Consequently, we recommend migrating your application to [Angular v18](https://angular.dev/update-guide) to ensure compatibility.
#### Tenant impersonation & User impersonation
Add the `impersonation: { userImpersonation: true, tenantImpersonation: true}` object to the `oAuthConfig` of the environment if it does not exit.
```
export const environment = {
//Other props..
oAuthConfig: {
//Other props..
impersonation: {
userImpersonation: true,
tenantImpersonation: true,
},
},
```
See https://abp.io/docs/latest/modules/account/impersonation#angular
## PRO
> Please check the **Open-Source (Framework)** section before reading this section. The listed topics might affect your application and you might need to take care of them.
@ -65,4 +87,4 @@ ABP provides a [URL Forwarding System](../../modules/cms-kit-pro/url-forwarding.
Since a new property has been added to the `CmsShortenedUrl` entity, you should create a new migration and apply it to your database.
> After creating a new migration and applying it to your database, typically you don't need to make any changes, however, if you have overridden a page/method or class related to the URL Forwarding System, you might need to update it accordingly. For this purpose, you can get the source code of the [CMS Kit Module's](../../modules/cms-kit-pro/index.md) and update the related parts in your application.
> After creating a new migration and applying it to your database, typically you don't need to make any changes, however, if you have overridden a page/method or class related to the URL Forwarding System, you might need to update it accordingly. For this purpose, you can get the source code of the [CMS Kit Module's](../../modules/cms-kit-pro/index.md) and update the related parts in your application.

100
docs/en/release-info/migration-guides/abp-9-0.md

@ -0,0 +1,100 @@
# ABP Version 9.0 Migration Guide
This document is a guide for upgrading ABP v8.x solutions to ABP v9.0. There are some changes in this version that may affect your applications, please read it carefully and apply the necessary changes to your application.
> ABP upgraded to .NET 9.0, so you need to move your solutions to .NET 9.0 if you want to use the ABP 9.0. You can check the [Migrate from ASP.NET Core 8.0 to 9.0](https://learn.microsoft.com/en-us/aspnet/core/migration/80-90) documentation.
## Open-Source (Framework)
### Upgraded to .NET 9.0
We've upgraded ABP to .NET 9.0, so you need to move your solutions to .NET 9.0 if you want to use ABP 9.0. You can check Microsoft’s [Migrate from ASP.NET Core 8.0 to 9.0](https://learn.microsoft.com/en-us/aspnet/core/migration/80-90) documentation, to see how to update an existing ASP.NET Core 8.0 project to ASP.NET Core 9.0.
After updating your solution to .NET 9.0, you should apply the following steps:
* Change the `app.UseStaticFiles()` to `app.MapAbpStaticAssets()` in the module classes of your host applications.
* Some JavaScript/CSS/Images files exist in the Virtual File System, but ASP NET Core 9's `MapStaticAssets` can't handle them. This is why we created the **MapAbpStaticAssets**.
* Upgrade the Microsoft packages (also other packages) for .NET 9.0. You can check the [Directory.Packages.props](https://github.com/abpframework/abp/blob/rel-9.0/Directory.Packages.props) file for package versions and update the necessary ones.
### Made the IdentitySession Entity Extensible & Updated the MaxIpAddressesLength
In this version, we made the `IdentitySession` entity extensible and as a result of that, you should be aware of the changes explained below:
* `IdentitySession` entity inherits from **AggregateRoot** instead of **BasicAggregateRoot**. Here is the PR for the related change: [#20771](https://github.com/abpframework/abp/pull/20771)
* `IdentitySession` entity's **MaxIpAddress** property now allows up to 2048 characters. You can check the related PR, [here](https://github.com/abpframework/abp/pull/20819).
You should create a new migration and apply it to your database for the changes explained above.
### Removed Auditing Properties From the `OpenIddictAuthorization` and `OpenIddictToken` Entities
In this version, we removed the auditing properties from the `OpenIddictAuthorization` and `OpenIddictToken` entities. Now, these entities are inherited from `AggregateRoot` instead of `FullAuditedAggregateRoot`.
> See the PR, if you need further information: https://github.com/abpframework/abp/pull/20671
Since the auditing properties are removed, you should create a new migration and apply it to your database.
### Updated Method Signature of `AbpCrudPageBase`
The method signature of [framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs) has been changed as follows:
```diff
- IEnumerable<TableColumn> GetExtensionTableColumns(string moduleName, string entityType)
+ Task<List<TableColumn>> GetExtensionTableColumnsAsync(string moduleName, string entityType)
```
### Removed React Native Mobile Option From Open Source Templates
In this version, we removed the **React Native** mobile option from the open source templates due to maintaining reasons. We updated the related documents and the ABP CLI (both old & new CLI) for this change, and with v9.0, you will not be able to create a free template with react-native as the mobile option.
> **Note:** Pro templates still provide the **React Native** as the mobile option and we will continue supporting it.
If you want to access the open-source React-Native template, you can visit the **abp-archive** repository: https://github.com/abpframework/abp-archive
## PRO
> Please check the **Open-Source (Framework)** section before reading this section. The listed topics might affect your application and you might need to take care of them.
If you are a paid-license owner and using the ABP's paid version, then please follow the following sections to get informed about the breaking changes and apply the necessary ones:
### ABP Suite: Better Naming For Multiple Navigation Properties
> **Note:** As a developer, you don't need to make any changes in your solution regarding this change. We just wanted to highlight this change and let you know.
Prior to this version, when you defined multiple (same) navigation properties to same entity, then ABP Suite was renaming them with a duplicate number.
Consider the following scenario for an example: If you have a book with an author and coauthor, prior to this version ABP Suite was creating a DTO class as below:
```csharp
public class BookWithNavigationPropertiesDto
{
public BookDto Book { get; set; }
public AuthorDto Author { get; set; }
public AuthorDto Author1 { get; set; }
}
```
Notice, that since the book entity has two same navigation properties, ABP Suite renamed them with a duplicate number. In this version, ABP Suite will ask you to define a propertyName for the **navigation properties** and you'll be able to specify a meaningful name such as:
```csharp
public class BookWithNavigationPropertiesDto
{
public BookDto Book { get; set; }
public AuthorDto Author { get; set; }
//used the specified property name
public AuthorDto CoAuthor { get; set; }
}
```
### CMS Kit Pro: Feedback Feature Improvements
In this version, we revised the **CMS Kit's Feedback Feature** and as a result, we made the following changes:
* `CmsKitProSettingGroupViewComponent` doesn't inject any service anymore and the design of the component has been updated. (no need for a change in your code, if you did not override the component)
* `Default.cshtml` and `Default.js` files (under the **Pages/Public/Shared/Components/PageFeedbacks/** directory) have been updated. (no need for a change in your code, if you did not override the files)
* `FeedbackUserId` property has been added to the `PageFeedback` entity, and that means you should create a new migration and apply it to your database.
* `PageFeedbackManager.CreateAsync` method now expecting an additional parameter: ***Guid feedbackUserId***. (no need for a change in your code, if you did not override or use this file)
* `PageFeedbackPublicAppService` has been updated due to saving the feedback user id. (no need for a change in your code, if you did not override or use this file)

1
docs/en/release-info/migration-guides/index.md

@ -2,6 +2,7 @@
The following documents explain how to migrate your existing ABP applications. We write migration documents only if you need to take an action while upgrading your solution. Otherwise, you can easily upgrade your solution using the [abp update command](../upgrading.md).
- [8.x to 9.0](abp-9-0.md)
- [8.x to 8.3](abp-8-3.md)
- [8.1 to 8.2](abp-8-2.md)
- [8.0 to 8.1](abp-8-1.md)

13
docs/en/release-info/release-notes.md

@ -4,6 +4,19 @@ This document contains **brief release notes** for each release. Release notes o
> If you want to read the release notes for each ABP Studio release, check it out from [here](../studio/release-notes.md).
## 9.0 (2024-10-22)
> This version is currently in preview. The final release date is planned for November, 2024.
See the detailed **[blog post / announcement](https://abp.io/blog/announcing-abp-9-0-release-candidate)** for the v9.0 release.
* Upgraded to .NET 9.0
* Introducing the `Extension Property Policy`
* Google Cloud Storage BLOB Provider
* Removed React Native mobile option from free templates
* ABP Suite: Better naming for multiple navigation properties to the same entity
* CMS Kit Pro: Feedback feature improvements
## 8.3 (2024-09-05)
See the detailed **[blog post / announcement](https://abp.io/blog/announcing-abp-8-3-stable-release)** for the v8.3 release.

27
docs/en/release-info/road-map.md

@ -4,43 +4,39 @@ This document provides a road map, release schedule, and planned features for th
## Next Versions
### v9.0
### v9.1
The next version will be 9.0 and planned to release the stable 9.0 version in November 2024. We will be mostly working on the following topics:
The next version will be 9.1 and planned to release the stable 9.1 version in January 2025. We will be mostly working on the following topics:
* Framework
* Upgrading to .NET 9.0
* Google Cloud Storage BLOB Provider
* Better handling localization resources in a microservice scenario
* Lazy expandable feature for documentation
* Unify the bundling system of Blazor and MVC
* SSR support for the Angular UI
* Upgrading 3rd-party dependencies
* ABP Suite
* Multiple navigation properties to the same target entity
* Define navigation properties without target string property dependency
* Improvements one-to-many scenarios
* Access to default code generation templates for customized templates
* File Upload Modal enhancements
* ABP Studio
* Blazor WebApp UI option for the new startup templates
* Execution order (dependency management) for Solution Runner
* Automate more details on new service creation for a microservice solution
* Support multiple concurrent Kubernetes deployment/integration scenarios
* Show the README file when you create a new solution or open an existing solution
* Improve ABP Suite code-generation possibilities for microservice solutions
* Improve the module installation experience
* Improve the module installation experience / installation guides
* Auto-install 3rd-party dependencies
* Better handle long log files
* Allow to directly create new solutions with ABP's RC (Release Candidate) versions
* Support Intel processors for Mac computers, support ARM chipset for Windows and support Linux OS
* Improve client proxy generation experience
* Modular Monolith Application Startup Template
* Application modules
* Account module: Support mixed social/local login scenarios
* Idle session warning
* UI/UX improvements on existing application modules
* New tutorials
* Modular monolith development
* Microservice development
## Backlog Items
@ -83,7 +79,6 @@ Here, are some of the important planned features for next ABP Studio versions:
* Theme builder for the LeptonX theme
* Analyze user solutions to explore entities, domain services, application services, pages and other fundamental objects.
* Add status bar to the built-in browser to easily see errors
* Swagger authentication support for the built-in browser
* Show related requests/events (traces) together in the solution runner panel
* Integrate common tool dashboards into ABP Studio (such a Garana, Redis, RabbitMQ, Kibana, etc)
@ -94,8 +89,8 @@ Here, are some of the important planned features for next ABP Studio versions:
* Downloading samples in ABP studio
* Built-in ABP documentation experience
* Auto-execute terminal commands in markdown files
* Compare changed on the startup templates when a new ABP version is published
* Remove unused projects while downloading source code of an existing module
* Compare changes on the startup templates when a new ABP version is published
* Remove unused projects while downloading the source code of an existing module
* Testing/hosting applications for module templates
* Easily explore all module and package dependencies of a large solution
* Built-in deployment options
@ -106,7 +101,7 @@ Here, are some of the important planned features for next ABP Studio versions:
[ABP Suite](../suite/index.md) is a GUI application that is mainly used to generate CRUD style pages in your application. You define your entity and it can generate all the code from the database layer to the UI layer. The generated code is clean and a perfect starting point to implement your custom requirements on top of it.
Here, are some of the important planned features for next ABP Suite versions:
Here, are some of the important planned features for the next ABP Suite versions:
* Handle image properties for entities
* Allow to define extra properties for DTOs those are not a part of the entity

22
docs/en/samples/index.md

@ -1,22 +1,34 @@
# Sample Applications
# ABP Samples
Here, a list of official samples built with ABP.
## Event Hub
A reference application built with ABP. It implements the Domain Driven Design with multiple application layers.
* [Live demo](https://www.openeventhub.com/)
* [Source code](https://github.com/abpframework/eventhub)
## eShopOnAbp
Reference microservice solution built with ABP and .NET.
* [Live demo](https://www.eshoponabp.com/)
* [Source code](https://github.com/abpframework/eShopOnAbp)
## Event Hub
## CMS Kit Demo
A reference application built with ABP. It implements the Domain Driven Design with multiple application layers.
A minimal example website built with the [CMS Kit module](../modules/cms-kit/index.md).
* [Source code](https://github.com/abpframework/eventhub)
* [Live demo](https://cms-kit-demo.abpdemo.com/)
* [Source code](https://github.com/abpframework/cms-kit-demo)
## Easy CRM
A middle-size CRM application built with ABP. [Click here](easy-crm.md) to see the details.
A middle-size CRM application built with ABP.
* [Live demo](http://easycrm.abp.io/)
* [Click here](easy-crm.md) to see the details and download the source code.
## Book Store

36
docs/en/solution-templates/layered-web-application/deployment/azure-deployment/azure-deployment.md

@ -0,0 +1,36 @@
# Azure Deployment using Application Service
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
````
> This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. For other options, please change the preference on top of this document.
## Prerequisites
- An active Azure account. If you don't have one, you can sign up for a [free account](https://azure.microsoft.com/en-us/free/)
- Your ABP **{{ UI_Value }}** project must be ready at a GitHub repository because we will use GitHub Actions to deploy the ABP application to the Azure Web App Service.
- **{{ DB_Value }}** database must be ready to use with your project. If you don't have a database, you can create a new Azure SQL database or Cosmos DB by following the instructions below:
- [Create a new Azure SQL Database](https://docs.microsoft.com/en-us/azure/azure-sql/database/single-database-create-quickstart?tabs=azure-portal)
- [Create a new Azure Cosmos DB](https://docs.microsoft.com/en-us/azure/cosmos-db/create-cosmosdb-resources-portal)
### Description of the process in three steps:
1. [Creating an Azure Web App Service Environment ](step1-create-azure-resources)
2. [Customizing the Configuration of Your ABP Application](step2-configuration-application)
3. [Deploying Your Application to Azure Web App Service](step3-deployment-github-action)
## What's next?
- [Creating an Azure Web App Service Environment](step1-create-azure-resources)

174
docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step1-create-azure-resources.md

@ -0,0 +1,174 @@
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
````
## Step 1: Creating an Azure Web App Service Environment
To create a new Azure Web App Service, choose one of the following options:
- [Create a new Azure Web App Service using the Azure Portal](#create-a-new-azure-web-app-service-using-the-azure-portal) (Recommended)
- [Create a new Azure Web App Service using the Terraform Template](terraform-web-app-service.md) (If you have experience with Terraform)
{{ if UI == "MVC" && Tiered == "No" }}
### Create a new Azure Web App service using the Azure Portal
1. Log in to the [Azure Portal](https://portal.azure.com/).
2. Click the **Create a resource** button.
3. Search for **Web App** and select **Web App** from the results.
![Create a resource](../../../../images/azure-deploy-create-a-resource.png)
4. Click the **Create** button.
5. Fill in the required fields and click the **Review + create** button.
6. Click the **Create** button.
![Create Web App](../../../../images/azure-deploy-create-web-app-2.png)
7. Wait for the deployment to complete.
![Create Web App](../../../../images/azure-deploy-create-web-app-3.png)
{{else}}
{{ if UI == "BlazorServer" || UI == "MVC" }}
### Create a new Azure Web App service using the Azure Portal
1. Log in to the [Azure Portal](https://portal.azure.com/).
2. Click the **Create a resource** button.
3. Search for **Web App** and select **Web App** from the results.
![Create a resource](../../../../images/azure-deploy-create-a-resource.png)
4. Click the **Create** button.
5. Fill in the required fields and click the **Review + create** button.
6. Click the **Create** button.
![Create Web App](../../../../images/azure-deploy-create-web-app-2.png)
7. Wait for the deployment to complete.
![Create Web App](../../../../images/azure-deploy-create-web-app-3.png)
{{ else if UI == 'NG' }}
### Create a new Azure Static Web App for Angular using the Azure Portal
1. Log in to the [Azure Portal](https://portal.azure.com/).
2. Click the **Create a resource** button.
3. Search for **Static Web App** and select **Static Web App** from the results.
![Create a resource angular](../../../../images/azure-deploy-create-a-resource-angular.png)
4. Click the **Create** button.
5. Fill in the required fields and click the **Review + create** button.
6. Click the **Create** button.
![Create Web App](../../../../images/azure-deploy-create-web-app-4.png)
7. Wait for the deployment to complete.
![Create Web App](../../../../images/azure-deploy-create-web-app-5.png)
{{else}}
### Create a new Azure Static Web App for Blazor using the Azure Portal
1. Log in to the [Azure Portal](https://portal.azure.com/).
2. Click the **Create a resource** button.
3. Search for **Static Web App** and select **Static Web App** from the results.
![Create a resource blazor](../../../../images/azure-deploy-create-a-resource-angular.png)
4. Click the **Create** button.
5. Fill in the required fields and click the **Review + create** button.
6. Click the **Create** button.
![Create Web App](../../../../images/azure-deploy-create-web-app-7.png)
7. Wait for the deployment to complete.
![Create Web App](../../../../images/azure-deploy-create-web-app-8.png)
{{end}}
### Create a new Azure Web App Service for API application
1. You can create a new Azure Web App Service for an API application in the same resource group.
2. Click the **Create** button on the top of the resource group page.
3. Search for **Web App** and select **Web App** from the results.
![Create a resource](../../../../images/azure-deploy-create-a-resource.png)
4. Click the **Create** button.
5. Fill in the required fields and click the **Review + create** button.
6. Click the **Create** button.
![Create Web App](../../../../images/azure-deploy-create-web-app-6.png)
7. Wait for the deployment to complete.
![Create Web App](../../../../images/azure-deploy-create-web-app-3.png)
{{ if Tiered == "Yes" && (UI == "MVC" || UI == "BlazorServer")}}
### Create a new Azure Web App Service for AuthServer application
Similar to the API application, you can create a new Azure Web App Service for an AuthServer application in the same resource group.
Same as above, but you only need to modify the name of the web app service to **authserver-yourapp** in step 5.
### Create Azure Cache for Redis
1. Click the **Create** button on the top of the resource group page.
2. Search for **Redis Cache** and select **Redis Cache** from the results.
![Create a resource](../../../../images/azure-deploy-create-redis.png)
3. Click the **Create** button.
4. Fill in the required fields and click the **Review + create** button.
5. Click the **Create** button.
![Create Redis](../../../../images/azure-deploy-create-redis-2.png)
6. Wait for the deployment to complete.
![Create Redis](../../../../images/azure-deploy-create-redis-3.png)
{{ end }}
{{ end }}
## What's next?
- [Customizing the Azure Web App Service](step2-configuration-application.md)

231
docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step2-configuration-application.md

@ -0,0 +1,231 @@
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
````
## Step 2: Customizing the Configuration of the ABP Application
- To customize the configuration of your ABP application, modify the `ConnectionString` values in every location throughout your project. The `ConnectionString` values are stored in the `appsettings.json` files.
This includes the following files:
{{ if UI == "MVC" && Tiered == "No" }}
**./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.Web/appsettings.json**
{{else}}
**./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json**
{{end}}
{{if Tiered == "Yes"}}
**./src/yourapp.AuthServer/appsettings.json**
{{end}}
```json
"ConnectionStrings": {
"Default": "Server=tcp:yourserver.database.windows.net,1433;Initial Catalog=yourdatabase;Persist Security Info=False;User ID=yourusername;Password=yourpassword;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
}
```
{{ if UI == "MVC" }}
{{if Tiered == "No"}}
- Modify the **yourapp.Web** URL in every location throughout your project, especially within the **./src/yourapp.Web/appsettings.json** and **./src/yourapp.DbMigrator/appsettings.json** files, to match your Azure Web App Service URL.
```json
"App": {
"SelfUrl": "https://yourapp.azurewebsites.net"
}
```
{{else}}
- Modify the **yourapp.Web** URL in every location throughout your project.
This includes the following files:
**./src/yourapp.Web/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** , **./src/yourapp.HttpApi.Host/appsettings.json** and **./src/yourapp.AuthServer/appsettings.json**
```json
"App": {
"SelfUrl": "https://yourapp.azurewebsites.net"
}
```
- Modify the **yourapp.ApiHost** URL in every location throughout your project.
This includes the following files:
**./src/yourapp.HttpApi.Host/appsettings.json** , **./src/yourapp.Web/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.AuthServer/appsettings.json**
```json
"App": {
"SelfUrl": "https://yourapp-apihost.azurewebsites.net"
}
```
- Modify the **yourapp.AuthServer** URL in every location throughout your project.
This includes the following files:
**./src/yourapp.Web/appsettings.json** , **./src/yourapp.AuthServer/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json**
```json
"App": {
"SelfUrl": "https://yourapp-authserver.azurewebsites.net"
}
```
- Modify the **Redis__Configuration** URL in every location throughout your project.
This includes the following files:
**./src/yourapp.Web/appsettings.json** , **./src/yourapp.AuthServer/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json**
```json
"Redis": {
"Configuration": "redis-abpdemo.redis.cache.windows.net:6380,password={yourpassword},ssl=true,abortConnect=False"
},
```
{{end}}
{{ else if UI == "NG" }}
- Modify the **`localhost:4200`** in every location throughout your project.
This includes the following files:
**./angular/src/environments/environment.prod.ts** , **./aspnet-core/src/yourapp.DbMigrator/appsettings.json** and **./aspnet-core/src/yourapp.HttpApi.Host/appsettings.json**
```typescript
application: {
baseUrl: 'https://yourapp.azurestaticapps.net'
}
```
- Modify the **yourapp.HttpApi.Host** URL in every location throughout your project.
This includes the following files:
**./angular/src/environments/environment.prod.ts** , **./aspnet-core/src/yourapp.DbMigrator/appsettings.json** and **./aspnet-core/src/yourapp.HttpApi.Host/appsettings.json**
```json
"App": {
"SelfUrl": "https://yourApiHost.azurewebsites.net"
}
```
{{ else if UI == "Blazor" }}
- Modify the **yourapp.Blazor** URL in every location throughout your project.
This includes the following files:
**./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json**
```json
"App": {
"SelfUrl": "https://yourapp.azurewebsites.net"
}
```
- Modify the **yourapp.HttpApi.Host** URL in every location throughout your project.
This includes the following files:
**./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json**
```json
"App": {
"SelfUrl": "https://yourApiHost.azurewebsites.net"
}
```
{{ else }}
{{if Tiered == "No"}}
- Modify the **yourapp.Web** URL in every location throughout your project.
This includes the following files:
**./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json**
```json
"App": {
"SelfUrl": "https://yourapp.azurewebsites.net"
}
```
- Modify the **yourapp.ApiHost** URL in every location throughout your project.
This includes the following files:
**./src/yourapp.HttpApi.Host/appsettings.json** , **./src/yourapp.Blazor/appsettings.json** and **./src/yourapp.DbMigrator/appsettings.json**
```json
"App": {
"SelfUrl": "https://yourapp-apihost.azurewebsites.net"
}
```
{{else}}
- Modify the **yourapp.Web** URL in every location throughout your project.
This includes the following files:
**./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** , **./src/yourapp.HttpApi.Host/appsettings.json** and **./src/yourapp.AuthServer/appsettings.json**
```json
"App": {
"SelfUrl": "https://yourapp.azurewebsites.net"
}
```
- Modify the **yourapp.ApiHost** URL in every location throughout your project.
This includes the following files:
**./src/yourapp.HttpApi.Host/appsettings.json** , **./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.AuthServer/appsettings.json**
```json
"App": {
"SelfUrl": "https://yourapp-apihost.azurewebsites.net"
}
```
- Modify the **yourapp.AuthServer** URL in every location throughout your project.
This includes the following files:
**./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.AuthServer/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json**
```json
"App": {
"SelfUrl": "https://yourapp-authserver.azurewebsites.net"
}
```
- Modify the **Redis__Configuration** URL in every location throughout your project.
This includes the following files:
**./src/yourapp.Blazor/appsettings.json** , **./src/yourapp.AuthServer/appsettings.json** , **./src/yourapp.DbMigrator/appsettings.json** and **./src/yourapp.HttpApi.Host/appsettings.json**
```json
"Redis": {
"Configuration": "redis-abpdemo.redis.cache.windows.net:6380,password={yourpassword},ssl=true,abortConnect=False"
},
```
{{end}}
{{end}}
## What's next?
- [Deploying Your ABP Application to Azure](step3-deployment-github-action.md)

735
docs/en/solution-templates/layered-web-application/deployment/azure-deployment/step3-deployment-github-action.md

@ -0,0 +1,735 @@
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
````
## Step 3: Deploying the ABP Application to Azure Web App Service
### Deploying the ABP Application to Azure Web App Service using GitHub Actions
1. Create a new GitHub repository for your project if you don't have one.
2. Push your project to the new GitHub repository.
3. Navigate to the **Actions** tab of your GitHub repository.
4. Click the **set up a workflow yourself** button.
![Set up this workflow](../../../../images/azure-deploy-set-up-this-workflow.png)
5. Copy this content to the opened file and commit it.
{{if UI == "NG"}}
{%{
```yaml
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions
name: Build and deploy ASP.Net Core with Angular app to Azure Web App
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build-backend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'
include-prerelease: true
- name: Install ABP CLI
run: |
dotnet tool install -g Volo.Abp.Cli
abp install-libs
shell: bash
- name: Build with dotnet
run: dotnet build --configuration Release
working-directory: ./aspnet-core
- name: Run migrations
run: dotnet run -- "${{ secrets.CONNECTION_STRING }}"
working-directory: ./aspnet-core/src/Demo.AzureAppsAngular.DbMigrator # Replace with your project name
- name: dotnet publish apihost
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost
working-directory: ./aspnet-core/src/Demo.AzureAppsAngular.HttpApi.Host # Replace with your project name
- name: Generate authserver.pfx
run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/apihost/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password
- name: Upload artifact for apihost
uses: actions/upload-artifact@v4
with:
name: .net-apihost
path: ${{env.DOTNET_ROOT}}/apihost
deploy-backend:
runs-on: ubuntu-latest
needs: build-backend
environment:
name: 'Production'
url: ${{ steps.deploy-to-webapp-1.outputs.webapp-url }}
steps:
- name: Download artifact from apihost
uses: actions/download-artifact@v1
with:
name: .net-apihost
path: ./apihost
- name: Deploy apihost
id: deploy-to-webapp-1
uses: azure/webapps-deploy@v3
with:
app-name: 'apihost-angular' # Replace with your app name
slot-name: 'Production'
publish-profile: ${{ secrets.apihostangularPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings
path: ./apihost
build-deploy-frontend:
runs-on: ubuntu-latest
needs: deploy-backend
name: Build and Deploy Angular App
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_PROUD_STONE }} # Set your Azure Static Web App API token as a secret in your repository settings
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for GitHub integrations (eg: PR comments)
action: "upload"
app_location: "angular" # App source code path
api_location: "" # Api source code path - optional
output_location: "dist/AzureAppsAngular" # Built app content directory - optional
```
}%}
{{ else if UI == "Blazor" }}
{%{
```yaml
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions
name: Build and deploy ASP.Net Core with Blazor to Azure Web App
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build-apihost:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'
include-prerelease: true
- name: Install ABP CLI
run: |
dotnet tool install -g Volo.Abp.Cli
abp install-libs
shell: bash
- name: Build with dotnet
run: dotnet build --configuration Release
- name: Run migrations
run: dotnet run -- "${{ secrets.CONNECTION_STRING }}"
working-directory: ./src/demo.BlazorNonTierEfCore.DbMigrator # Replace with your project name
- name: dotnet publish apihost
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost
working-directory: ./src/demo.BlazorNonTierEfCore.HttpApi.Host # Replace with your project name
- name: Generate authserver.pfx
run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/apihost/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password
- name: Upload artifact for apihost
uses: actions/upload-artifact@v4
with:
name: .net-apihost
path: ${{env.DOTNET_ROOT}}/apihost
deploy-apihost:
runs-on: ubuntu-latest
needs: build-apihost
environment:
name: 'Production'
steps:
- name: Download artifact from apihost
uses: actions/download-artifact@v4
with:
name: .net-apihost
path: ./apihost
- name: Deploy apihost
id: deploy-to-webapp-2
uses: azure/webapps-deploy@v3
with:
app-name: 'apihost-blazor' # Replace with your app name
slot-name: 'Production'
publish-profile: ${{ secrets.apihostblazorPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings
build-deploy-frontend:
runs-on: ubuntu-latest
needs: deploy-apihost
name: Build and Deploy Job
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS }} # Set your Azure Static Web App API token as a secret in your repository settings
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for GitHub integrations (eg: PR comments)
action: "upload"
app_location: "src/demo.BlazorNonTierEfCore.Blazor" # App source code path
api_location: "" # Api source code path - optional
output_location: "wwwroot" # Built app content directory - optional
```
}%}
{{ else if UI == "BlazorServer" }}
{{ if Tiered == "No" }}
{%{
```yaml
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions
name: Build and deploy ASP.Net Core with BlazorServer to Azure Web App
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'
include-prerelease: true
- name: Install ABP CLI
run: |
dotnet tool install -g Volo.Abp.Cli
abp install-libs
shell: bash
- name: Build with dotnet
run: dotnet build --configuration Release
- name: Run migrations
run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" # Set your connection string as a secret in your repository settings
working-directory: ./src/blazorservertierdemo.DbMigrator # Replace with your project name
- name: dotnet publish apihost
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost
working-directory: ./src/blazorservertierdemo.HttpApi.Host # Replace with your project name
- name: Generate authserver.pfx
run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/apihost/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password
- name: dotnet publish webapp
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/webapp
working-directory: ./src/blazorservertierdemo.Blazor # Replace with your project name
- name: Upload artifact for apihost
uses: actions/upload-artifact@v4
with:
name: .net-apihost
path: ${{env.DOTNET_ROOT}}/apihost
- name: Upload artifact for webapp
uses: actions/upload-artifact@v4
with:
name: .net-webapp
path: ${{env.DOTNET_ROOT}}/webapp
deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: 'Production'
url: ${{ steps.deploy-to-webapp-3.outputs.webapp-url }}
- name: Download artifact from apihost
uses: actions/download-artifact@v4
with:
name: .net-apihost
path: ./apihost
- name: Deploy apihost
id: deploy-to-webapp-2
uses: azure/webapps-deploy@v3
with:
app-name: 'apihost-blazorserver' # Replace with your app name
slot-name: 'Production'
publish-profile: ${{ secrets.apihostblazorserverPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings
package: ./apihost
- name: Download artifact from webapp
uses: actions/download-artifact@v4
with:
name: .net-webapp
path: ./webapp
- name: Deploy webapp
id: deploy-to-webapp-3
uses: azure/webapps-deploy@v3
with:
app-name: 'webapp-blazorserver' # Replace with your app name
slot-name: 'Production'
publish-profile: ${{ secrets.webappblazorserverPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings
package: ./webapp
```
}%}
{{ else }}
{%{
```yaml
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions
name: Build and deploy ASP.Net Core with BlazorServer to Azure Web App
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'
include-prerelease: true
- name: Install ABP CLI
run: |
dotnet tool install -g Volo.Abp.Cli
abp install-libs
shell: bash
- name: Build with dotnet
run: dotnet build --configuration Release
- name: Run migrations
run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" # Set your connection string as a secret in your repository settings
working-directory: ./src/blazorservertierdemo.DbMigrator # Replace with your project name
- name: dotnet publish authserver
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/authserver
working-directory: ./src/blazorservertierdemo.AuthServer # Replace with your project name
- name: Generate authserver.pfx
run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/authserver/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password
- name: dotnet publish apihost
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost
working-directory: ./src/blazorservertierdemo.HttpApi.Host # Replace with your project name
- name: dotnet publish webapp
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/webapp
working-directory: ./src/blazorservertierdemo.Blazor # Replace with your project name
- name: Upload artifact for authserver
uses: actions/upload-artifact@v4
with:
name: .net-authserver
path: ${{env.DOTNET_ROOT}}/authserver
- name: Upload artifact for apihost
uses: actions/upload-artifact@v4
with:
name: .net-apihost
path: ${{env.DOTNET_ROOT}}/apihost
- name: Upload artifact for webapp
uses: actions/upload-artifact@v4
with:
name: .net-webapp
path: ${{env.DOTNET_ROOT}}/webapp
deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: 'Production'
url: ${{ steps.deploy-to-webapp-3.outputs.webapp-url }}
steps:
- name: Download artifact from authserver
uses: actions/download-artifact@v4
with:
name: .net-authserver
path: ./authserver
- name: Deploy authserver
id: deploy-to-webapp
uses: azure/webapps-deploy@v3
with:
app-name: 'authserver-blazorserver' # Replace with your app name
slot-name: 'Production'
publish-profile: ${{ secrets.authserverblazorserverPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings
package: ./authserver
- name: Download artifact from apihost
uses: actions/download-artifact@v4
with:
name: .net-apihost
path: ./apihost
- name: Deploy apihost
id: deploy-to-webapp-2
uses: azure/webapps-deploy@v3
with:
app-name: 'apihost-blazorserver' # Replace with your app name
slot-name: 'Production'
publish-profile: ${{ secrets.apihostblazorserverPublishSettings }} # Set your Azure Web App to publish your profile as a secret in your repository settings
package: ./apihost
- name: Download artifact from webapp
uses: actions/download-artifact@v4
with:
name: .net-webapp
path: ./webapp
- name: Deploy webapp
id: deploy-to-webapp-3
uses: azure/webapps-deploy@v3
with:
app-name: 'webapp-blazorserver' # Replace with your app name
slot-name: 'Production'
publish-profile: ${{ secrets.webappblazorserverPublishSettings }} # Set your Azure Web App publish your profile as a secret in your repository settings
```
}%}
{{end}}
{{ else if UI == "MVC" }}
{{ if Tiered == "No" }}
{%{
```yaml
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions
name: Build and deploy ASP.Net Core with MVC to Azure Web App
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'
include-prerelease: true
- name: Install ABP CLI
run: |
dotnet tool install -g Volo.Abp.Cli
abp install-libs
shell: bash
- name: Build with dotnet
run: dotnet build --configuration Release
- name: Run migrations
run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" # Set your connection string as a secret in your repository settings
working-directory: ./src/yourapp.DbMigrator # Replace with your project name
- name: dotnet publish
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp
working-directory: ./src/yourapp.Web # Replace with your project name
- name: Generate authserver.pfx
run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/myapp/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password
- name: Upload artifact for deployment job
uses: actions/upload-artifact@v4
with:
name: .net-app
path: ${{env.DOTNET_ROOT}}/myapp
deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: 'Production'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
steps:
- name: Download artifact from build job
uses: actions/download-artifact@v4
with:
name: .net-app
- name: Deploy to Azure Web App
id: deploy-to-webapp
uses: azure/webapps-deploy@v3
with:
app-name: 'yourapp' # Replace with your azure web app name
slot-name: 'Production'
publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE }} # Set your Azure Web App publish your profile as a secret in your repository settings
package: .
```
}%}
{{ else }}
{%{
```yaml
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions
name: Build and deploy ASP.Net Core with MVC to Azure Web App
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'
include-prerelease: true
- name: Install ABP CLI
run: |
dotnet tool install -g Volo.Abp.Cli
abp install-libs
shell: bash
- name: Build with dotnet
run: dotnet build --configuration Release
- name: Run migrations
run: dotnet run -- "${{ secrets.CONNECTION_STRING }}" # Set your connection string as a secret in your repository settings
working-directory: ./src/mvctierdemo.DbMigrator # Replace with your project name
- name: dotnet publish authserver
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/authserver
working-directory: ./src/mvctierdemo.AuthServer # Replace with your project name
- name: Generate authserver.pfx
run: dotnet dev-certs https -v -ep ${{env.DOTNET_ROOT}}/authserver/authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED # Replace with your password
- name: dotnet publish apihost
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/apihost
working-directory: ./src/mvctierdemo.HttpApi.Host # Replace with your project name
- name: dotnet publish webapp
run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/webapp
working-directory: ./src/mvctierdemo.Web # Replace with your project name
- name: Upload artifact for authserver
uses: actions/upload-artifact@v4
with:
name: .net-authserver
path: ${{env.DOTNET_ROOT}}/authserver
- name: Upload artifact for apihost
uses: actions/upload-artifact@v4
with:
name: .net-apihost
path: ${{env.DOTNET_ROOT}}/apihost
- name: Upload artifact for webapp
uses: actions/upload-artifact@v4
with:
name: .net-webapp
path: ${{env.DOTNET_ROOT}}/webapp
deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: 'Production'
url: ${{ steps.deploy-to-webapp-3.outputs.webapp-url }}
steps:
- name: Download artifact from apihost
uses: actions/download-artifact@v4
with:
name: .net-apihost
path: ./apihost
- name: Deploy apihost
id: deploy-to-webapp-2
uses: azure/webapps-deploy@v3
with:
app-name: 'apihost-prodemo'
slot-name: 'Production'
publish-profile: ${{ secrets.apihostprodemoPublishSettings }} # Set your Azure Web App publish your profile as a secret in your repository settings
package: ./apihost
- name: Download artifact from authserver
uses: actions/download-artifact@v4
with:
name: .net-authserver
path: ./authserver
- name: Deploy authserver
id: deploy-to-webapp
uses: azure/webapps-deploy@v3
with:
app-name: 'authserver-prodemo'
slot-name: 'Production'
publish-profile: ${{ secrets.authserverprodemoPublishSettings }} # Set your Azure Web App publish your profile as a secret in your repository settings
package: ./authserver
- name: Download artifact from webapp
uses: actions/download-artifact@v4
with:
name: .net-webapp
path: ./webapp
- name: Deploy webapp
id: deploy-to-webapp-3
uses: azure/webapps-deploy@v3
with:
app-name: 'webapp-prodemo'
slot-name: 'Production'
publish-profile: ${{ secrets.webappprodemoPublishSettings }} # Set your Azure Web App publish your profile as a secret in your repository settings
package: ./webapp
```
}%}
{{end}}
{{end}}
7. Navigate to the **Settings** tab of your GitHub repository.
8. Click the **Secrets** button.
9. Click the **New repository secret** button.
![New repository secret](../../../../images/azure-deploy-new-repository-secret.png)
10. Add the following secrets:
- **CONNECTION_STRING**: The connection string of your database.
Example of Azure SQL connection string:
![Azure sql connection string](../../../../images/azure-deploy-connection-string.png)
- **AZUREAPPSERVICE_PUBLISHPROFILE**: The publish the profile of your Azure Web App Service. You can download it from the **Overview** tab of your Azure Web App Service.
![Publish profile](../../../../images/azure-deploy-publish-profile.png)
{{ if UI == "NG" || UI == "Blazor"}}
- **AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS**: The API token of your Azure Static Web App. You can get it from the **Overview** tab of your Azure Static Web App.
![API token](../../../../images/azure-deploy-api-token.png)
{{end}}
11. Navigate to the **Actions** tab of your GitHub repository.
12. Click the **Deploy to Azure Web App** workflow.
![Deploy to Azure Web App](../../../../images/azure-deploy-deploy-to-azure-web-app.png)
13. Click the **Run workflow** button.
![Run workflow](../../../../images/azure-deploy-run-workflow.png)
14. Navigate to the web app URL to see the deployed application.
![Azure Web App](../../../../images/azure-deploy-runtime-stack2.png)
> If deploying your application was unsuccessful, you can check the logs of the deployment by clicking the **Deploy to Azure Web App** workflow and then clicking the **deploy-to-webapp** job.
> If deployment is successful, but you get an error when you navigate to the web app url, you can check the logs of the web app by clicking the **Logs** button on the **Overview** tab of your Azure Web App Service.
> Finally, you have the CI/CD pipeline for your application. Every time you push your code to the main branch, your application will be deployed to Azure Web App Service automatically.
## What's next?
- [Docker Deployment using Docker Compose](../deployment-docker-compose.md)
- [IIS Deployment](../deployment-iis.md)

572
docs/en/solution-templates/layered-web-application/deployment/azure-deployment/terraform-web-app-service.md

@ -0,0 +1,572 @@
# Provisioning an Azure Web App using Terraform
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
````
In this tutorial, we'll walk through the steps to provision an Azure Web App using Terraform. Terraform is an open-source infrastructure as a code tool that allows you to define and manage your infrastructure in a declarative way.
## Prerequisites
Before you begin, you'll need the following:
- [Azure account](https://azure.microsoft.com/en-us/free/)
- [Terraform installed](https://developer.hashicorp.com/terraform/downloads) on your local machine
- [Azure CLI installed](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) on your local machine
## Creating a Service Principal for Terraform in Azure
When working with Terraform on Azure, you'll need a "Service Principal" for authentication. A "Service Principal" is an identity created to be used with applications, hosted services, and automated tools to access Azure resources.
[To create a service principal](https://learn.microsoft.com/en-us/azure/developer/terraform/authenticate-to-azure?tabs=bash#create-a-service-principal), run the following command in the Azure CLI:
1. Login to Azure CLI
Before you begin, make sure you are logged into your Azure account with the Azure CLI:
```bash
az login
```
2. Set your Subscription:
If you have multiple Azure subscriptions, specify the one you intend to use:
```bash
az account set --subscription="YOUR_SUBSCRIPTION_ID"
```
3. Create the Service Principal:
The following command will create a service principal. Replace YOUR_APP_NAME with a suitable name for your application:
```bash
az ad sp create-for-rbac --name "YOUR_APP_NAME" --role contributor --scopes /subscriptions/YOUR_SUBSCRIPTION_ID
```
> Replace `YOUR_SUBSCRIPTION_ID` with your subscription id.
The output of this command will provide the **appId**, **displayName**, **name**, **password**, and **tenant**. It's crucial to note these values, especially **appId (Client ID)** and **password (Client Secret)**, as you'll need them for Terraform authentication.
4. Specify the service principal credentials in environment variables
bash:
```bash
export ARM_SUBSCRIPTION_ID="<azure_subscription_id>"
export ARM_TENANT_ID="<azure_subscription_tenant_id>"
export ARM_CLIENT_ID="<service_principal_appid>"
export ARM_CLIENT_SECRET="<service_principal_password>"
```
To execute the ~/.bashrc script, run source ~/.bashrc (or its abbreviated equivalent . ~/.bashrc). You can also exit and reopen Cloud Shell for the script to run automatically.
Run the following bash command to verify the Azure environment variables:
```bash
. ~/.bashrc
```
powershell:
```powershell
$env:ARM_SUBSCRIPTION_ID="<azure_subscription_id>"
$env:ARM_TENANT_ID="<azure_subscription_tenant_id>"
$env:ARM_CLIENT_ID="<service_principal_appid>"
$env:ARM_CLIENT_SECRET="<service_principal_password>"
```
Run the following PowerShell command to verify the Azure environment variables:
```powershell
gci env:ARM_*
```
> Replace the values with your own.
## Creating a Terraform Configuration
1. Create a new directory for your Terraform configuration files.
2. Create a new file named `main.tf` in the directory and add the following code:
{{if UI == "NG"}}
```terraform
# Configure the Azure provider
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0.0"
}
}
required_version = ">= 0.14.9"
}
provider "azurerm" {
features {}
}
# Create the resource group
resource "azurerm_resource_group" "rg" {
name = "demo-angular-web-app-rg"
location = "westeurope"
}
# Create the Linux App Service Plan
resource "azurerm_service_plan" "appserviceplan" {
name = "demo-angular-web-app-plan"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
os_type = "Linux"
sku_name = "B3"
}
resource "azurerm_linux_web_app" "apihost" {
name = "apihost-angular"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_service_plan.appserviceplan.id
https_only = true
site_config {
application_stack {
dotnet_version = "6.0"
}
minimum_tls_version = "1.2"
}
}
resource "azurerm_static_site" "angularweb" {
name = "angularweb"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
```
{{ else if UI == "Blazor" }}
```terraform
# Configure the Azure provider
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0.0"
}
}
required_version = ">= 0.14.9"
}
provider "azurerm" {
features {}
}
# Create the resource group
resource "azurerm_resource_group" "rg" {
name = "blazor-app-nontier-rg"
location = "westeurope"
}
# Create the Linux App Service Plan
resource "azurerm_service_plan" "appserviceplan" {
name = "blazor-app-nontier-plan"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
os_type = "Linux"
sku_name = "B3"
}
# Create the web app, pass in the App Service Plan ID
resource "azurerm_linux_web_app" "apihost" {
name = "apihost-blazor"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_service_plan.appserviceplan.id
https_only = true
site_config {
application_stack {
dotnet_version = "6.0"
}
minimum_tls_version = "1.2"
}
}
resource "azurerm_static_site" "blazorweb" {
name = "blazorweb"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
```
{{ else if UI == "BlazorServer" }}
{{if Tiered == "No"}}
```terraform
# Configure the Azure provider
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0.0"
}
}
required_version = ">= 0.14.9"
}
provider "azurerm" {
features {}
}
# Create the resource group
resource "azurerm_resource_group" "rg" {
name = "blazorserver-app-nontier-rg"
location = "westeurope"
}
# Create the Linux App Service Plan
resource "azurerm_service_plan" "appserviceplan" {
name = "blazorserver-app-nontier-plan"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
os_type = "Linux"
sku_name = "B3"
}
# Create the web app, pass in the App Service Plan ID
resource "azurerm_linux_web_app" "authserver" {
name = "authserver-blazorserver"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_service_plan.appserviceplan.id
https_only = true
site_config {
application_stack {
dotnet_version = "6.0"
}
minimum_tls_version = "1.2"
}
}
resource "azurerm_linux_web_app" "apihost" {
name = "apihost-blazorserver"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_service_plan.appserviceplan.id
https_only = true
site_config {
application_stack {
dotnet_version = "6.0"
}
minimum_tls_version = "1.2"
}
}
resource "azurerm_linux_web_app" "webapp" {
name = "webapp-blazorserver"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_service_plan.appserviceplan.id
https_only = true
site_config {
application_stack {
dotnet_version = "6.0"
}
minimum_tls_version = "1.2"
}
}
```
{{ else }}
```terraform
# Configure the Azure provider
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0.0"
}
}
required_version = ">= 0.14.9"
}
provider "azurerm" {
features {}
}
# Create the resource group
resource "azurerm_resource_group" "rg" {
name = "blazorserver-app-tier-rg"
location = "westeurope"
}
# Create the Linux App Service Plan
resource "azurerm_service_plan" "appserviceplan" {
name = "blazorserver-app-tier-plan"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
os_type = "Linux"
sku_name = "B3"
}
# Create the web app, pass in the App Service Plan ID
resource "azurerm_linux_web_app" "authserver" {
name = "authserver-blazorserver"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_service_plan.appserviceplan.id
https_only = true
site_config {
application_stack {
dotnet_version = "6.0"
}
minimum_tls_version = "1.2"
}
app_settings = {
"Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string
}
}
resource "azurerm_linux_web_app" "apihost" {
name = "apihost-blazorserver"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_service_plan.appserviceplan.id
https_only = true
site_config {
application_stack {
dotnet_version = "6.0"
}
minimum_tls_version = "1.2"
}
app_settings = {
"Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string
}
}
resource "azurerm_linux_web_app" "webapp" {
name = "webapp-blazorserver"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_service_plan.appserviceplan.id
https_only = true
site_config {
application_stack {
dotnet_version = "6.0"
}
minimum_tls_version = "1.2"
}
app_settings = {
"Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string
}
}
resource "azurerm_redis_cache" "redis" {
name = "redis-blazorserver"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
capacity = 0
family = "C"
sku_name = "Basic"
enable_non_ssl_port = false
minimum_tls_version = "1.2"
redis_configuration {
maxmemory_reserved = 2
maxmemory_delta = 2
maxmemory_policy = "volatile-lru"
}
}
```
{{end}}
{{ else if UI == "MVC" }}
{{ if Tiered == "No" }}
```terraform
# Configure the Azure provider
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0.0"
}
}
required_version = ">= 0.14.9"
}
provider "azurerm" {
features {}
}
# Create the resource group
resource "azurerm_resource_group" "rg" {
name = "demo-abp-web-app"
location = "westeurope"
}
# Create the Linux App Service Plan
resource "azurerm_service_plan" "appserviceplan" {
name = "demo-abp-web-app-plan"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
os_type = "Linux"
sku_name = "B3"
}
# Create the web app, pass in the App Service Plan ID
resource "azurerm_linux_web_app" "webapp" {
name = "demo-abp-web-app"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_service_plan.appserviceplan.id
https_only = true
site_config {
application_stack {
dotnet_version = "6.0"
}
minimum_tls_version = "1.2"
}
}
output "webappurl" {
value = "${azurerm_linux_web_app.webapp.name}.azurewebsites.net"
}
```
{{ else }}
```terraform
# Configure the Azure provider
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0.0"
}
}
required_version = ">= 0.14.9"
}
provider "azurerm" {
features {}
}
# Create the resource group
resource "azurerm_resource_group" "rg" {
name = "demo-abp-web-app-tier-rg"
location = "westeurope"
}
# Create the Linux App Service Plan
resource "azurerm_service_plan" "appserviceplan" {
name = "demo-abp-web-app-tier-plan"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
os_type = "Linux"
sku_name = "B3"
}
# Create the web app, pass in the App Service Plan ID
resource "azurerm_linux_web_app" "authserver" {
name = "authserver-prodemo"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_service_plan.appserviceplan.id
https_only = true
site_config {
application_stack {
dotnet_version = "6.0"
}
minimum_tls_version = "1.2"
}
app_settings = {
"Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string
}
}
resource "azurerm_linux_web_app" "apihost" {
name = "apihost-prodemo"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_service_plan.appserviceplan.id
https_only = true
site_config {
application_stack {
dotnet_version = "6.0"
}
minimum_tls_version = "1.2"
}
app_settings = {
"Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string
}
}
resource "azurerm_linux_web_app" "webapp" {
name = "webapp-prodemo"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
service_plan_id = azurerm_service_plan.appserviceplan.id
https_only = true
site_config {
application_stack {
dotnet_version = "6.0"
}
minimum_tls_version = "1.2"
}
app_settings = {
"Redis__Configuration" = azurerm_redis_cache.redis.primary_connection_string
}
}
resource "azurerm_redis_cache" "redis" {
name = "redis-prodemo"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
capacity = 0
family = "C"
sku_name = "Basic"
enable_non_ssl_port = false
minimum_tls_version = "1.2"
redis_configuration {
maxmemory_reserved = 2
maxmemory_delta = 2
maxmemory_policy = "volatile-lru"
}
}
output "authserver" {
value = "${azurerm_linux_web_app.authserver.name}.azurewebsites.net"
}
output "apihost" {
value = "${azurerm_linux_web_app.apihost.name}.azurewebsites.net"
}
output "webapp" {
value = "${azurerm_linux_web_app.webapp.name}.azurewebsites.net"
}
output "redis_hostname" {
value = azurerm_redis_cache.redis.hostname
description = "The hostname for the Redis instance."
}
```
{{end}}
{{end}}
3. Run `terraform init` to initialize the directory.
4. Run `terraform plan` to see the execution plan.
5. Run `terraform apply` to apply the changes. Write `yes` when prompted to confirm the deployment.
6. Wait for the deployment to complete.
7. Navigate to the web app URL to see the deployed application.
> You can also see the web app URL in the output of the `terraform apply` command.
> You have to change the **dotnet version** of the runtime stack according to your application. For example, if you are using .NET 7, you should change `dotnet_version = "6.0"` to `dotnet_version = "7.0"`.
![Azure Web App](../../../images/azure-deploy-runtime-stack.png)
## Destroying the Terraform Configuration
1. Run `terraform destroy` to destroy the created resources.
2. Type `yes` when prompted to confirm the destruction.

1933
docs/en/solution-templates/layered-web-application/deployment/deployment-docker-compose.md

File diff suppressed because it is too large

292
docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md

@ -0,0 +1,292 @@
# IIS Deployment
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
````
> This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. For other options, please change the preference on top of this document.
## Prerequisites
- An IIS Server that is ready for deployment.
- Install the [hosting bundle](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/hosting-bundle).
- **{{ DB_Value }}** database must be ready to use with your project.
- If you want to publish in a local environment, this guide will use mkcert to create self-signed certificates. Follow the [installation guide](https://github.com/FiloSottile/mkcert#installation) to install mkcert.
{{ if Tiered == "Yes" }}
- A Redis instance prepared for caching.
{{end}}
## Generate an Authentication Certificate
If you're using OpenIddict, you need to generate an authentication certificate. You can execute this command in {{ if Tiered == "Yes" }}AuthServer{{ else if UI == "NG" || UI == "Blazor" }}HttpApi.Host{{ else if UI == "BlazorServer" }}Blazor{{ else }}Web{{ end }} folder.
````bash
dotnet dev-certs https -v -ep authserver.pfx -p 00000000-0000-0000-0000-000000000000
````
> `00000000-0000-0000-0000-000000000000` is the password of the certificate, you can change it to any password you want.
## Creating the Publish Files
You can execute this commands in your project root folder.
````bash
dotnet publish ./src/Volo.Sample.DbMigrator/Volo.Sample.DbMigrator.csproj -c Release -o ./publish/dbmigrator # Replace with your project name
````
{{ if UI == "NG" }}
````bash
cd angular && yarn build:prod --output-path ../publish/angular && cd ..
dotnet publish ./aspnet-core/src/Volo.Sample.HttpApi.Host/Volo.Sample.HttpApi.Host.csproj -c Release -o ./publish/apihost # Replace with your project name
{{ if Tiered == "Yes" }}
dotnet publish ./aspnet-core/src/Volo.Sample.AuthServer/Volo.Sample.AuthServer.csproj -c Release -o ./publish/authserver # Replace with your project name
{{ end }}
````
{{ else if UI == "Blazor" }}
````bash
dotnet publish ./src/Volo.Sample.Blazor/Volo.Sample.Blazor.csproj -c Release -o ./publish/blazor # Replace with your project name
dotnet publish ./src/Volo.Sample.HttpApi.Host/Volo.Sample.HttpApi.Host.csproj -c Release -o ./publish/apihost # Replace with your project name
{{ if Tiered == "Yes" }}
dotnet publish ./src/Volo.Sample.AuthServer/Volo.Sample.AuthServer.csproj -c Release -o ./publish/authserver # Replace with your project name
{{ end }}
````
{{ else if UI == "BlazorServer" }}
````bash
dotnet publish ./src/Volo.Sample.Blazor/Volo.Sample.Blazor.csproj -c Release -o ./publish/blazor # Replace with your project name
{{ if Tiered == "Yes" }}
dotnet publish ./src/Volo.Sample.HttpApi.Host/Volo.Sample.HttpApi.Host.csproj -c Release -o ./publish/apihost # Replace with your project name
dotnet publish ./src/Volo.Sample.AuthServer/Volo.Sample.AuthServer.csproj -c Release -o ./publish/authserver # Replace with your project name
{{ end }}
````
{{ else }}
````bash
dotnet publish ./src/Volo.Sample.Web/Volo.Sample.Web.csproj -c Release -o ./publish/web # Replace with your project name
{{ if Tiered == "Yes" }}
dotnet publish ./src/Volo.Sample.HttpApi.Host/Volo.Sample.HttpApi.Host.csproj -c Release -o ./publish/apihost # Replace with your project name
dotnet publish ./src/Volo.Sample.AuthServer/Volo.Sample.AuthServer.csproj -c Release -o ./publish/authserver # Replace with your project name
{{ end }}
````
{{ end }}
## Run the DbMigrator With Your Custom Settings
Update the connection string and OpenIddict section with your domain names. Run the DbMigrator app.
> For example, in a tiered MVC project.
````json
{
"ConnectionStrings": {
"Default": "Server=volo.sample;Database=Sample;User Id=sa;Password=1q2w3E**;TrustServerCertificate=true"
},
"Redis": {
"Configuration": "volo.sample"
},
"OpenIddict": {
"Applications": {
"Sample_Web": {
"ClientId": "Sample_Web",
"ClientSecret": "1q2w3e*",
"RootUrl": "https://web.sample"
},
"Sample_Swagger": {
"ClientId": "Sample_Swagger",
"RootUrl": "https://api.sample"
}
}
}
}
````
## Preparing for Local Deployment
You can skip this part if you're going to deploy on a server with real domain names.
### Creating a Self-Signed Certificate with mkcert
You can execute this command in your command prompt.
````bash
cd Desktop # or another path
mkcert -pkcs12 auth.sample api.sample web.sample # Replace with your domain names
````
Rename the created file extension to ".pfx"
Import the certificate to IIS
![Import the certificate](../../../images/iis-install-cert.gif)
### Add domain names to hosts file
Add domain names to hosts file(in Windows: `C:\Windows\System32\drivers\etc\hosts`, in Linux and macOS: `/etc/hosts`).
> For example, in a tiered MVC project.
````json
127.0.0.1 auth.sample
127.0.0.1 api.sample
127.0.0.1 web.sample
````
## Publish the Application(s) On IIS
### Update the appsettings
Update the appsettings according to your project type and domain names.
> For example, in a tiered MVC project.
````json
//AuthServer
{
"App": {
"SelfUrl": "https://auth.sample",
"CorsOrigins": "https://api.sample,https://web.sample",
"RedirectAllowedUrls": "https://api.sample,https://web.sample",
"DisablePII": "false"
},
"ConnectionStrings": {
"Default": "Server=volo.sample;Database=Sample;User Id=sa;Password=1q2w3E**;TrustServerCertificate=true"
},
"AuthServer": {
"Authority": "https://auth.sample",
"RequireHttpsMetadata": "true"
},
"StringEncryption": {
"DefaultPassPhrase": "f9uRkTLdtAZLmlh3"
},
"Redis": {
"Configuration": "volo.sample"
}
}
//HttpApi.Host
{
"App": {
"SelfUrl": "https://api.sample",
"CorsOrigins": "https://web.sample",
"DisablePII": "false",
"HealthCheckUrl": "/health-status"
},
"ConnectionStrings": {
"Default": "Server=volo.sample;Database=Sample;User Id=sa;Password=1q2w3E**;TrustServerCertificate=true"
},
"Redis": {
"Configuration": "volo.sample"
},
"AuthServer": {
"Authority": "https://auth.sample",
"RequireHttpsMetadata": "true",
"SwaggerClientId": "Sample_Swagger"
},
"StringEncryption": {
"DefaultPassPhrase": "f9uRkTLdtAZLmlh3"
}
}
//Web
{
"App": {
"SelfUrl": "https://web.sample",
"DisablePII": "false"
},
"RemoteServices": {
"Default": {
"BaseUrl": "https://api.sample/"
},
"AbpAccountPublic": {
"BaseUrl": "https://auth.sample/"
}
},
"Redis": {
"Configuration": "volo.sample"
},
"AuthServer": {
"Authority": "https://auth.sample",
"RequireHttpsMetadata": "true",
"ClientId": "Sample_Web",
"ClientSecret": "1q2w3e*"
},
"StringEncryption": {
"DefaultPassPhrase": "f9uRkTLdtAZLmlh3"
}
}
````
### Copy the .pfx file
You need to copy pfx file from ./src/{{ if Tiered == "Yes" }}AuthServer{{ else if UI == "NG" || UI == "Blazor" }}HttpApi.Host{{ else if UI == "BlazorServer" }}Blazor{{ else }}Web{{ end }} to ./publish/{{ if Tiered == "Yes" }}authserver{{ else if UI == "NG" || UI == "Blazor" }}apihost{{ else if UI == "BlazorServer" }}blazor{{ else }}web{{ end }} folder.
### Publish the Applications(s)
You can add as website from IIS.
> For {{ if Tiered == "Yes" }}authserver{{ else if UI == "NG" || UI == "Blazor" }}apihost{{ else if UI == "BlazorServer" }}blazor{{ else }}web{{ end }} we need to enable load user profile to true from application pool for created web site.
![Load User Profile](../../../images/load-user-profile-iis.png)
> For local deployment select the SSL certificate when you add the web site.
![SSL Certificate Selection](../../../images/ssl-cert-selection-in-iis.png)
The final result should look like this (depending on your project type).
![IIS deployment](../../../images/iis-sample-deployment.png)
We can visit the websites from a browser.
![Tiered IIS deployment](../../../images/iis-sample-tiered-deployment.gif)
## How to get stdout-log
If your application is running on IIS and getting errors like `502.5, 500.3x`, you can enable stdout logs to see the error details.
To enable and view stdout logs:
1. Navigate to the site's deployment folder on the hosting system.
2. If the logs folder isn't present, create the folder. For instructions on how to enable MSBuild to create the logs folder in the deployment automatically, see the [Directory structure topic](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/directory-structure?view=aspnetcore-8.0).
3. Edit the `web.config` file. Set `stdoutLogEnabled` to `true` and change the `stdoutLogFile` path to point to the logs folder (for example, `.\logs\stdout`). stdout in the path is the log file name prefix. A timestamp, process id, and file extension are added automatically when the log is created. Using stdout as the file name prefix, a typical log file is named `stdout_20180205184032_5412.log`.
4. Ensure your application pool's identity has write permissions to the logs folder.
5. Save the updated `web.config` file.
6. Make a request to the app.
7. Navigate to the logs folder. Find and open the most recent stdout log.
> The following sample aspNetCore element configures stdout logging at the relative path `.\log\.` Confirm that the AppPool user identity has permission to write to the path provided.
```xml
<aspNetCore processPath="dotnet"
arguments=".\MyAbpApp.dll"
stdoutLogEnabled="true"
stdoutLogFile=".\logs\stdout"
hostingModel="inprocess">
</aspNetCore>
```
Reference:
[IIS log creation and redirection](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/logging-and-diagnostics)
[Troubleshoot ASP.NET Core on Azure App Service and IIS](https://learn.microsoft.com/en-us/aspnet/core/test/troubleshoot-azure-iis)
## What's next?
- [Docker Deployment using Docker Compose](deployment-docker-compose.md)
- [Azure Deployment using Application Service](deployment-azure-application-service.md)

111
docs/en/solution-templates/layered-web-application/deployment/identityserver-deployment.md

@ -0,0 +1,111 @@
# IdentityServer Deployment
IdentityServer configuration may be different based on deployment configurations. Basically, you need update identityserver client related data and update your hosting preferences based on your deployment environment.
## Update Cors Origins
Cors origins configuration for **gateways**, **microservices** swagger authorization and **Angular/Blazor** (web assembly) must be updated for deployment. This can be found under **App** configuration in *appsettings.json*
```json
"CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200,https://localhost:44307,https://localhost:44325,https://localhost:44353,https://localhost:44367,https://localhost:44388,https://localhost:44381,https://localhost:44361",
```
## Update Redirect Allowed Urls
This configuration must be done if **Angular** or **Blazor** (web assembly) is used as back-office web application. It is found under **App** configuration in appsettings.json
```json
"RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307"
```
## Update DbMigrator
`IdentityServerDataSeedContributor` uses **IdentityServer.Clients** section of `appsettings.json` for `ClientId`, `RedirectUri`, `PostLogoutRedirectUri`, `CorsOrigins`.
Update DbMigrator project `appsettings.json` **IdentityServer.Clients.RootUrls** with production values:
![db-migrator-appsettings](../../../images/db-migrator-appsettings.png)
Or, manually add production values to `IdentityServerClientRedirectUris`, `IdentityServerClientPostLogoutRedirectUris`, `IdentityServerClientCorsOrigins` tables in your database.
> If you are using microservice template on-the-fly migration and not using dbmigrator project, update **IdentityService** appsettings.
Eventually, you shouldn't have `localhost` related data.
## Update IdentityServer
You need to update token signing certificate and identityserver midware based on your hosting environment.
### Signing Certificate
Default development environment uses [developer signing certificates option](https://github.com/abpframework/abp/blob/dev/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderOptions.cs#L29). Using developer signing certificates may cause *IDX10501: Signature validation failed* error on production.
Update **IdentityServerModule** with using real certificate on `IIdentityServerBuilder` pre-configuration.
![idsrv-certificate](../../../images/idsrv-certificate.png)
You can also [create self-signed certificate](https://docs.abp.io/en/commercial/5.0/startup-templates/microservice/tye-integration#create-developer-certificates) and use it.
> If you are using self signed certificate, do not forget to set the certificate (.pfx file) as `EmbeddedResource` and set `CopyToOutputDirectory`. File needs to exist physically.
### Use HTTPS
Update **IdentityServerModule** to [enfcore https](https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-6.0&tabs=visual-studio). Add `UseHsts` to add hsts headers to clients, add `UseHttpsRedirection` to redirect http requests to https.
![use-https](../../../images/use-https.png)
### Behind Load Balancer
To redirect http requests to https from load balancer, update `OnApplicationInitialization` method of the **IdentityServerModule** with the midware below:
```csharp
app.Use((httpContext, next) =>
{
httpContext.Request.Scheme = "https";
return next();
});
```
### Kubernetes
A common scenario is running applications in kubernetes environment. While IdentityServer needs to face internet on https, internal requests can be done using http.
![idsrv-k8s](../../../images/idsrv-k8s.png)
**HttpApi.Host** and **Web** applications authority should be set to http since token validations will done using http request.
![api-resource-internal-idsrv](../../../images/api-resource-internal-idsrv.png)
> You can use different appsettings files like *appsettings.production.json* to override these values or directly override environment values from kubernetes.
To isolate internal identityserver requests from external network (internet), append extra header instead of overwriting.
For ingress, you can use `nginx.ingress.kubernetes.io/configuration-snippet`:
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myidentityserver-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-buffer-size: "32k"
nginx.ingress.kubernetes.io/proxy-buffers-number: "8"
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_input_headers "from-ingress: true";
spec:
```
You need to set the IdentityServer origin based on header. Update `OnApplicationInitialization` method of the **IdentityServerModule** with the midware below:
```csharp
app.Use(async (ctx, next) =>
{
if (ctx.Request.Headers.ContainsKey("from-ingress"))
{
ctx.SetIdentityServerOrigin("https://myidentityserver.com");
}
await next();
});
```

20
docs/en/solution-templates/layered-web-application/deployment/index.md

@ -0,0 +1,20 @@
# Deployment
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
````
> This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. For other options, please change the preference on top of this document.
This guide explains how to deploy your application in staging and production environments based on your application architecture;
- [Docker Deployment using Docker Compose](deployment-docker-compose.md)
- [Azure Deployment using Application Service](azure-deployment/azure-deployment.md)
- [IIS Deployment](deployment-iis.md)

127
docs/en/solution-templates/layered-web-application/deployment/openiddict-deployment.md

@ -0,0 +1,127 @@
# OpenIddict Deployment
[OpenIddict](https://github.com/openiddict/openiddict-core) is the default OpenId Provider library used by ABP templates through the [OpenIddict Module](https://docs.abp.io/en/abp/latest/Modules/OpenIddict). It is hosted by the **AuthServer** project in the tiered/seperate-authserver application templates. For non-tiered applications, it is hosted by the Web (MVC/Razor), BlazorServer or the **HttpApi.Host** project for Blazor and Angular applications.
## Update Cors Origins
Cors origins configuration for ***gateways***, ***microservices*** swagger authorization, and ***Angular/Blazor*** (web assembly) must be updated for deployment. This can be found under the ***App*** configuration in **appsettings.json**
```json
"CorsOrigins": "https://*.MyProjectName.com,http://localhost:4200,https://localhost:44307,https://localhost:44325,https://localhost:44353,https://localhost:44367,https://localhost:44388,https://localhost:44381,https://localhost:44361",
```
## Update Redirect Allowed URLs
If **Angular** or **Blazor** (Web Assembly) is used as a back-office web application, this configuration must be done. It is found under **App** configuration in `appsettings.json`.
```json
"RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307"
```
## Update DbMigrator
`OpenIddictDataSeedContributor` uses **OpenIddict.Applications** section of `appsettings.json` for `ClientId`, `RedirectUri`, `PostLogoutRedirectUri` and `CorsOrigins`.
Update DbMigrator project `appsettings.json` **OpenIddict.Applications.RootUrls** with production values or override them:
![db-migrator-appsettings](../../../images/db-migrator-openiddict-appsettings.png)
> If you are using microservice template self-migration and not using DbMigrator project, update **IdentityService** appsettings.
Eventually, you shouldn't have any `localhost` related data.
## Update AuthServer
In the development environment, OpenIddict uses a development encryption and signing certificate. In the production environment, this must be disabled. OpenIddict needs a real certificate for signing and encrypting the tokens.
### Signing and Encryption Certificate
The default development environment uses [developer signing certificates option](https://github.com/abpframework/abp/blob/bda231b319b62582dee4f8389494cd4442ac474f/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs#L104-L105). Using developer signing certificates may cause *IDX10501: Signature validation failed* error on production.
Update **AuthServerModule** by using a real certificate on `OpenIddictBuilder` pre-configuration.
![openiddict-certificate](../../../images/openiddict-certificate.png)
When you create a new application from the application template, ABP CLI automatically generates a new self-signed certificate with the name `openiddict.pfx` and a random password. This file and the password are provided in the `GetSigningCertificate` method.
> Note: If you are receiving errors about not being able to reach the `openiddict.pfx` file on the server, make sure you have the necessary permissions.
The best place to store your certificates will depend on your host:
- For IIS applications, [storing the certificates in the machine store](https://www.sonicwall.com/support/knowledge-base/how-can-i-import-certificates-into-the-ms-windows-local-machine-certificate-store/170504615105398/) is the recommended option.
- On Azure, certificates can be uploaded and exposed to Azure App Service applications using the special `WEBSITE_LOAD_CERTIFICATES` flag. For more information, visit the [Use a TLS/SSL certificate in your code in Azure App Service](https://docs.microsoft.com/en-us/azure/app-service/configure-ssl-certificate-in-code) document.
Please check [OpenIddict documentation](https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html#registering-a-certificate-recommended-for-production-ready-scenarios) for more information and using different types of signing/encryption keys.
### Using or Disabling the HTTPS
AuthServer that hosts the OpenIddict openid-provider library uses the SSL/TLS binding of the ASP.NET Core middleware. If you host it on `HTTPS`, the **Issuer** will be hosted on `HTTPS`.
In some deployment scenarios, you may come across an error:
```json
error: invalid_request
error_description: This server only accepts HTTPS requests.
error_uri: https//documnentation.openiddict.com/errors/ID2083
```
You can easily disable the HTTPS requirement from the **appsettings.json**:
```json
"AuthServer": {
"Authority": "https://localhost:44369",
"RequireHttpsMetadata": "false"
},
```
This configuration can be found under the `ConfigureServices` method of the AuthServer project:
```csharp
if (!Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]))
{
Configure<OpenIddictServerAspNetCoreOptions>(options =>
{
options.DisableTransportSecurityRequirement = true;
});
}
```
### Behind Load Balancer
You may need to forward the headers if you are using [Nginx](https://www.nginx.com/) or [Kubernetes Nginx Ingress](https://github.com/kubernetes/ingress-nginx).
Configure the options in the **ConfigureServices** method of `AuthServerModule`:
```csharp
Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
```
And use the middleware in the **OnApplicationInitialization** method of `AuthServerModule`:
```csharp
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseForwardedHeaders();
...
```
Sometimes, including forwarded headers in requests proxied to the application may be impossible.
If the proxy enforces that all public external requests are HTTPS, the scheme can be manually set before using any middleware.
Configure it under the **OnApplicationInitialization** method of `AuthServerModule`:
```csharp
app.Use((httpContext, next) =>
{
httpContext.Request.Scheme = "https";
return next();
});
```
# FAQ
- I see `Server Error 502!`
- Check your application logs under the *Logs* folder. A misconfiguration can prevent your application from starting up, and the easiest way is to pinpoint the problem by checking the logs.
- `System.IO.FileNotFoundException: Signing Certificate couldn't found!:`
- Ensure you have the **.pfx** file in the related location. The **.pfx** file should be marked as an embedded resource, and it should be in the publish directory when you publish your application.
- I can't see the login page! It shows an `HTTP 400` error.
- This is related to the generated URL from the application that tries to authenticate against the AuthServer. Check the AuthServer logs and make sure you have **valid redirect_uri** seeded from the *OpenIddictDataSeedContributor* and the application that redirects to AuthServer has the same configuration.

46
docs/en/solution-templates/microservice/how-to-use-with-abp-suite.md

@ -6,14 +6,54 @@ You can open ABP Suite from ABP Studio by using the **ABP Suite** -> **Open** to
![abp-suite-context-menu](images/abp-suite-context-menu.png)
It opens the ABP Suite in a built-in browser window. You can also access the suite by visiting `http://localhost:3000` through your browser. From there, you can visually design your solution and generate code. In this example, we create a **Product** entity.
It opens the ABP Suite in a built-in browser window. You can also access the suite by visiting `http://localhost:3000` through your browser. From there, you can visually design your solution and generate code.
In the following example, we've defined the entity name as **Product** and provide other metadata for the related entity:
![abp-suite-product-entity](images/abp-suite-product-entity.png)
After clicking **Save and generate** for the entity in ABP Suite, use **Run** -> **Build & Restart** in the [Solution Runner](../../studio/running-applications.md#start) to apply the changes.
To confirm, visit the Swagger UI to verify that the necessary API endpoints and services have been created.
> ABP Suite requires you to stop all running instances in the related solution/project to be able to generate codes properly. Otherwise, it might not work effectively.
Then, to confirm, you can visit the Swagger UI to verify that the necessary API endpoints and services have been created.
![abp-suite-product-services](images/abp-suite-product-services.png)
> Currently, you can't generate UI code with ABP Suite for microservice solutions. This feature will be added in future releases.
If you selected the *Create user interface* option for the entity, the related UI components (pages, styles, scripts etc.) will also be created. To be able to see the related pages in your host application/UI you should apply the following steps:
1. Generate [*client-proxies*](../../framework/api-development/static-csharp-clients.md) with the following command:
```bash
abp generate-proxy -t csharp -url http://localhost:{your-service-port}/ -m {remote-service-name} --without-contracts
```
* You should run this command in the directory of your host application, and your microservices should be up and running.
* The command will generate proxy classes for your microservice in the host application, which you can see under the **ClientProxies** folder.
> **Note:** After each entity generation/modification in your services, then you should run this command to update client-proxies.
2. Configure the application for the static client proxy:
```csharp
public class MyClientAppModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Prepare for static client proxy generation
context.Services.AddStaticHttpClientProxies(
typeof(MyServiceApplicationContractsModule).Assembly
);
// Include the generated app-generate-proxy.json in the virtual file system
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<MyClientAppModule>();
});
}
}
```
After you apply these steps, you're ready to go to run your microservices and see the generated CRUD pages:
![abp-suite-product-pages](images/abp-suite-products-pages.png)

BIN
docs/en/solution-templates/microservice/images/abp-suite-products-pages.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
docs/en/studio/images/solution-explorer/abp-solution.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 74 KiB

BIN
docs/en/studio/images/solution-explorer/create-new-microservice-nolayers-additional-options.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/en/studio/images/solution-explorer/create-new-microservice-nolayers-enable-integration.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 80 KiB

BIN
docs/en/studio/images/solution-explorer/create-new-module.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/en/studio/images/solution-explorer/folder-context-menu.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 41 KiB

BIN
docs/en/studio/images/solution-explorer/imported-module.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 71 KiB

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

Loading…
Cancel
Save