Browse Source

Merge branch 'dev' into pr/21213

pull/21213/head
maliming 2 years ago
parent
commit
a10719e742
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 4
      .github/workflows/auto-pr.yml
  2. 2
      .github/workflows/build-and-test.yml
  3. 120
      Directory.Packages.props
  4. 19
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  5. 1
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  6. 9
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  7. BIN
      docs/en/Blog-Posts/2024-10-23 v9_0_Preview/docs-image-larger.png
  8. BIN
      docs/en/Blog-Posts/2024-10-23 v9_0_Preview/suite-navigation-properties.png
  9. BIN
      docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/community-talks.png
  10. BIN
      docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/cover-image.png
  11. 93
      docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/post.md
  12. BIN
      docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/switch-to-stable.png
  13. BIN
      docs/en/Community-Articles/2024-10-09-Cookies-vs-Local-Storage/cover.png
  14. BIN
      docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/cited-from-microsoft-blog-post.png
  15. BIN
      docs/en/Community-Articles/2024-10-09-NET9-Performance-Improvements/cover.png
  16. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-add-existing-package.png
  17. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-add-new-microservice.png
  18. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-solution-runner.png
  19. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/abp-studio-vs-dotnet-aspire-comparison-table.png
  20. BIN
      docs/en/Community-Articles/2024-10-11-NET-Aspire-vs-ABP-Studio/dotnet-aspire-dashboard.png
  21. BIN
      docs/en/Community-Articles/2024-10-23-Abp-Net9-Upgrade/dog-food.png
  22. BIN
      docs/en/Community-Articles/2024-10-23-Abp-Net9-Upgrade/net-support-policy.png
  23. 125
      docs/en/Community-Articles/2024-11-01-Hybrid-Cache-Net-9/POST.md
  24. BIN
      docs/en/Community-Articles/2024-11-01-Hybrid-Cache-Net-9/cover-image.png
  25. BIN
      docs/en/Community-Articles/2024-11-01-Hybrid-Cache-Net-9/debug-hybrid-cache.png
  26. 86
      docs/en/Community-Articles/2024-11-04-EF Core 9 Read-only-Primitive-Collections/POST.md
  27. 54
      docs/en/Community-Articles/2024-11-05-.NET Aspire 9.0 Features/Post.md
  28. BIN
      docs/en/Community-Articles/2024-11-05-.NET Aspire 9.0 Features/aspire_resource_lifecycle.jpg
  29. BIN
      docs/en/Community-Articles/2024-11-05-.NET Aspire 9.0 Features/aspire_trace_filter.jpg
  30. 113
      docs/en/Community-Articles/2024-11-05-SignalR-supports-trimming-and-Native-AOT/POST.md
  31. BIN
      docs/en/Community-Articles/2024-11-05-SignalR-supports-trimming-and-Native-AOT/chat.png
  32. 58
      docs/en/Community-Articles/2024-11-06-Keyed-DI-in-Middlewares-Net-9/post.md
  33. 108
      docs/en/Community-Articles/2024-11-06-Optimize-static-web-asset-delivery/POST.md
  34. BIN
      docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/cover.png
  35. BIN
      docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/img1.png
  36. BIN
      docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/img2.png
  37. BIN
      docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/img3.png
  38. BIN
      docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/img4.png
  39. BIN
      docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/img5.png
  40. 164
      docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/post.md
  41. 202
      docs/en/Community-Articles/2024-11-14-Csharp-13-Features/Post.md
  42. 165
      docs/en/Community-Articles/2024-11-14-EF-Core-9-Linq-SQL-Translation/POST.md
  43. 2
      docs/en/cli/index.md
  44. 73
      docs/en/cli/new-command-samples.md
  45. 2
      docs/en/deployment/configuring-openIddict.md
  46. 84
      docs/en/deployment/forwarded-headers.md
  47. 1
      docs/en/deployment/index.md
  48. 58
      docs/en/docs-nav.json
  49. 1
      docs/en/docs-params.json
  50. 25
      docs/en/framework/infrastructure/event-bus/index.md
  51. 2
      docs/en/framework/ui/angular/http-error-handling.md
  52. BIN
      docs/en/get-started/images/abp-studio-microservice-solution-runner-docker-dependencies.png
  53. 6
      docs/en/get-started/index.md
  54. 10
      docs/en/get-started/layered-web-application.md
  55. 32
      docs/en/get-started/microservice.md
  56. 8
      docs/en/modules/account/impersonation.md
  57. 2
      docs/en/modules/openiddict.md
  58. 18
      docs/en/release-info/migration-guides/abp-8-3.md
  59. 6
      docs/en/release-info/release-notes.md
  60. 4
      docs/en/release-info/upgrading.md
  61. 184
      docs/en/solution-templates/guide.md
  62. BIN
      docs/en/solution-templates/images/example-modular-solution.png
  63. BIN
      docs/en/solution-templates/images/layered-abp-application.png
  64. BIN
      docs/en/solution-templates/images/single-layer-abp-solution.png
  65. 21
      docs/en/solution-templates/index.md
  66. 31
      docs/en/solution-templates/layered-web-application/deployment/deployment-iis.md
  67. 7
      docs/en/solution-templates/layered-web-application/index.md
  68. BIN
      docs/en/solution-templates/microservice/images/enable-dynamic-localization.png
  69. BIN
      docs/en/solution-templates/microservice/images/ui-localization-mvc.png
  70. 114
      docs/en/solution-templates/microservice/localization-system.md
  71. 61
      docs/en/solution-templates/single-layer-web-application/index.md
  72. 76
      docs/en/studio/release-notes.md
  73. 2
      docs/en/studio/running-applications.md
  74. 19
      docs/en/studio/version-compatibility.md
  75. 24
      docs/en/studio/version-mapping.md
  76. 2
      docs/en/suite/generating-crud-page.md
  77. 8
      docs/en/tutorials/book-store/part-01.md
  78. 10
      docs/en/tutorials/book-store/part-02.md
  79. 8
      docs/en/tutorials/book-store/part-03.md
  80. 2
      docs/en/tutorials/book-store/part-04.md
  81. 8
      docs/en/tutorials/book-store/part-05.md
  82. 2
      docs/en/tutorials/book-store/part-06.md
  83. 2
      docs/en/tutorials/book-store/part-07.md
  84. 2
      docs/en/tutorials/book-store/part-08.md
  85. 12
      docs/en/tutorials/book-store/part-09.md
  86. 6
      docs/en/tutorials/book-store/part-10.md
  87. 5
      docs/en/tutorials/index.md
  88. BIN
      docs/en/tutorials/microservice/images/abp-studio-abp-suite-inside.png
  89. BIN
      docs/en/tutorials/microservice/images/abp-studio-add-entity-framework-core-migration.png
  90. BIN
      docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-command-2.png
  91. BIN
      docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-command.png
  92. BIN
      docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-dialog-2.png
  93. BIN
      docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-dialog-additional-options-step.png
  94. BIN
      docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-dialog-database-step.png
  95. BIN
      docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-dialog-integration-step.png
  96. BIN
      docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-dialog.png
  97. BIN
      docs/en/tutorials/microservice/images/abp-studio-browse-catalog-service-2.png
  98. BIN
      docs/en/tutorials/microservice/images/abp-studio-browse-catalog-service.png
  99. BIN
      docs/en/tutorials/microservice/images/abp-studio-browse-cloud-crm-products.png
  100. BIN
      docs/en/tutorials/microservice/images/abp-studio-browse-ordering-service.png

4
.github/workflows/auto-pr.yml

@ -27,10 +27,12 @@ jobs:
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
draft: true
token: ${{ github.token }}
- name: Merge Pull Request
env:
GH_TOKEN: ${{ secrets.BOT_SECRET }}
run: |
gh pr ready
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
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.2.24474.11
dotnet-version: 9.0.100
- name: chown
run: |

120
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.2" />
<PackageVersion Include="AsyncKeyedLock" Version="7.1.3" />
<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" />
@ -17,10 +17,10 @@
<PackageVersion Include="AWSSDK.SecurityToken" Version="3.7.400.30" />
<PackageVersion Include="Azure.Messaging.ServiceBus" Version="7.18.1" />
<PackageVersion Include="Azure.Storage.Blobs" Version="12.22.1" />
<PackageVersion Include="Blazorise" Version="1.6.1" />
<PackageVersion Include="Blazorise.Components" Version="1.6.1" />
<PackageVersion Include="Blazorise.DataGrid" Version="1.6.1" />
<PackageVersion Include="Blazorise.Snackbar" Version="1.6.1" />
<PackageVersion Include="Blazorise" Version="1.6.2" />
<PackageVersion Include="Blazorise.Components" Version="1.6.2" />
<PackageVersion Include="Blazorise.DataGrid" Version="1.6.2" />
<PackageVersion Include="Blazorise.Snackbar" Version="1.6.2" />
<PackageVersion Include="Castle.Core" Version="5.1.1" />
<PackageVersion Include="Castle.Core.AsyncInterceptor" Version="2.1.0" />
<PackageVersion Include="CommonMark.NET" Version="0.15.1" />
@ -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.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.Authentication.JwtBearer" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Web" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.33" />
<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.AspNetCore.TestHost" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.WebUtilities" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.0.0" />
<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.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.Data.Sqlite" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Proxies" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0.0" />
<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.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.Extensions.Caching.Memory" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.CommandLine" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Composite" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Localization" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0-rc.2.24508.2" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0.0" />
<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.2" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.0" />
<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,17 @@
<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.2.24473.5" />
<PackageVersion Include="System.Collections.Immutable" Version="9.0.0.0" />
<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.2.24473.5" />
<PackageVersion Include="System.Security.Permissions" Version="9.0.0.0" />
<PackageVersion Include="System.Security.Principal.Windows" Version="5.0.0" />
<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.Text.Encoding.CodePages" Version="9.0.0.0" />
<PackageVersion Include="System.Text.Encodings.Web" Version="9.0.0.0" />
<PackageVersion Include="System.Text.Json" Version="9.0.0.0" />
<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" />

19
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json

@ -22,6 +22,7 @@
"Permission:Accounting": "Accounting",
"Permission:Accounting:Quotation": "Quotation",
"Permission:Accounting:Invoice": "Invoice",
"Permission:Export" : "Export",
"Menu:Organizations": "Organizations",
"Menu:Accounting": "Accounting",
"Menu:Packages": "Packages",
@ -511,6 +512,7 @@
"QuotationTemplate.BankAccount": "Our bank account information can be found at {0}",
"Permission:Raffles": "Raffle",
"Permission:Draw": "Draw",
"Permission:ExportAttendeesAsExcel": "Export at attendees as Excel",
"Menu:Raffles": "Raffles",
"RaffleIsNotDrawable": "Raffle is not drawable",
"WinnerCountMustBeGreaterThanZero": "Winner count must be greater than zero",
@ -649,6 +651,19 @@
"Permission:HeroSections": "Hero Sections",
"RedirectLink": "Redirect link",
"HeroSectionsDeletionConfirmationMessage": "Are you sure you want to delete the hero section?",
"AbpStudioName": "Abp Studio name"
"AbpStudioName": "ABP Studio name",
"Permission:EditAttendees": "Edit Attendees",
"AttendeesCount": "Attendees Count",
"CreateQRCode": "Create QR Code",
"DrawTV": "Public draw on the TV",
"DrawModal": "Private draw on the modal",
"SetAsDrawable": "Set as drawable",
"SetAsNoDrawable": "Set as non-drawable",
"SetAsCompleted": "Set as completed",
"RemoveAllWinners": "Remove all winners",
"EditWinners": "Edit winners",
"EditAttendees": "Edit attendees",
"ExportAttendeesAsExcel": "Export attendees as Excel",
"DuplicateRaffle": "Duplicate raffle"
}
}
}

1
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json

@ -1211,6 +1211,5 @@
"TrainingDescription": "We are offering the following training packages for who want to get expertise on the ABP Framework and the ABP.",
"PurchaseDevelopers": "developers",
"LinkExpiredMessage": "The payment link has expired! Contact us at <a href='mailto:sales@volosoft.com'>sales@volosoft.com</a> to update the link or <a href='https://abp.io/contact'>click here</a> to navigate to the contact page."
}
}

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

@ -459,7 +459,7 @@
"FullName": "Full name",
"CompanySize": "Company size",
"TestimonialTitle": "Let's hear your testimonial",
"TestimonialInfo": "What our customers say matters! Tell us about your experience with our product and service. It is recommended to write the testimonial in English to reach a wider audience.",
"TestimonialInfo": "What you say matters! Tell us about your experience with ABP in a few sentences. Please write it in English to reach a wider audience.",
"Country": "Country",
"TestimonialTextPlaceholder": "Write a brief story about how ABP helped you build and deliver your project.",
"PositionPlaceholder": "Your position at your company",
@ -1691,8 +1691,8 @@
"HurryUpLastDay": "Hurry Up! Last Day: {0}",
"CreatingCRUDPagesWithABPSuite": "Creating CRUD pages with ABP Suite",
"MultipleYearDiscount": "Multiple Year Discount",
"CampaignDiscountText": "New Platform Discount",
"CampaignDiscountName": "New Platform",
"CampaignDiscountText": "Black Friday Discount",
"CampaignDiscountName": "Black Friday",
"CampaignName:BlackFriday": "Black Friday",
"MultipleOrganizationInfo": "See All Your Organizations",
"AbpStudioBetaAccessInfoTitle": "ABP Studio Beta Access",
@ -1867,6 +1867,7 @@
"NewsletterEmailFooterTemplateDeleteSubscription": "<a style=\"color: #007bff;\" href=\"{0}\" data-root=\"{1}\">If you change your mind, you're always welcome to resubscribe!</a>",
"GenerateQuote" : "Generate Quote" ,
"GeneratePriceQuote": "Generate a Price Quote",
"Qa:QuestionPageTitle": "Support"
"Qa:QuestionPageTitle": "Support",
"SelectedTrainingName" : "Trainings"
}
}

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

After

Width:  |  Height:  |  Size: 212 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 54 KiB

BIN
docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/community-talks.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

BIN
docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/cover-image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 KiB

93
docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/post.md

@ -0,0 +1,93 @@
# ABP.IO Platform 9.0 Has Been Released Based on .NET 9.0
![](cover-image.png)
Today, [ABP](https://abp.io/) 9.0 stable version has been released based on [.NET 9.0](https://dotnet.microsoft.com/en-us/download/dotnet/9.0). You can create solutions with ABP 9.0 starting from ABP Studio v0.9.11 or by using the ABP CLI as explained in the following sections.
## What's New With Version 9.0?
All the new features were explained in detail in the [9.0 RC Announcement Post](https://abp.io/blog/announcing-abp-9-0-release-candidate), so there is no need to review them again. You can check it out for more details.
## Getting Started with 9.0
### Creating New Solutions
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) to create new solutions.
By default, ABP Studio uses stable versions to create solutions. Therefore, it will be creating the solution with the latest stable version, which is v9.0 for now, so you don't need to specify the version. **You can create solutions with ABP 9.0 starting from v0.9.11.**
### How to Upgrade an Existing Solution
You can upgrade your existing solutions with either ABP Studio or ABP CLI. In the following sections, both approaches are explained:
### Upgrading via ABP Studio
If you are already using the ABP Studio, you can upgrade it to the latest version to align it with ABP v9.0. ABP Studio periodically checks for updates in the background, and when a new version of ABP Studio is available, you will be notified through a modal. Then, you can update it by confirming the opened modal. See [the documentation](https://abp.io/docs/latest/studio/installation#upgrading) for more info.
After upgrading the ABP Studio, then you can open your solution in the application, and simply click the **Switch to stable** action button to instantly upgrade your solution:
![](switch-to-stable.png)
> Please note that ABP CLI & ABP Studio only upgrade the related ABP packages, so you need to upgrade the other packages for .NET 9.0 manually.
### Upgrading via ABP CLI
Alternatively, you can upgrade your existing solution via ABP CLI. First, you need to install the ABP CLI or upgrade it to the latest version.
If you haven't installed it yet, you can run the following command:
```bash
dotnet tool install -g Volo.Abp.Studio.Cli
```
Or to update the existing CLI, you can run the following command:
```bash
dotnet tool update -g Volo.Abp.Studio.Cli
```
After installing/updating the ABP CLI, you can use the [`update` command](https://abp.io/docs/latest/CLI#update) to update all the ABP related NuGet and NPM packages in your solution as follows:
```bash
abp update
```
You can run this command in the root folder of your solution to update all ABP related packages.
> Please note that ABP CLI & ABP Studio only upgrade the related ABP packages, so you need to upgrade the other packages for .NET 9.0 manually.
## Migration Guides
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)
## Community News
### Highlights from .NET 9.0
Our team has closely followed the ASP.NET Core and Entity Framework Core 9.0 releases, read Microsoft's guides and documentation, and adapted the changes to our ABP.IO Platform. We are proud to say that we've shipped the ABP 9.0 based on .NET 9.0 just after Microsoft's .NET 9.0 release.
In addition to the ABP's .NET 9.0 upgrade, our team has created many great articles to highlight the important features coming with ASP.NET Core 9.0 and Entity Framework Core 9.0.
> You can read [this post](https://volosoft.com/blog/Highlights-for-ASP-NET-Entity-Framework-Core-NET-9-0) to see the list of all articles.
### New ABP Community Articles
In addition to [the articles to highlight .NET 9.0 features written by our team](https://volosoft.com/blog/Highlights-for-ASP-NET-Entity-Framework-Core-NET-9-0), here are some of the recent posts added to the [ABP Community](https://abp.io/community):
* [Video: Building Modular Monolith Applications with ASP.NET Core & ABP Studio](https://abp.io/community/videos/building-modular-monolith-applications-with-asp.net-core-abp-studio-66znukvf) by [Halil İbrahim Kalkan](https://x.com/hibrahimkalkan)
* [How to create your Own AI Bot on WhatsApp Using an ABP.io Template](https://abp.io/community/articles/how-to-create-your-own-ai-bot-on-whatsapp-using-the-abp-framework-c6jgvt9c) by [Michael Kokula](https://abp.io/community/members/Michal_Kokula)
* [ABP Now Supports .NET 9](https://abp.io/community/articles/abp-now-supports-.net-9-zpkznc4f) by [Alper Ebiçoğlu](https://x.com/alperebicoglu)
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.
### ABP Community Talks 2024.7: What’s New with .NET 9 & ABP 9?
![](community-talks.png)
In this episode of ABP Community Talks, 2024.7; we will dive into the features that came with .NET 9.0 with [Alper Ebicoglu](https://github.com/ebicoglu), [Engincan Veske](https://github.com/EngincanV), [Berkan Sasmaz](https://github.com/berkansasmaz) and [Ahmet Faruk Ulu](https://github.com/ahmetfarukulu).
## Conclusion
This version comes with some new features and a lot of enhancements to the existing features. You can see the [Road Map](https://docs.abp.io/en/abp/9.0/Road-Map) documentation to learn about the release schedule and planned features for the next releases. Please try ABP v9.0 and provide feedback to help us release more stable versions.
Thanks for being a part of this community!

BIN
docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/switch-to-stable.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 541 KiB

After

Width:  |  Height:  |  Size: 524 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

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

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

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.

Before

Width:  |  Height:  |  Size: 60 KiB

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.

Before

Width:  |  Height:  |  Size: 155 KiB

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.

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 71 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 36 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 840 KiB

After

Width:  |  Height:  |  Size: 93 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 528 KiB

After

Width:  |  Height:  |  Size: 46 KiB

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

86
docs/en/Community-Articles/2024-11-04-EF Core 9 Read-only-Primitive-Collections/POST.md

@ -0,0 +1,86 @@
# EF Core 9 Read-only Primitive Collections
In this article, we will explore the new features introduced in EF Core 9, specifically focusing on Read-only Primitive Collections. EF Core 8 introduced support for mapping arrays and mutable lists of primitive types, and you can read more about it [here](https://abp.io/community/articles/ef-core-8-primitive-collections-ttn5b6xp). This has been expanded in EF Core 9 to include read-only collections/lists. Specifically, EF Core 9 supports collections typed as `IReadOnlyList`, `IReadOnlyCollection`, or `ReadOnlyCollection`.
## Introduction to EF Core 9 Read-only Primitive Collections
Entity Framework Core 9 introduces several enhancements, one of which is the support for Read-only Primitive Collections. This feature aims to provide better support for scenarios where collections of primitive types, such as `int`, `string`, or `bool`, need to be used in a read-only manner in your entity classes. Previously, developers had to use complex workarounds to ensure collections couldn't be modified, but EF Core 9 now provides a simpler, built-in solution to handle this more effectively.
### Why Read-only Primitive Collections Matter
Read-only Primitive Collections are particularly useful when you need to guarantee the integrity of certain data within your entities. For example, imagine you have a `Car` entity that has a collection of `Colors`, represented as a set of enums. You might not want these colors to be modified after they're initially set, ensuring that any business logic reliant on these values remains consistent.
EF Core 9 introduces a convenient way to define these collections as read-only, helping developers maintain stricter control over their data.
### How It Works
Defining a read-only primitive collection is quite straightforward in EF Core 9. You can use the `IReadOnlyList<T>`, `IReadOnlyCollection<T>`, or `ReadOnlyCollection<T>` types to declare your properties, ensuring a consistent read-only behavior. This helps maintain data integrity by preventing modifications after the collection is set. Below is an example that includes a `Car` class and a `Color` enum. The `Car` class has a `Colors` property that holds a read-only list of available colors, ensuring that these values cannot be modified after being initially set:
```csharp
public enum Color
{
Black,
White,
Red,
Blue
}
public class Car
{
public int Id { get; set; }
public string Brand { get; set; }
public string Model { get; set; }
public IReadOnlyList<Color> Colors { get; private set; } = new List<Color> { Color.Black, Color.White }.AsReadOnly();
protected Car()
{
/* This constructor is for deserialization / ORM purpose */
}
public Car(string brand, string model, IEnumerable<Color> colors)
{
Brand = brand;
Model = model;
Colors = colors.ToList().AsReadOnly();
}
}
```
In the example above, `Colors` is defined as a read-only list, preventing any accidental modifications once it is set. This ensures that data integrity is maintained without the need for manual validation.
To query cars with specific colors, you can use the following example:
```csharp
var colors = new List<Color> { Color.Black, Color.White };
var cars = await context.Cars
.Where(c => c.Colors.Intersect(colors).Any())
.ToListAsync();
```
The query selects all cars that have any of the specified colors in their `Colors` collection.
The SQL result looks like this; as you can see, it sends colors as parameters instead of adding them inline. It also uses the `json_each` function to deserialize on the database side:
```sql
SELECT "c"."id",
"c"."brand",
"c"."colors",
"c"."model"
FROM "cars" AS "c"
WHERE EXISTS (SELECT 1
FROM (SELECT "c0"."value"
FROM Json_each("c"."colors") AS "c0"
INTERSECT
SELECT "c1"."value"
FROM Json_each(@__colors_0) AS "c1") AS "i")
```
### Conclusion
Read-only primitive collections make it easier to enforce data integrity by preventing changes to your collection data. This feature helps simplify your code while ensuring that critical parts of your data remain consistent.
## References
- https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-9.0/whatsnew#read-only-primitive-collections
- https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew#primitive-collections
- https://abp.io/community/articles/ef-core-8-primitive-collections-ttn5b6xp

54
docs/en/Community-Articles/2024-11-05-.NET Aspire 9.0 Features/Post.md

@ -0,0 +1,54 @@
# .NET Aspire 9.0 Features
.NET Aspire 9.0 is the next major release, supporting both .NET 8 and .NET 9. This version includes new features and improvements.
## Upgrade to .NET Aspire
Now, you don't need workloads to develop .NET Aspire applications. In your project, you can add an SDK reference to `Aspire.AppHost.Sdk`.
For more information, you can check out [https://learn.microsoft.com/en-us/dotnet/aspire/whats-new/dotnet-aspire-9?tabs=windows#upgrade-to-net-aspire-9](https://learn.microsoft.com/en-us/dotnet/aspire/whats-new/dotnet-aspire-9?tabs=windows#upgrade-to-net-aspire-9) which explains upgrading an existing project in details.
## Dashboard
.NET Aspire offers a nice dashboard for developers to observe the performance and behavior of their applications. In this version, there are some enhancements;
* **Manage resource lifecycle**: You can stop, start, and restart resources.
* **Mobile and responsive support**: The .NET Aspire dashboard is now mobile-friendly.
* **Sensitive properties**: Properties can be marked as sensitive, automatically masking them in the dashboard UI.
* **Volumes**: Configured container volumes are listed in resource details.
* **Health checks**: .NET Aspire 9 adds support for health checks.
![Resource Lifecycle](./aspire_resource_lifecycle.jpg)
## Telemetry
.NET Aspire 9 comes with many new features to the Telemetry service.
* **Improve telemetry filtering**: Telemetry data can now be filtered by attribute values.
* **Combine telemetry from multiple resources**: If a resource has multiple replicas, you can now filter telemetry data to view from all instances.
* **Browser telemetry support**: The dashboard now supports OpenTelemetry Protocol (OTLP) over HTTP and cross-origin resource sharing (CORS).
![Telemetry Filtering](./aspire_trace_filter.jpg)
## Orchestration
The .NET App Host is a core component of the .NET runtime that helps launch and execute .NET applications.
.NET Aspire 9 introduces many new features to the app host. Let's take a look;
* **Waiting for dependencies**: You can configure a resource to wait for another resource to start before starting.
* **Resource health checks**: The `Waiting for dependencies` feature uses health checks to determine if a resource is ready.
## Integrations
.NET Aspire has integrations with some services and tools that make it easy to get started. New integrations are coming with .NET Aspire 9.
* Redis Insight
* OpenAI (Preview)
* MongoDB
* Azure
For Azure part, it is better to check the official documentation here [https://learn.microsoft.com/en-us/dotnet/aspire/whats-new/dotnet-aspire-9-release-candidate-1?tabs=windows&pivots=visual-studio#azure](https://learn.microsoft.com/en-us/dotnet/aspire/whats-new/dotnet-aspire-9-release-candidate-1?tabs=windows&pivots=visual-studio#azure) because it has a very detailed explanation.
## ABP Studio
.NET Aspire and [ABP Studio](https://abp.io/studio) are tools for different purposes with different scopes, and they have different approaches to solving problems; many developers may still be confused since they also have some similar functionalities and solve some common problems. You can check the comparison of .NET Aspire and ABP Studio in this [article](https://abp.io/community/articles/.net-aspire-vs-abp-studio-side-by-side-t1c73d1l).

BIN
docs/en/Community-Articles/2024-11-05-.NET Aspire 9.0 Features/aspire_resource_lifecycle.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
docs/en/Community-Articles/2024-11-05-.NET Aspire 9.0 Features/aspire_trace_filter.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

113
docs/en/Community-Articles/2024-11-05-SignalR-supports-trimming-and-Native-AOT/POST.md

@ -0,0 +1,113 @@
# SignalR supports trimming and Native AOT
## What is SignalR?
SignalR is a library that allows you to add real-time web functionality to your applications. It provides a simple API for creating server-to-client remote procedure calls (RPC) that can be called from the server and client. Now SignalR supports trimming and Native AOT in .NET 8.0 and .NET 9.0. You can learn more about [SignalR new features](https://abp.io/community/articles/asp.net-core-signalr-new-features-summary-kcydtdgq) in this article.
## What is trimming and Native AOT?
AOT (Ahead-of-Time) compilation is a feature that allows you to compile your application into native code before running it. This can help improve performance and reduce startup times. Trimming is a feature that allows you to remove unused code from your application, reducing its size and improving performance. You can learn more about [Native AOT Compilation](https://abp.io/community/articles/native-aot-compilation-in-.net-8-oq7qtwov) in this article.
## How to use SignalR with trimming and Native AOT?
You can create ASP.NET Core AOT application with using the following command:
```bash
dotnet new webapiaot -n Acme.Sample
```
The created application uses `CreateSlimBuilder` method to create minimal builder for the application. You can use `CreateBuilder` method to create a builder with all the services registered. However, deploying an application with `CreateSlimBuilder` method is more convenient because it reduces the size of the application. You can learn more about [CreateSlimBuilder vs CreateBuilder](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/native-aot#createslimbuilder-vs-createbuilder).
Replace the `Program.cs` file with the following code:
```csharp
using Microsoft.AspNetCore.SignalR;
using System.Text.Json.Serialization;
var builder = WebApplication.CreateSlimBuilder(args);
builder.Services.AddSignalR();
builder.Services.Configure<JsonHubProtocolOptions>(o =>
{
o.PayloadSerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});
var app = builder.Build();
app.MapHub<ChatHub>("/chatHub");
app.MapGet("/", () => Results.Content("""
<!DOCTYPE html>
<html>
<head>
<title>SignalR Chat</title>
</head>
<body>
<input id="userInput" placeholder="Enter your name" />
<input id="messageInput" placeholder="Type a message" />
<button onclick="sendMessage()">Send</button>
<ul id="messages"></ul>
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/8.0.7/signalr.min.js"></script>
<script>
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chatHub")
.build();
connection.on("ReceiveMessage", (user, message) => {
const li = document.createElement("li");
li.textContent = `${user}: ${message}`;
document.getElementById("messages").appendChild(li);
});
async function sendMessage() {
const user = document.getElementById("userInput").value;
const message = document.getElementById("messageInput").value;
await connection.invoke("SendMessage", user, message);
}
connection.start().catch(err => console.error(err));
</script>
</body>
</html>
""", "text/html"));
app.Run();
[JsonSerializable(typeof(string))]
internal partial class AppJsonSerializerContext : JsonSerializerContext { }
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
```
It is a simple chat application that uses SignalR to send and receive messages.
![chat](chat.png)
Before deploying the application, ensure that **Desktop development with C++** is installed on your machine if you're using Windows OS. For more details, you can check the [pre-requisites](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot#prerequisites).
You can deploy the application with the following command:
```bash
dotnet publish -c Release
```
### Limitations
Since we are using Native AOT, there are some limitations that you should be aware of:
- **Only the JSON protocol is supported**: For the payload serialization in SignalR, only the JSON protocol is supported. You need to configure the `JsonHubProtocolOptions` to use the `AppJsonSerializerContext` for serialization/deserialization.
- **Reflection**: Native AOT does not support reflection. You need to use the `JsonSerializable` attribute to specify the types that should be serialized/deserialized. In this example, we have used the `JsonSerializable` attribute for the `string` type in the `AppJsonSerializerContext` class.
For more details, you can check the [limitations](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot#limitations-of-native-aot-deployment) of Native AOT.
## Conclusion
In this article, we learned how to use SignalR with trimming and Native AOT in .NET 8.0 and .NET 9.0. We created a simple chat application that uses SignalR to send and receive messages. We also discussed the limitations of using Native AOT and how to overcome them.
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#signalr-supports-trimming-and-native-aot).

BIN
docs/en/Community-Articles/2024-11-05-SignalR-supports-trimming-and-Native-AOT/chat.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

58
docs/en/Community-Articles/2024-11-06-Keyed-DI-in-Middlewares-Net-9/post.md

@ -0,0 +1,58 @@
# Middleware Now Supports Keyed Dependency Injection in .NET 9
This article explores a new feature in .NET 9 that enables keyed dependency injection in middleware. Previously, .NET 8 introduced keyed services, which allowed developers to register multiple instances of the same service type with distinct keys. Now, .NET 9 extends this feature to middleware, making it easier to inject specific services within the middleware based on defined keys. For more details, see this [overview on the .NET blog](https://github.com/dotnet/core/blob/main/release-notes/9.0/preview/rc1/aspnetcore.md#keyed-di-in-middleware).
## What is Keyed Dependency Injection?
Keyed dependency injection is a technique for registering multiple service versions with unique identifiers, or “keys.” This approach is especially helpful when multiple implementations of the same service are required in different contexts. For example, you may have various logging services but want to inject a specific logger based on the application’s current needs. By using keys, developers can ensure that the appropriate service version is injected precisely where it’s needed.
## Using Keyed Dependency Injection in Middleware
In .NET 9, developers can now use keyed dependency injection directly in middleware. Keyed services can be injected through the middleware constructor or via the `Invoke`/`InvokeAsync` methods, allowing for straightforward and flexible control of service instances in middleware components. Here’s an example of how to configure and use keyed dependency injection in middleware:
```csharp
var builder = WebApplication.CreateBuilder(args);
// Register services with unique keys
builder.Services.AddKeyedSingleton<MySingletonClass>("test");
builder.Services.AddKeyedScoped<MyScopedClass>("test2");
var app = builder.Build();
app.UseMiddleware<MyMiddleware>();
app.Run();
internal class MyMiddleware
{
private readonly RequestDelegate _next;
private readonly MySingletonClass _singletonService;
// Constructor injection with key
public MyMiddleware(RequestDelegate next, [FromKeyedServices("test")] MySingletonClass singletonService)
{
_next = next;
_singletonService = singletonService;
}
// Invoke method with additional scoped service injection using key
public Task Invoke(HttpContext context, [FromKeyedServices("test2")] MyScopedClass scopedService)
{
// Middleware logic here
return _next(context);
}
}
```
In this example:
- `MySingletonClass` and `MyScopedClass` are registered with unique keys (`"test"` and `"test2"`).
- These services are injected into the middleware through both the constructor and `Invoke` method, based on their respective keys.
This approach allows developers to manage which service instances are available within middleware precisely.
## Conclusion
Keyed dependency injection in middleware is a significant addition in .NET 9. It provides developers with more control over which services are injected based on specific keys. This enhancement enables selective service injection in middleware scenarios, allowing for more modular and maintainable applications.
## References
- [.NET 9 Release Notes](https://github.com/dotnet/core/blob/main/release-notes/9.0/preview/rc1/aspnetcore.md#keyed-di-in-middleware)
- [Dependency Injection and Keyed Services](https://learn.microsoft.com/aspnet/core/fundamentals/dependency-injection#keyed-services)

108
docs/en/Community-Articles/2024-11-06-Optimize-static-web-asset-delivery/POST.md

@ -0,0 +1,108 @@
# Optimizing Static Asset Delivery feature in ASP.NET Core 9.0
Delivering static assets efficiently is a key factor in building performant web applications. By optimizing how assets like CSS, JavaScript, and images are served to the browser, you can reduce load times, decrease network traffic, and improve the overall user experience.
One powerful tool to help achieve this is **MapStaticAssets**, a feature in ASP.NET Core that significantly optimizes the delivery of static resources. Whether you're working with Blazor, Razor Pages, MVC, or other UI frameworks, **MapStaticAssets** streamlines asset management and ensures that your web app delivers resources in the most efficient way possible.
## Why Optimizing Static Assets Matters
Serving static assets without optimization can lead to several performance bottlenecks:
- **Excessive network requests**: The browser may need to request the same resources multiple times, even if they haven’t changed.
- **Unnecessary data transfer**: Larger files are sent over the network, consuming bandwidth and slowing down page loads.
- **Outdated assets**: Without proper cache management, users may receive stale versions of files after an app update.
Optimizing static assets involves compressing files, managing caching headers, and ensuring that only the necessary resources are sent to the client. **MapStaticAssets** takes care of all these issues in a seamless, automated way.
## What is MapStaticAssets?
**MapStaticAssets** is designed to enhance the default static asset serving mechanism in ASP.NET Core. It can replace `UseStaticFiles` in most scenarios and comes with several built-in optimizations. These optimizations are executed at both build and publish time, ensuring that static resources are served in the most efficient way possible when your app is running.
Here's how you can implement **MapStaticAssets** in your app:
```csharp
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
// Replacing UseStaticFiles with MapStaticAssets
app.MapStaticAssets();
app.MapRazorPages();
app.Run();
```
## Key Features of MapStaticAssets
1. **Build-time Compression**:
**MapStaticAssets** automatically compresses all static assets during the build process. It uses **gzip** compression during development and **gzip + brotli** compression when publishing. This reduces the file size significantly, ensuring faster download times.
For example, in a default Razor Pages template, assets like `bootstrap.min.css` and `jquery.js` are compressed by over 80%, resulting in significantly reduced file sizes:
| File | Original Size | Compressed Size | Compression Reduction |
|----------------------|---------------|-----------------|-----------------------|
| `bootstrap.min.css` | 163 KB | 17.5 KB | 89.26% |
| `jquery.js` | 89.6 KB | 28 KB | 68.75% |
| `bootstrap.min.js` | 78.5 KB | 20 KB | 74.52% |
| **Total** | 331.1 KB | 65.5 KB | 80.20% |
2. **Content-based ETags**:
**MapStaticAssets** generates **ETags** based on the SHA-256 hash of the file content, encoded in Base64. This ensures that the browser only re-downloads a resource if its content has changed. This eliminates unnecessary network requests, improving page load speeds.
3. **Smaller File Sizes for Libraries**:
Popular component libraries, such as **Fluent UI Blazor** and **MudBlazor**, benefit from similar compression optimizations. For example, the size of the **MudBlazor** library is reduced by over 90%, from 588 KB to just 46.7 KB after compression.
| File | Original Size | Compressed Size | Compression Reduction |
|----------------------|---------------|-----------------|-----------------------|
| `MudBlazor.min.css` | 541 KB | 37.5 KB | 93.07% |
| `MudBlazor.min.js` | 47.4 KB | 9.2 KB | 80.59% |
| **Total** | 588.4 KB | 46.7 KB | 92.07% |
4. **Automatic Optimization**:
As libraries or components are added or updated, **MapStaticAssets** automatically optimizes the assets as part of the build process. This includes minimizing the size of JavaScript and CSS files, reducing the impact of mobile or low-bandwidth environments.
5. **Serving Assets with a CDN**:
Although **MapStaticAssets** is focused on server-side optimizations, integrating a **CDN (Content Delivery Network)** can further boost performance by serving static assets from servers geographically closer to the user, reducing latency.
## Comparing MapStaticAssets to IIS Dynamic Compression
**MapStaticAssets** provides several advantages over traditional dynamic compression techniques, such as IIS **gzip** compression:
- **Simplicity**: There is no need for server-specific configuration, making **MapStaticAssets** easy to implement.
- **Performance**: By compressing assets at build time, the app doesn't need to perform compression during every request, which improves server performance.
- **Optimization**: Developers can focus on ensuring that assets are compressed to the smallest possible size during the build process.
For example, using **MapStaticAssets**, a file like `MudBlazor.min.css` is compressed down to 37.5 KB, whereas IIS dynamic compression might result in a size of 90 KB. This represents a **59%** reduction in size.
## About MapAbpStaticAssets
The ABP framework is 100% compatible with this new feature.
However, some JavaScript, CSS, and image files exist in the [Virtual File System](https://abp.io/docs/latest/framework/infrastructure/virtual-file-system), which ASP.NET Core's **MapStaticAssets** can't handle. For these files, additional **StaticFileMiddleware** is needed to serve them, which is where **MapAbpStaticAssets** comes in.
**MapAbpStaticAssets** adds the necessary **StaticFileMiddleware** to ensure that virtual files are correctly served. This middleware setup ensures seamless delivery of virtual resources alongside static assets.
You can view the source code of **MapAbpStaticAssets** on [GitHub](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs#L129-L198).
## Conclusion
Optimizing static asset delivery is essential for building fast, efficient web applications. **MapStaticAssets** simplifies and automates the optimization of static files by providing build-time compression, caching headers, and content-based ETags. This ensures that your app's static assets are always delivered in the most efficient way, whether users are on fast broadband or slower mobile connections. By using **MapStaticAssets**, you can deliver a faster, more reliable experience for your users with minimal effort.
## References
* [Static files in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-9.0)
* [What's new in ASP.NET Core 9.0](https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-9.0?view=aspnetcore-8.0#optimize-static-web-asset-delivery)

BIN
docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/cover.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 KiB

BIN
docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/img1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

BIN
docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/img2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

BIN
docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/img3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

BIN
docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/img4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/img5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

164
docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/post.md

@ -0,0 +1,164 @@
Built-in OpenAPI Document Generation with .NET 9 — No more SwaggerUI! 👋
========================================================================
![Cover](cover.png)
What’s Swagger UI?
------------------
[Swagger UI](https://swagger.io/) is an open-source tool that automatically generates an interactive, web-based documentation interface for WebAPIs.
It supports OpenAPI standards. It was very popular tool among the ASP.NET Core developers from 2020 to 2024.
Because it was a built-in tool comes with ASP.NET Core default templates.
We liked this tool because it was the first tool that allows us to make WebAPI calls for testing.
Now it provides paid services as well as free ones.
> Previously, Swagger was included by default from **.NET 5** to **.NET 8** in .NET web templates.
---
What’s OpenAPI?
---------------
OpenAPI is a standard specification for defining REST APIs.
The official website is [https://www.openapis.org/](https://www.openapis.org/).
Microsoft is now using OpenAPI and here is the official documentation 👉 [https://aka.ms/aspnet/openapi](https://aka.ms/aspnet/openapi)
---
Replacement of Swagger UI with OpenAPI
----------------------------------------------------------------------------
Swagger UI is no longer integrated into NET 9, as Microsoft wants a solution with first-class support, better control, and enhanced security. As you see in the below screenshot, Microsoft declares that it's already removed.
![Docs](img2.png)
---
## Why is Swagger Removed from .NET 9?
In March 2024, the ASP.NET Core team announced that they are removing the `Swashbuckle.AspNetCore` dependency from web templates from .NET 9 release.
> This decision was influenced by the project's lack of active maintenance and the absence of an official release for .NET 8.
Microsoft team created a new package `Microsoft.AspNetCore.OpenApi`. It provides built-in OpenAPI document generation just like Swagger. So Microsoft doesn't depend on external tools. Because in every .NET release, they need to ask the owners of the external tool libraries to align with their new version. And sometimes these library owners cannot update their code-base according to the recent .NET changes. And it is becoming harder for Microsoft to support the 3rd party libraries under these circumstances. Basically reducing 3rd party dependencies will help Microsoft fast release cycles.
I read Reddit, GitHub discussions and YouTube reviews about this topic. As I see community members expressed concerns about the inactivity of Swashbuckle and they are discussing alternatives like contributing to or forking the project. The Microsoft team also contacted the owners of Swashbuckle and NSwag to explore potential collaborations and ensure a smooth transition for developers.
In the below GitHub issue, you can see the details of this decision:
* [github.com/dotnet/aspnetcore/issues/54599](https://github.com/dotnet/aspnetcore/issues/54599)
**Jeremy** -Product Manager- at Microsoft, answers why they took this decision in [this post](https://github.com/dotnet/aspnetcore/issues/54599#issuecomment-2004975574).
![Jeremy Comments](img3.png)
As a summary;
**The change is due to a lack of maintenance of the Swagger library**, although it has seen some recent updates. This aims to reduce dependency on external tools and provide a streamlined, out-of-the-box experience for generating OpenAPI documentation for ASP.NET Core Web APIs.
---
What are the Benefits of the New OpenAI Package?
---------------------------------------------------------------
### Native Support and Reduced Dependency
The new `Microsoft.AspNetCore.OpenApi` package provides first-class citizen support for OpenAPI. It reduces reliance on external tools like Swashbuckle or NSwag for basic documentation needs. The native implementation leverages source generators to reduce runtime overhead.
### Simplified Configuration
No need extra setup or 3rd party integrations. Just by defining controllers and endpoints, ASP.NET Core automatically generates OpenAPI specifications.
### Well Integration with Minimal APIs
[Minimal APIs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis) introduced in .NET 6. There's an optimized built-in support for Minimal APIs. It automatically adds metadata for routes, request parameters, and responses.
### Compatibility with Existing Tools
You can still use the output of OpenAPI with Swagger or NSwag... So it doesn't mean that in this case you have only one option when you use OpenAPI.
---
How to Use the New OpenAPI in .NET9?
------------------------------------
When you create a new ASP.NET Core project, you can see the below checkbox to add OpenAPI.
![New .NET 9 Project Screen](img5.png)
I created a new .NET 9 web project, I saw that OpenAPI had already been added.
![Package Reference](img4.png)
## Add OpenAPI Support For Your Existing Project
Upgrade your project to .NET 9 and add the required NuGet package [Microsoft.AspNetCore.OpenApi](https://www.nuget.org/packages/Microsoft.AspNetCore.OpenApi)
```
dotnet add package Microsoft.AspNetCore.OpenApi
```
###
Add the following services and middleware in `Program.cs`
```
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(); //<<-----
var app = builder.Build();
app.MapOpenApi(); //<<-----
app.MapGet("/", () => "Test");
app.Run();
```
Your OpenAPI document URL is [_https://localhost:7077/openapi/v1.json_](https://localhost:7077/openapi/v1.json)
Change the port to your active port. This is how it looks like:
![Web UI of the Documentation](img1.png)
---
Alternative 3rd Party Tool: Scalar
==================================
**Scalar** is an open-source API platform for RestAPI documentation. Also, it provides an interface for interacting with RESTful API. Generates interactive and user-friendly API documentation. Supports OpenAPI and Swagger specifications. It’s open-source with **7K stars** on GitHub.
See the repo 👉 [https://github.com/scalar/scalar](https://github.com/scalar/scalar).
That's all from the replacement of Swagger in .NET 9.
Happy coding 👨‍💻
**References**
* [https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-9.0?view=aspnetcore-8.0#openapi](https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-9.0?view=aspnetcore-8.0#openapi)

202
docs/en/Community-Articles/2024-11-14-Csharp-13-Features/Post.md

@ -0,0 +1,202 @@
# C# 13 Features
C# 13 is the latest version of C# and it comes with a lot of new features. In this article, we will discuss some of the new features of C# 13.
## `params` collections
With the C# 13, method parameter with `params` keyword isn't limited to be an array. You can now use any collection type that implements `IEnumerable<T>` interface.
Let's see how it can help us in our code.
```csharp
public IEnumerable<int> GetOdds(params IEnumerable<int> numbers)
{
foreach (var number in numbers)
{
if (number % 2 != 0)
{
Console.WriteLine(number);
}
}
}
```
## New lock object
I'm sure you have used `lock` statement in your code to synchronize access to a shared resource. With C# 13, you can now use a new lock object that is more efficient than the traditional lock object.
The new `Lock` type provides better thread synchronization through its API. When `Lock.EnterScope()` method is called, it returns a struct named `Scope` that contains a `Dispose` method. The `Dispose` method is called when the `Scope` object goes out of scope, which releases the lock. C# `using` statement recognizes the `Dispose` method and calls it automatically like it does with other `IDisposable` objects.
It was something similar before:
```csharp
private object _lock = new();
public void DoSomething()
{
lock (_lock)
{
// Do something
}
}
```
Now, you can use the new lock object like this:
```csharp
System.Threading.Lock x = new System.Threading.Lock();
public void DoSomething()
{
using (x.EnterScope())
{
// Do something
}
}
```
## New escape sequence
In C# 13, a new escape sequence `\e` has been introduced to represent the `ESCAPE` character, Unicode `U+001B`. Previously, you had to use `\u001b` or `\x1b` to represent this character. The new `\e` escape sequence simplifies this process and avoids potential issues with hexadecimal digits following `\x1b`.
> You can check [here](https://en.wikipedia.org/wiki/ANSI_escape_code#C0_control_codes) for ANSI escape codes.
## Implicit index access
The implicit "from the end" index operator, `^`, is now allowed in an object initializer expression.
It was not possible before, but now you can do this:
```csharp
var countdown = new TimerRemaining()
{
buffer =
{
[^1] = 0,
[^2] = 1,
[^3] = 2,
[^4] = 3,
[^5] = 4,
[^6] = 5,
[^7] = 6,
[^8] = 7,
[^9] = 8,
[^10] = 9
}
};
```
It's a great feature that makes the code more readable and maintainable. Still not a big deal, but it's nice to have it.
## `ref` and `unsafe` in iterators and async methods
In C# 13, the restrictions on using `ref` and `unsafe` constructs in iterators and async methods have been relaxed. Previously, you couldn't declare local `ref` variables or use unsafe contexts in these methods. Now, you can declare ref local variables and use unsafe contexts in async methods and iterators, provided they are not accessed across `await` or `yield` boundaries
This change allows for more expressive and efficient code, especially when working with types like `System.Span<T>` and `System.ReadOnlySpan<T>`. The compiler ensures that these constructs are used safely, and it will notify you if any safety rules are violated.
You can read more about this feature on the [Microsoft Learn page](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-13.0/ref-unsafe-in-iterators-async).
## More partial members
In C# 13, the concept of partial members has been expanded to include partial properties and partial indexers. Previously, only methods could be defined as partial members. This means you can now split the definition of properties and indexers across multiple files, just like you could with methods.
For example, you can declare a partial property in one part of your class and implement it in another part. Here's a simple illustration:
```csharp
public partial class MyClass
{
// Declaring declaration
public partial string MyProperty { get; set; }
}
public partial class MyClass
{
// Implementing declaration
private string _myProperty;
public partial string MyProperty
{
get => _myProperty;
set => _myProperty = value;
}
}
```
This feature allows for better organization and modularization of your code, especially in large projects where different parts of a class might be implemented by different team members.
## Overload resolution priority
What does "Overload resolution priority" section mean in this page?
In C# 13, the OverloadResolutionPriority attribute allows library authors to specify which method overload should be preferred by the compiler when multiple overloads are available. This attribute helps avoid ambiguity and ensures that the most appropriate overload is chosen, even if it might not be the most obvious choice based on traditional overload resolution rules.
This may be useful in scenarios where you have multiple overloads that are equally valid, but you want to prioritize one over the others. The attribute can be applied to a method or constructor to indicate its priority in the overload resolution process. It can prevent unexpected behavior and make your code more predictable and maintainable.
Let me show with an example:
```csharp
public class Example
{
// Existing method
public void Display(string message = "Hello!")
{
Console.WriteLine("Message: " + message);
}
// New, more efficient method with higher priority
[OverloadResolutionPriority(1)]
public void Display(string message = "Hello!", int repeatCount = 3)
{
for (int i = 0; i < repeatCount; i++)
{
Console.WriteLine("Message: " + message);
}
}
}
class Program
{
static void Main()
{
Example example = new Example();
// Normally, you can't compile this code because of ambiguity:
example.Display();
}
}
```
Output:
```
Message: Hello!
Message: Hello!
Message: Hello!
```
## The `field` keyword
n C# 13, the `field` keyword is introduced as a preview feature to simplify property accessors. This keyword allows you to reference the compiler-generated backing `field` directly within a property accessor, eliminating the need to declare an explicit backing `field` in your type declaration.
For example, instead of writing:
```csharp
private int _value;
public int Value
{
get => _value;
set => _value = value;
}
```
You can now write:
```csharp
public int Value
{
get => field;
set => field = value;
}
```
This makes your code cleaner and more concise. However, be cautious if you have a `field` named `field` in your class, as it could cause confusion. You can disambiguate by using `@field` or `this.field`.
Make sure you're using the latest `LangVersion` in your `.csproj` project file to enable this feature.
```xml
<LangVersion>preview</LangVersion>
```

165
docs/en/Community-Articles/2024-11-14-EF-Core-9-Linq-SQL-Translation/POST.md

@ -0,0 +1,165 @@
# EF Core 9 LINQ & SQL translation
EF Core improves the translation of LINQ queries to SQL with every release. EF Core 9 is no exception. This article will show you some of the improvements in EF Core 9.
EF Core 9 includes a lot of improvements in LINQ to SQL translation. we don't cover all of them in this article. You can find more information in the [official release notes](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-9.0/whatsnew#linq-and-sql-translation).
## Support for complex types
### GroupBy
EF Core now supports grouping by complex type instance. For example:
```csharp
var groupedAddress = await context.Customers
.GroupBy(c => new { c.Address })
.Select(g => new { g.Key, Count = g.Count() })
.ToListAsync();
```
Address is a complex type as a value object here.
### ExecuteUpdate
EF Core now supports updating a complex type. For example:
```csharp
var newAddress = new Address("New Street", "New City", "New Country");
await context.Customers
.Where(e => e.Region == "Turkey")
.ExecuteUpdateAsync(s => s.SetProperty(b => b.Address, newAddress));
```
EF Core updates each column of the complex type.
## Prune unneeded elements from SQL
Ef Core now translates LINQ queries to SQL more efficiently. It will remove unneeded elements from the SQL query and bring better performance.
### Table pruning
When you use table-per-hierarchy (TPH) inheritance, previously EF Core generated SQL queries that included JIONs to tables that were not needed.
For example:
```csharp
public class Order
{
public int Id { get; set; }
...
public Customer Customer { get; set; }
}
public class DiscountedOrder : Order
{
public double Discount { get; set; }
}
public class Customer
{
public int Id { get; set; }
...
public List<Order> Orders { get; set; }
}
public class AppContext : DbContext
{
...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>().UseTptMappingStrategy();
}
}
```
Consider the following query to get all customers with at least one order:
```csharp
var customers = await context.Customers.Where(o => o.Orders.Any()).ToListAsync();
```
Previously, EF Core generated the following SQL query:
```sql
SELECT [c].[Id], [c].[Name]
FROM [Customers] AS [c]
WHERE EXISTS (
SELECT 1
FROM [Orders] AS [o]
LEFT JOIN [DiscountedOrders] AS [d] ON [o].[Id] = [d].[Id]
WHERE [c].[Id] = [o].[CustomerId])
```
It included a JOIN to the `DiscountedOrders` table, which was not needed. In EF Core 9, the generated SQL query is:
```sql
SELECT [c].[Id], [c].[Name]
FROM [Customers] AS [c]
WHERE EXISTS (
SELECT 1
FROM [Orders] AS [o]
WHERE [c].[Id] = [o].[CustomerId])
```
## EF Core in ABP
ABP Framework is built on top of the latest technologies. It will support EF Core 9 as soon as it is released. You can use the latest features of EF Core in your ABP applications.
For example, you can use the `ExecuteUpdateAsync` method in your ABP application:
```csharp
public class Book : FullAuditedAggregateRoot<Guid>
{
public string Name { get; set; }
public float Price { get; set; }
public string Author { get; set; }
}
public class AppContext : AbpDbContext<AppContext>
{
public DbSet<Book> Books { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(builder);
builder.Entity<Book>(b =>
{
b.ToTable("Books");
b.ConfigureByConvention();
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
b.Property(x => x.Author).IsRequired().HasMaxLength(64);
});
}
}
public class BookRepository : EfCoreRepository<AppContext, Book, Guid>, IBookRepository
{
public BookRepository(IDbContextProvider<AppContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async Task UpdatePriceByAuthorAsync(string author, float price)
{
await (await GetDbSetAsync())
.Where(b => b.Author == author)
.ExecuteUpdateAsync(b => b.SetProperty(x => x.Price, price));
}
}
```
* `FullAuditedAggregateRoot` is an aggregate root base class with auditing properties provided by ABP Framework.
* `IRepository` is a generic repository interface provided by ABP Framework that provides CRUD operations and you can use EF Core's API in your entity repository implementation.
## References
* [LINQ and SQL translation](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-9.0/whatsnew#linq-and-sql-translation)
* [ABP Entity Framework Core Integration](https://abp.io/docs/latest/framework/data/entity-framework-core)
* [ABP Entities](https://abp.io/docs/latest/framework/architecture/domain-driven-design/entities)

2
docs/en/cli/index.md

@ -913,7 +913,7 @@ abp logout
### bundle
This command generates script and style references for ABP Blazor WebAssembly and MAUI Blazor project and updates the **index.html** file. It helps developers to manage dependencies required by ABP modules easily. In order ```bundle``` command to work, its **executing directory** or passed ```--working-directory``` parameter's directory must contain a Blazor or MAUI Blazor project file(*.csproj).
This command generates script and style references for ABP Blazor WebAssembly and MAUI Blazor project and updates the **index.html** file. It helps developers to manage dependencies required by ABP modules easily. In order for ```bundle``` command to work, its **executing directory** or passed ```--working-directory``` parameter's directory must contain a Blazor or MAUI Blazor project file(*.csproj).
Usage:

73
docs/en/cli/new-command-samples.md

@ -221,6 +221,79 @@ As seen below, ABP libraries are local project references.
</ItemGroup>
```
## Using Existing Configuration
If you want to programmaticaly create solutions, you can use an existing configuration instead of passing parameters to CLI one by one. ABP Studio keeps the solution creation history locally in `(UserProfile)\.abp\studio\solution-creation-history.json` file, there you can find the configurations of the solutions created in your machine.
### Using a Solution Id
In `*.abpsln` file of the solutions, there is an ID field that you can use to recreate a solution. To do this, pass the id to cli using `-shi or --solution-history-id` parameters.
```bash
abp new -shi dbb1afa9-190e-419a-842d-2780bb1bad1f
abp new -shi dbb1afa9-190e-419a-842d-2780bb1bad1f -o D:\test\Acme.BookStore
```
### Using a JSON Configuration File
You can also use a configuration file to create solutions. You need to use `-rcp or ready-config-path` parameters to do that.
```bash
abp new -rcp MyTests\config.json
abp new -rcp D:\MyTests\config.json
abp new -rcp D:\MyTests\config.json -o D:\test\Acme.BookStore
```
To prepare a config file, you can check the records in `solution-creation-history.json` file mentioned above. An example config file would look like that:
```json
{
"solutionName": {
"fullName": "Acme.BookStore",
"companyName": "Acme",
"projectName": "BookStore"
},
"pro": true,
"useOpenSourceTemplate": false,
"booksSample": false,
"databaseProvider": "ef",
"createInitialMigration": true,
"runDbMigrator": true,
"uiFramework": "angular",
"theme": "leptonx",
"themeStyle": "system",
"mobileFramework": "none",
"databaseManagementSystem": "sqlserver",
"databaseManagementSystemBuilderExtensionMethod": "UseSqlServer",
"connectionString": "Server=(LocalDb)\\\\MSSQLLocalDB;Database=BookStore;Trusted_Connection=True;TrustServerCertificate=true",
"mauiBlazorApplicationIdGuid": "d3499a09-f3d4-4bb7-9d58-4c7b1caee331",
"tiered": false,
"publicWebsite": false,
"cmskit": false,
"openIddictAdmin": true,
"languageManagement": true,
"textTemplateManagement": true,
"multiTenancy": true,
"auditLogging": false,
"gdpr": true,
"chat": false,
"fileManagement": false,
"socialLogins": true,
"includeTests": true,
"distributedEventBus": "none",
"publicRedis": false,
"separateTenantSchema": false,
"progressiveWebApp": false,
"runProgressiveWebAppSupport": false,
"runInstallLibs": false,
"runBundling": false,
"kubernetesConfiguration": true,
"templateName": "app"
}
```
## See Also
* [ABP CLI documentation](../cli/index.md)

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

@ -36,7 +36,7 @@ To avoid that, consider creating self-signed certificates and storing them in th
`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.
You can use the `dotnet dev-certs https -v -ep openiddict.pfx -p 00000000-0000-0000-0000-000000000000` command to generate the `openiddict.pfx` certificate.
> `00000000-0000-0000-0000-000000000000` is the password of the certificate, you can change it to any password you want.

84
docs/en/deployment/forwarded-headers.md

@ -0,0 +1,84 @@
# Forwarded Headers
Reverse proxies and load balancers play a crucial role in modern web application architectures. When an application is deployed behind these proxies and load balancers, several specific issues can arise. This document will discuss these issues in detail, explain how ASP.NET Core's forwarded headers middleware can address them, and provide a code example for configuring forwarded headers in an ABP application.
## Possible problem in a Reverse Proxy Environment
When requests pass through a reverse proxy or load balancer, the following common issues can occur:
### 1. Loss of Original Request Information
A reverse proxy or load balancer typically modifies the original HTTP request headers. For example, the proxy may replace the client's `X-Forwarded-For` header, or the `Host` header might be set to the proxy's address. This can result in the backend application being unable to directly access the client's IP address, the true hostname, and the protocol used.
### 2. HTTPS vs HTTP Protocol Confusion
When a request is forwarded by a proxy server, it is often upgraded to HTTPS to ensure secure transmission. The proxy server will send a header like `X-Forwarded-Proto` to indicate whether the original request was HTTP or HTTPS. If the backend application does not correctly handle this header, it may generate URLs with the wrong protocol.
### 3. Path Handling Issues
Since load balancers and proxies might modify or map the request URL paths differently, the backend application could encounter path inconsistencies. For example, a reverse proxy might forward a request from `/api` to `/myapp/api`. If the backend application is not correctly configured, path parsing errors may occur.
### 4. IP Address and Security
Reverse proxies might replace the original client IP address with their own, which can affect logging, authentication, and access control mechanisms. To retrieve the actual client IP address, the `X-Forwarded-For` header must be correctly parsed and trusted.
### 5. Load Balancer Impact
Load balancers might distribute requests to different backend servers using different algorithms. This can create session affinity problems. If session data is stored on a single server and the load balancer directs subsequent requests to different servers, session loss or inconsistency may occur.
## Forwarded Headers Middleware in ABP web application
To resolve the above issues, ASP.NET Core provides a built-in middleware, `ForwardedHeadersMiddleware`, which processes the headers forwarded by reverse proxies. This middleware helps the application recover the correct original request information, such as the client’s IP address, protocol, and host.
### Configuring `ForwardedHeadersMiddleware`
ASP.NET Core’s `ForwardedHeadersMiddleware` supports several HTTP headers:
- **X-Forwarded-For**: Contains the original client’s IP address.
- **X-Forwarded-Proto**: Indicates whether the original request was HTTP or HTTPS.
- **X-Forwarded-Host**: Contains the original host requested by the client.
- **X-Forwarded-Port**: Indicates the original port of the request.
To configure this middleware:
1. In the `ConfigureServices` method of your module, configure the `ForwardedHeadersOptions`:
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
}
```
2. In the `OnApplicationInitialization` method of your module, add the middleware:
> Forwarded Headers Middleware should run before other middleware. This ordering ensures that the middleware relying on forwarded headers information can consume the header values for processing. Forwarded Headers Middleware can run after diagnostics and error handling, but it must be run before calling UseHsts:
```csharp
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseForwardedHeaders();
}
else
{
app.UseErrorPage();
app.UseForwardedHeaders();
app.UseHsts();
}
// Other middleware configurations...
}
```
## References
- [ASP.NET Core Proxy and Load Balancer Configuration](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-9.0)

1
docs/en/deployment/index.md

@ -12,3 +12,4 @@ However, there are some topics that you should care about when you are deploying
* [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.
* [Forwarded Headers](./forwarded-headers): Explains how to configure the application to trust headers forwarded by reverse proxies and recover the original request information from the `X-Forwarded-For` and `X-Forwarded-Proto` headers.

58
docs/en/docs-nav.json

@ -156,6 +156,43 @@
}
]
},
{
"text": "Microservice Solution",
"items": [
{
"text": "Overview",
"path": "tutorials/microservice/index.md"
},
{
"text": "1: Creating the initial solution",
"path": "tutorials/microservice/part-01.md"
},
{
"text": "2: Creating the initial Catalog service",
"path": "tutorials/microservice/part-02.md"
},
{
"text": "3: Building the Catalog service",
"path": "tutorials/microservice/part-03.md"
},
{
"text": "4: Creating the initial Ordering service",
"path": "tutorials/microservice/part-04.md"
},
{
"text": "5: Building the Ordering service",
"path": "tutorials/microservice/part-05.md"
},
{
"text": "6: Integrating the services: HTTP API Calls",
"path": "tutorials/microservice/part-06.md"
},
{
"text": "7: Integrating the services: Using Distributed Events",
"path": "tutorials/microservice/part-07.md"
}
]
},
{
"text": "Community Articles",
"path": "https://abp.io/community"
@ -227,8 +264,8 @@
"path": "studio/concepts.md"
},
{
"text": "Version Compatibility",
"path": "studio/version-compatibility.md"
"text": "Version Mapping",
"path": "studio/version-mapping.md"
},
{
"text": "Release Notes",
@ -893,7 +930,7 @@
"items": [
{
"text": "Overview",
"path": "framework/ui/mvc-razor-pages/overall"
"path": "framework/ui/mvc-razor-pages/overall.md"
},
{
"text": "Navigation / Menus",
@ -1642,6 +1679,10 @@
"text": "Overview",
"path": "solution-templates"
},
{
"text": "Template Guide",
"path": "solution-templates/guide.md"
},
{
"text": "Single-Layer Solution",
"path": "solution-templates/single-layer-web-application"
@ -1718,7 +1759,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",

1
docs/en/docs-params.json

@ -7,6 +7,7 @@
"MVC": "MVC / Razor Pages",
"Blazor": "Blazor WebAssembly",
"BlazorServer": "Blazor Server",
"BlazorWebApp": "Blazor WebApp",
"NG": "Angular"
}
},

25
docs/en/framework/infrastructure/event-bus/index.md

@ -6,5 +6,26 @@ An event bus is a mediator that transfers a message from a sender to a receiver.
ABP provides two type of event buses;
* **[Local Event Bus](local)** is suitable for in-process messaging.
* **[Distributed Event Bus](distributed)** is suitable for inter-process messaging, like microservices publishing and subscribing to distributed events.
* **[Local Event Bus](local/index.md)** is suitable for in-process messaging.
* **[Distributed Event Bus](distributed/index.md)** is suitable for inter-process messaging, like publishing and subscribing to distributed events in a distributed/microservice system.
## Event Bus Guiding
You may confuse which event bus to use in your application. Here, a few example scenarios:
* If you are building a microservice system, use the distributed event bus for **inter-microservice communication**. If you are publishing an event and always handling it in the same microservice, you can use the local event bus for that event.
* If you are building a modular monolith application, use the distributed event bus for **inter-module communication**. Since the distributed event bus works in-process by default (unless you configure a real distributed event bus provider). In that way, if you migrate to a microservice system later, these inter-module communication can become a inter-microservice communication without any code change (with just installing a distributed event bus provide package). If you are publishing an event and always handling it in the same module, you can use the local event bus for that event.
* If you are building a monolith (non-modular) application, you can always use the local event bus.
The distributed event bus works in-process by default. Unless you don't configure a real distributed event bus provider, it works just like the local event bus. Once you configure a real distributed event bus provider, all your events become distributed.
So, you use the local event bus only if you an event should always remain in-process in any scenario. For other type of events, use the distributed event bus.
### Technical Differences
There are some technical differences between the local and distributed event bus:
* You can send entities or other non-serializable objects using the local event bus since these objects are not serialized/deserialized on event publishing. On the other hand, distributed event bus serializes/deserializes objects once you use a real distributed event bus provider.
* The local event bus is always transactional in the database level. For distributed event bus, you should enable inbox/outbox pattern to ensure data consistency once you use a real distributed event bus provider.
These differences are because of the distributed event bus supports distributed scenarios while the local event bus is only used for in-process messaging. When you don't set up a real distributed event bus provider, these differences are not valid.

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

@ -27,7 +27,7 @@ export class AppModule {}
```
- `ErrorScreenErrorCodes` the error codes that you can pass to `skipHandledErrorCodes` and `forWhichErrors`.
- `skipHandledErrorCodes` the error codes those you don't want to handle it.
- `skipHandledErrorCodes` the error codes those you don't want to handle.
- `errorScreen` the screen that you want to show when a route error occurs.
- `component` component that you want to show.
- `forWhichErrors` same as `ErrorScreenErrorCodes`

BIN
docs/en/get-started/images/abp-studio-microservice-solution-runner-docker-dependencies.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

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

@ -5,10 +5,14 @@ Great that you've decided to create a new application with ABP. ABP provides mul
Please select one of the following documents best fits for your application:
- **[Single-Layer Solution](single-layer-web-application.md)**: Creates a single-project solution. Recommended for building an application with a **simpler and easy to understand** architecture.
- **[Layered Solution](layered-web-application.md)**: A fully layered (multiple projects) solution based on [Domain Driven Design](../framework/architecture/domain-driven-design) practices. Recommended for long-term projects that need a **maintainable and extensible** codebase.
- **[Application (Layered)](layered-web-application.md)**: A fully layered (multiple projects) solution based on [Domain Driven Design](../framework/architecture/domain-driven-design) practices. Recommended for long-term projects that need a **maintainable and extensible** codebase.
- **[Microservice Solution](microservice.md)**: A **distributed solution** to build **microservice systems**. It includes pre-built services, API gateways, web and mobile applications, Kubernetes and Helm configuration, and everything you need to start your large-scale microservice solution.
- **Others**
- [Empty ASP.NET Core Application](empty-aspnet-core-application.md)
- [MAUI Application](maui.md)
- [WPF Application](wpf.md)
- [Console Application](console.md)
## Which Startup Template is Suitable for Me?
You can see the *[Solution Template Selection Guide](../solution-templates/guide.md)* if you are not sure which solution template is suitable for you.

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

@ -3,7 +3,7 @@
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"UI": ["MVC", "Blazor", "BlazorServer", "BlazorWebApp", "NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
@ -162,7 +162,7 @@ You can start the following application(s):
{{ else if UI == "Blazor" }}
{{ if Tiered == "No" }}- `Acme.BookStore.HttpApi.Host`{{ end }}
- `Acme.BookStore.Blazor`
{{ else if UI == "BlazorServer" }}
{{ else if UI == "BlazorServer" || UI == "BlazorWebApp" }}
- `Acme.BookStore.Blazor`
{{ else }}
- `Acme.BookStore.Web`
@ -174,7 +174,7 @@ You can start the following application(s):
> Notice that the services running in docker-compose are exposed to your localhost. If any service in your localhost is already using the same port(s), you will get an error. In that case, stop your local services first.
{{ end }}
Once the `Acme.BookStore.{{ if UI == "NG" }}Angular{{ else if UI == "BlazorServer" || UI == "Blazor" }}Blazor{{ else }}Web{{ end }}` application started, you can right-click it and select the *Browse* command:
Once the `Acme.BookStore.{{ if UI == "NG" }}Angular{{ else if UI == "BlazorServer" || UI == "Blazor" || UI == "BlazorWebApp" }}Blazor{{ else }}Web{{ end }}` application started, you can right-click it and select the *Browse* command:
![abp-studio-quick-start-browse-command](images/abp-studio-quick-start-browse-command.png)
@ -206,7 +206,7 @@ Once the solution is opened in Visual Studio, you should see a screen like shown
![visual-studio-bookstore-application](images/visual-studio-bookstore-application.png)
Right-click the `Acme.BookStore.{{ if UI == "NG" || UI == "Blazor" }}HttpApi.Host{{ else if UI == "BlazorServer" }}Blazor{{ else }}Web{{ end }}` project and select the *Set as Startup Project* command. You can then hit *F5* or *Ctrl + F5* to run the web application. It will run and open the application UI in your default browser:
Right-click the `Acme.BookStore.{{ if UI == "NG" || UI == "Blazor" }}HttpApi.Host{{ else if UI == "BlazorServer" || UI == "BlazorWebApp" }}Blazor{{ else }}Web{{ end }}` project and select the *Set as Startup Project* command. You can then hit *F5* or *Ctrl + F5* to run the web application. It will run and open the application UI in your default browser:
![bookstore-browser-users-page](images/bookstore-browser-users-page.png)
@ -242,4 +242,4 @@ Before starting the mobile application, ensure that you configure it for [react-
> For example in non-tiered MVC with public website application:
![solution-runner-public-website](images/solution-runner-public-website.png)
![solution-runner-public-website](images/solution-runner-public-website.png)

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

@ -73,11 +73,11 @@ Click the Next button to see *Additional Options* selection:
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:
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:
![abp-studio-created-new-microservice-solution](images/abp-studio-created-new-microservice-solution.png)
You can explore the solution, but you need to wait for background tasks to be completed before running any application in the solution (it can take up to a few minutes to set up all).
You can explore the solution, but you need to **wait for background tasks to be completed** before running any application in the solution (it can take up to a few minutes to set up all).
> The solution structure can be different in your case based on the options you've selected.
@ -123,9 +123,7 @@ In the *Solution Runner* section (on the left side) you can see all the runnable
![abp-studio-microservice-solution-runner-applications](images/abp-studio-microservice-solution-runner-applications.png)
> All the leaf items in the *Solution Runner* is called as an *Application* as they are executable applications.
> For a faster start process, first start the *Docker-Dependencies*, then you can start all applications.
> A leaf item in the *Solution Runner* is called as an *Application* as it is an executable application.
As shown in the figure above, the executable applications are grouped into folders like `apps`, `gateways`, `infrastructure`, and `services`. You can start/stop them all, a group (folder) of them, or one by one.
@ -135,16 +133,14 @@ Before running the applications, it is good to be sure that all applications are
> *Solution Runner* doesn't build an application before running it. That provides a great performance gain because most of the time you will work on one or a few services and you don't need to build all of the other applications in every run. However, if you want to build before running, you can right-click an item in the *Solution Runner* tree and select *Run* -> *Build & Start* command.
It will take some time to build all. Once all is done, you can start the system.
You can click the *Play* button on the root item in Solution Runner to start all the applications. Or you can start `Docker-Dependencies` first, so the database and other infrastructure services get ready before the other applications:
![abp-studio-microservice-solution-runner-docker-dependencies](images/abp-studio-microservice-solution-runner-docker-dependencies.png)
It will take some time to build all. Once all is done, you can start the system. You can click the *Play* button on the root item in Solution Runner to start all the applications.
> **About the Docker Containers**
>
> Docker will fetch the docker images before starting the containers in your first run (if they were not fetched before) and that process may take a few minutes depending on your internet connection speed. So, please wait for it to completely start. If the process takes more time than you expect, you can right-click on `Docker-Dependencies` and select the *Logs* command to see what's happening.
Once `Docker-Dependencies` is ready, you can click the *Play* button on the root item in Solution Runner to start all the applications.
> **About Failing Services on Startup**
>
> Some applications/services may fail on the first run. That may be because of service and database dependencies were not satisfied and an error occurs on the application startup. ABP Studio automatically restarts failing services until it is successfully started. Being completely ready for such a distributed solution may take a while, but it will be eventually started.
Once all the applications are ready, you can right-click the `Web` application and select the *Browse* command:
@ -222,6 +218,8 @@ Once the solution is ready in Kubernetes, you can open a browser and visit the f
![abp-studio-microservice-web-application-home-page](images/abp-studio-microservice-web-application-home-page.png)
> We could use `cloudcrm-local-web` as the host name since ABP Studio has added an entry to the host file for us.
Click the *Login* link in the application UI, it will redirect you to the *Authentication Server* application, enter `admin` as username and `1q2w3E*` as password to login to the application.
> The services run independently from each other and perform some initial data seed logic on their startups. So, they may fail in their first run. In that case, Kubernetes will re-start them. So, it may initially get some time to make the solution fully ready and working.
@ -248,11 +246,11 @@ Clicking the *Connect* button will start a process that establishes the VPN conn
![abp-studio-microservice-kubernetes-services](images/abp-studio-microservice-kubernetes-services.png)
Now, you can access all the services inside the Kubernetes cluster, including the services those are not exposes out of the cluster. You can use the service name as DNS. For example, you can directly visit `http://cloudcrm-local-identity` in your Browser. You can also right-click to a service or application and select the Browse command to open it's UI in the built-in browser of ABP Studio:
Now, you can access all the services inside the Kubernetes cluster, including the services those are not exposed out of the cluster. You can use the service name as DNS. For example, you can directly visit `http://cloudcrm-local-identity` in your Browser. You can also right-click to a service or application and select the Browse command to open it's UI in the built-in browser of ABP Studio:
![abp-studio-microservice-kubernetes-services-browse](images/abp-studio-microservice-kubernetes-services-browse.png)
You can even use the other services (e.g. SQL Server or RabbitMQ) from your local computer (even if they were not exposed out of cluster) with their service names. `sa` password for the SQL server is `myPassw@rd` by default, you can use your SQL Server management studio to connect to it and see the databases:
You can even use the other services (e.g. SQL Server or RabbitMQ) from your local computer (even if they were not exposed out of cluster) with their service names. `sa` password for the SQL server is `myPassw@rd` by default, you can use your SQL Server management studio to connect to it and see the databases (*Server name* is `cloudcrm-local-sqlserver`):
![abp-studio-microservice-sql-server-connection](images/abp-studio-microservice-sql-server-connection.png)
@ -266,6 +264,8 @@ When you connect to Kubernetes, ABP Studio automatically connects to the applica
In this way, you can easily track HTTP requests, distributed events, exceptions, logs and other details of your applications.
> If you want to browse a web application in the integrated browser of ABP Studio, right-click to a service in the *Kubernetes* tab of the *Kubernetes* panel and select the *Browse* command.
## Kubernetes Integration: Intercepting Services
The next step is to intercept a service to forward the traffic (coming to that service) to your local computer, so you can run the same service in your local computer to test, debug and develop it. This is the way of connecting two environments (your local machine and the Kubernetes cluster) to develop your services integrated to Kubernetes.
@ -306,3 +306,7 @@ To re-deploy a service to Kubernetes, right-click the service and select *Comman
![abp-studio-microservice-kubernetes-redeploy](images/abp-studio-microservice-kubernetes-redeploy.png)
ABP Studio will re-build the Docker image and re-install it using the related Helm chart.
## See Also
* [Microservice Development Tutorial](../tutorials/microservice/index.md)

8
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
{
@ -301,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
@ -367,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
{

2
docs/en/modules/openiddict.md

@ -279,7 +279,7 @@ UserInfoController -> connect/userinfo
> **Device flow** implementation will be done in the commercial module.
#### AbpOpenIddictAspNetCoreOptions
### AbpOpenIddictAspNetCoreOptions
`AbpOpenIddictAspNetCoreOptions` can be configured in the `PreConfigureServices` method of your OpenIddict [module](../framework/architecture/modularity/basics.md).

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

@ -57,6 +57,24 @@ In this version, we have started updating entities' `EntityVersion`, `Modificati
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.

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

@ -4,11 +4,9 @@ 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)
## 9.0 (2024-11-19)
> 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.
See the detailed **[blog post / announcement](https://abp.io/blog/abp-9-0-stable-release-with-dotnet-9-0)** for the v9.0 release.
* Upgraded to .NET 9.0
* Introducing the `Extension Property Policy`

4
docs/en/release-info/upgrading.md

@ -20,7 +20,7 @@ Run this command in the terminal while you are in the root folder of your soluti
When you upgrade to a new version, it is good to check if there is a database schema change and upgrade your database schema if your database provider is **Entity Framework Core**;
* Use `Add-Migration "Upgraded_To_Abp_8_2"` or a similar command in the Package Manager Console (PMC) to create a new migration (Set the `EntityFrameworkCore` as the Default project in the PMC and `.DbMigrator` as the Startup Project in the Solution Explorer, in the Visual Studio).
* Use `Add-Migration "Upgraded_To_Abp_8_3"` or a similar command in the Package Manager Console (PMC) to create a new migration (Set the `EntityFrameworkCore` as the Default project in the PMC and `.DbMigrator` as the Startup Project in the Solution Explorer, in the Visual Studio).
* Apply the database migrations to your database. If available, you can run the `.DbMigrator` application to upgrade the database and seed the initial data.
> If `Add-Migration` generates an empty migration (that means no schema change), you can use `Remove-Migration` to delete it before executing the `.DbMigrator`.
@ -57,4 +57,4 @@ Preview releases and nightly builds can help you to try new features and adapt y
## See Also
* [Migration Guides](migration-guides)
* [Migration Guides](migration-guides)

184
docs/en/solution-templates/guide.md

@ -0,0 +1,184 @@
# Solution Templates: A Guide to Select the Right One For You
ABP provides several [startup templates](index.md) to you. It is important to start with the right startup template that is suitable for your **project** and **team**. This guide aims to lead you to select the most proper startup template for your requirements.
The following **architectures** will be discussed based on ABP startup templates:
* **Single-Layer** (non-layered) application
* **N-Layered** application
* **Modular** application
* **Microservice** solution
## What is a Startup Template?
In the following section, you will understand what a startup template is and what it provides.
### Pre-Architected Solution Structure
A startup solution template is a **pre-architected** structure. For example, the [layered startup template](layered-web-application/index.md) is a great starting point if you want to build a layered application code-base based on [Domain-Driven Design](../framework/architecture/domain-driven-design/index.md) principles and patterns.
However, starting with any startup template **doesn't limit you** on adding or removing projects, layers, integration packages, and creating other applications/services. You can even start with a [single-layer application template]() and convert it to a microservice solution. However, if you want to build a microservice solution, starting with the [microservice startup template](microservice/index.md) is the best.
So, it is **best to start with the most suitable startup template** for your purpose and then modify the solution to fit your custom requirements.
### Well-Structured Code Organization
Besides the overall solution structure, the internals of each project in a solution template are well-structured. It is clear where will you place your [entities](../framework/architecture/domain-driven-design/entities.md), [repositories](../framework/architecture/domain-driven-design/repositories.md), [data access code](../framework/data/index.md), [application services](../framework/architecture/domain-driven-design/application-services.md), [API controllers](../framework/api-development/index.md), [UI elements](../framework/ui/index.md), etc. You don't spend time thinking about how to **organize your codebase** in every new project. If you prefer to build automated tests for your application, the test projects are also included and pre-configured.
### Library Integrations & Configurations
When you use ABP startup solution templates to create a new solution, some **fundamental library installations** ([Serilog](https://serilog.net/), [Autofac](https://autofac.org/), [AutoMapper](https://automapper.org/), [Swagger](https://swagger.io/), [HealthCheck](https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks) and others..) and their fine-tuned configurations are already prepared for you. Also, required **[ABP packages](https://abp.io/packages)** are just installed based on your preferences and configured for **development and production environments**.
### Development Ready
When you create a new solution, or when a new teammate starts to work on your existing solution, it is pretty **easy to understand** the solution structure, design decisions and the development flow by the help of [solution structure documents](index.md) and [development tutorials](../tutorials/index.md).
### Production Ready
ABP's startup templates are ready for production out of the box. You can just create a new solution and **deploy it** to your production environment. It is not only about **technical readiness**, but also about **functional readiness**.
When you create a new ABP solution, **fundamental modules are already installed**. Your application has a robust [account module](../modules/account.md) (user registration, login, social logins, 2-factor authentication, user lockout, password complexity control...), an advanced [identity module](../modules/identity.md) (user, role and permission management), and many other production-ready [pre-built application modules](../modules/index.md) are just working as a part your application in the first day.
## The Startup Solution Templates
Up to this point, it is explained what a startup template is and the features it offers. In the following section, you will see the types of startup solution templates and **which one is best for you**.
### Single-Layer Application Solution Template
The [single-layer solution template](single-layer-web-application/index.md) is the simplest. It provides a **minimal solution architecture** while starting a new project. Your .NET solution typically contains a **single, or a few .NET projects** depending on your UI and other preferences while creating your solution.
The following figure shows a single-project web application that has [MVC (Razor Pages) UI](../framework/ui/mvc-razor-pages/overall.md) and [Entity Framework Core](../framework/data/entity-framework-core/index.md) database provider with the default configuration:
![single-layer-abp-solution](images/single-layer-abp-solution.png)
As you see in the preceding figure, all the application code (entities, data access, services, UI pages, etc.) are located in a **single .NET project**.
#### When Should You Start a Single-Layer Solution Template?
In the following conditions, you may consider to use the single-layer solution template:
* If **your project is small** and you don't expect that it will grow by the time. But remember that many projects are thought of as small in the beginning.
* If your project is a **temporary project** and it will be trash in a short time. It can be a POC project or a temporary application for a demo or advertisement campaign.
* If you are a **single developer** or there are only 2-3 developers working on your solution, and these developers are not experienced and are not willing to understand the structure and benefits of a layered application.
If the preceding conditions are met with your case, you can consider starting with this solution template.
However, keep in mind that your solution can quickly become a **[big ball of mud](https://thedomaindrivendesign.io/big-ball-of-mud/)**.
We think that only a **very small portion of applications** are suitable for that kind of solution structure.
Note that the single-layer solution template doesn't provide the following options/features:
* Mobile application integration
* Public website (a second web application for landing page of your product)
* Tiered architecture (for MVC applications, separates UI and service layers)
* Separate tenant schema (for multi-tenant applications)
* Kubernetes / Helm configuration
* Automated (unit/integration) test projects
These options are not implemented to keep the solution structure as simple as possible. If you need some of these, please feel free to use the layered solution template.
### Layered Solution Template
The [layered application startup template](layered-web-application/index.md) is a .NET solution that consists of several projects.
Each project represents a layer of the application or has a specific functionality for the solution.
The exact project count in your solution depends on the options you have selected.
The following figure shows a solution with [MVC (Razor Pages) UI](../framework/ui/mvc-razor-pages/overall.md) and [Entity Framework Core](../framework/data/entity-framework-core/index.md) database provider with the default configuration:
![layered-abp-application](images/layered-abp-application.png)
The solution is layered based on Domain-Driven Design principles and extended based on real-world business application requirements. It includes test projects for each layer. Layering the solution has great benefits:
* It makes your business code (domain & application layers) independent from infrastructure (UI and database) that makes it more **maintainable and long-living**.
* Different developers can **focus on different layers**. It is valuable when multiple developers (with different roles) touching to the same solution.
* It **separate concerns**, so you can focus on a single concern at a time. You can optimize your data access code without touching other layers, you can change your UI code without breaking your business logic.
* It provides **maximum code reusability**. If you have multiple applications (e.g. one back office application, one end-user application, and a mobile application), it is easy to separate these application's codebases (simply create new application & UI layers for each application type) while they can share the same domain and data access layers.
* Separating **UI layer** gives an opportunity to **replace/modify** it in the future without affecting other parts of your solution. You know, UI is the fastest changing technology in software industry.
While it may seem a little complicated at the beginning, once you **complete the [Book Store tutorial](../tutorials/book-store/index.md)**, you will easily understand the purpose and usage of each project.
#### When Should You Start a Layered Solution Template?
In the following conditions, you may consider to use the layered solution template:
* If your project **code-base** is relatively **larger**.
* If your project is **relatively complex** and involves multiple business domains or complex workflows.
* If your project is a **long-term** project and you want to design it as **maintainable** for long years.
* If you are **a team of developers** working on your solution. When multiple teams or developers work on different parts of the system.
* If your solution will have **multiple** web, mobile or other type of **applications** that need to **share** the same business logic.
* If your project needs **scalability**, solutions that may need to scale in functionality or user load over time.
* If your project needs **extensibility**, which requires the addition of new features or integration with third-party services.
### Modular Monolith Applications
ABP does not provide a specific modular monolith application startup template. However, it is not needed. Let us explain why.
The ABP Framework and [ABP Studio](../studio/index.md) are already designed to support modular application development from their beginning. ABP framework provides all the **necessary infrastructure** for [modularity](../framework/architecture/modularity/basics.md) and all other framework features are **compatible with modular solutions**.
On the other hand, the main purpose of ABP Studio's [Solution Explorer panel](../studio/solution-explorer.md) is to **architect and build modular and complex software solutions**. You can easily create new modules, arrange dependencies between the modules and import/install these modules into a monolith application. While you can do all these manually yourself, ABP Studio makes it extremely easy to do and understand it.
#### How to Build a Modular Monolith Application?
A **modular monolith** application consists of a **single host** application and **multiple sub-modules**. Typically, each module has its own .NET solution that contains the code related to that module. So, the general structure is shown in the following figure:
![example-modular-solution](images/example-modular-solution.png)
In this example, `MyCrm.Host` is an almost-empty host application that has package references to other modules. Every module consists of two packages: implementation and contract packages.
You can follow the steps below to create such a modular solution with ABP Studio:
* **Create a new application** using either [single-layer](single-layer-web-application/index.md) or [layered](layered-web-application/index.md) application startup template. That application will be the **host application** of your solution.
* **Create new modules** (right-click to the solution root, select the *Add* -> *New Module* -> ... command).
* **Import & Install** these **modules** to the host application.
> You can follow the **[Modular Monolith Application Development Tutorial](../tutorials/modular-crm/index.md)** to learn how to build a modular application step by step.
#### Which Startup Template should be used for a Modular Application?
So, both [single-layer](single-layer-web-application/index.md) and [layered](layered-web-application/index.md) application startup templates are inherently modular. Just use one of them and start your modular solution. You may wonder which one to start:
* Use the **[single-layer startup template](single-layer-web-application/index.md)** for the host application of your modular monolith if you will leave the host application as empty. It will contain some configuration code of course, but it won't contain any actual application code. **This is the suggested approach.**
* Use the **[layered application startup template](layered-web-application/index.md)** if you will write some application code into the hosting application. You may want to write some code that makes multiple module operations that are not easy to implement in a particular module. In that case, a layered hosting application will be a better way to organize your codebase. However, this approach can quickly move your solution away from a modular system. So, take your own risk.
#### When Should You Start a Modular Monolith Application?
In the following conditions, you may consider to build a modular software solution:
* If your **domain is too complex** to develop and maintain in a single monolith codebase.
* If your business domain has clear functional boundaries and is possible to **split into sub-domains**.
* If you have **multiple teams** that will work on the solution.
* When you need to **reduce complexity** early on. And if you are considering migrating your application to a **microservice system**.
While all these are also suitable for microservice solutions (which will be discussed in the next section), a modular solution is more suitable than microservices for most of the projects.
Especially if you don't need to have technology diversity, deploy and scale services independently and serve too many users concurrently with a fault-tolerant system, a modular monolith application would be a better choice to not deal with the complexity of a microservice system. Also, it is better to start with a thin architecture when you have a small team that can focus on building features without spending time managing distributed architecture complexities. Another advantage is that the modular monoliths avoid the network latency and communication overhead inherent in microservices, so debugging and monitoring are easier as all modules run within a single application. In summary, if you anticipate that your application may grow to require a microservices architecture in the future, a modular monolith is a great starting point.
> Build for Now, Scale for Tomorrow
Even if you are considering building a microservice architecture, it is usually advised to [start with a monolith modular first](https://martinfowler.com/bliki/MonolithFirst.html), then migrate to microservices later once your business and module boundaries are more stable.
### Microservice Solution Template
ABP's [microservice startup template](microservice/index.md) includes multiple services, API gateways and applications that are well integrated into each other and ready to be a great **base solution for your microservice system**.
In the following picture, you can see an overall diagram that shows the main components of the solution (they vary based on the options while you are creating your solution):
![ms-overall-architecture](microservice/images/overall-architecture.png)
#### When Should You Start a Microservice Solution Template?
In the following conditions, you may consider to build a microservice system:
* If your **domain is too complex** to develop and maintain in a single monolith codebase.
* If your business domain is possible to **split into sub-domains**.
* If you have **multiple teams** that will work on the solution in parallel.
* If you need to **develop**, **test**, **deploy** and **scale services** independently.
* If you need to use **multiple technology stacks** so, some services can be built with .NET, and others can be built with Java, Python, etc...
* If you need to serve **too many users** concurrently with a **high available** and **fault tolerant** system.
* If you have **DevOps** knowledge and culture in your company. If you can deal with **complex** development, build, test, deployment and production environments.
**Use Case Examples**
* **E-Commerce Platforms**: Separate services for cart, checkout, inventory, and shipping.
* **Streaming Services**: Modules for content delivery, user preferences, and recommendations.
* **SaaS Platforms**: Independent services for billing, user accounts, and analytics.
## Conclusion
In summary, the ABP Platform offers a variety of solution templates tailored to different architectural needs, including layered applications, microservices, and modular development. These templates provide a great foundation for building robust applications by implementing best practices and providing essential features. By selecting the right template, you can streamline the development process, ensuring scalability and maintainability in your project.

BIN
docs/en/solution-templates/images/example-modular-solution.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

BIN
docs/en/solution-templates/images/layered-abp-application.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
docs/en/solution-templates/images/single-layer-abp-solution.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

21
docs/en/solution-templates/index.md

@ -1,12 +1,21 @@
# Solution Templates
ABP provides pre-architected and production-ready templates to jump start a new solution. The following solution templates are provided out of the box:
ABP provides pre-architected and production-ready templates to jump start a new solution.
* **[Single-Layer Solution](single-layer-web-application)**: A single-project solution. Recommended for building an application with a **simpler and easy to understand** architecture.
* **[Layered Solution](layered-web-application)**: A fully layered (multiple projects) solution based on [Domain Driven Design](../framework/architecture/domain-driven-design) practices. Recommended for long-term projects that need a **maintainable and extensible** codebase.
* **[Microservice Solution](microservice)**: A **distributed solution** to build **microservice systems**. It includes pre-built services, API gateways, web and mobile applications, Kubernetes and Helm configuration, and everything you need to start your large-scale microservice solution.
* **[Application Module](application-module)**: A template that can be used to create a **reusable [application module](../modules)** based on the [module development best practices & conventions](../framework/architecture/best-practices). It is also suitable for creating **services** (with or without UI).
> **You can see the [Solution Template Selection Guide](guide.md) if you are not sure which solution template is suitable for you.**
The following solution templates are provided out of the box:
* **[Single-Layer Solution](single-layer-web-application/index.md)**: A single-project solution. Recommended for building an application with a **simpler and easy to understand** architecture.
* **[Layered Solution](layered-web-application/index.md)**: A fully layered (multiple projects) solution based on [Domain Driven Design](../framework/architecture/domain-driven-design) practices. Recommended for long-term projects that need a **maintainable and extensible** codebase.
* **[Microservice Solution](microservice/index.md)**: A **distributed solution** to build **microservice systems**. It includes pre-built services, API gateways, web and mobile applications, Kubernetes and Helm configuration, and everything you need to start your large-scale microservice solution.
* **[Application Module](application-module/index.md)**: A template that can be used to create a **reusable [application module](../modules/index.md)** based on the [module development best practices & conventions](../framework/architecture/best-practices/index.md). It is also suitable for creating **services** (with or without UI).
* **Others**
- [MAUI Application](../get-started/maui.md)
- [WPF Application](../get-started/wpf.md)
- [Console Application](../get-started/console.md)
- [Console Application](../get-started/console.md)
## See Also
* [Solution Template Selection Guide](guide.md)
* [Get Started with ABP Platform](../get-started/index.md)

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

@ -254,6 +254,37 @@ 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)

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

@ -1,9 +1,9 @@
# Layered Application Solution Template
## Introduction
This template provides a layered application structure based on the [Domain Driven Design](../../framework/architecture/domain-driven-design) (DDD) practices.
## Getting Started
This document explains **the solution structure** and projects in details. If you want to start quickly, follow the guides below:
* [The getting started document](../../get-started/layered-web-application.md) explains how to create a new application in a few minutes.
@ -68,7 +68,8 @@ Use the `-m` (or `--mobile`) option to specify the mobile application framework:
abp new Acme.BookStore -m react-native
````
If not specified, no mobile application will be created.
* [The getting started document](../../get-started/layered-web-application.md) explains how to create a new application with this startup template.
* [The application development tutorial](../../tutorials/book-store/part-01.md) explains step by step application development with this startup template.
## Solution Structure

BIN
docs/en/solution-templates/microservice/images/enable-dynamic-localization.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
docs/en/solution-templates/microservice/images/ui-localization-mvc.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

114
docs/en/solution-templates/microservice/localization-system.md

@ -18,12 +18,124 @@ Like the other fundamental feature modules ([Permission Management](permission-m
## Language Management
> If the dynamic localization option is enabled, then the *Language Management Module** will be removed from the optional modules and a new microservice named `LanguageService` will be created. The `LanguageService` uses *Language Management Module* behind the scene.
The *Administration* microservice provides a set of APIs to manage localization. The localization resources are defined in each microservice, and when a microservice starts, it registers its localization resources to the related localization tables automatically. After that, you can see the localization resources from the [language texts](../../modules/language-management.md#language-texts) and manage them.
![language-texts](images/language-management-language-texts-page.png)
> The *Language Management* module is optional. If you don't need to manage localization resources from the UI, you can uncheck the *Language Management* module while creating the solution. However, each microservice's localization resources are still registered to the database and can be used by the applications.
## Dynamic Localization
When you create a new microservice solution, you can **enable dynamic localization** option, which allows you to add/remove languages and change localization texts on the application UI:
![](./images/enable-dynamic-localization.png)
When you enable this option, a new microservice named **LanguageService** will be added (with the language management module integrated) and you can use its `LanguageServiceResource` class to use the localization entries in your UI application. It's already configured in your final host application, so you don't need to make any configuration related to that. To define a new localization entry you can either use the language files in the `LanguageService` or update the already defined localization entries in the UI (on the *Language Texts* page).
After defining localization entries or updating them, you can inject the `IStringLocalizer<>` or `IHtmlLocalizer<>` services and use the localized values in your pages for MVC/Razor Pages UI, for instance:
```html
@page
@using Microsoft.Extensions.Localization
@inject IStringLocalizer<MyProjectNameWebResource> L
<div>
<h1>@L["LongWelcomeMessage"]</h1>
</div>
```
## UI Localizations
In the microservice architecture, localizations also can be defined in the final host application, if they only need to be defined in the UI. When you create a new microservice solution template, independent from the UI, all configurations are made and you can directly define localization entries and use them in your final UI application.
> **Note:** When you define localization entries in the host application, then you can't make dynamic localization with the language management module! (Because the language management module, would be unaware of the defined localization entries on the UI side)
### MVC/Razor Pages & Blazor UIs
For MVC & Blazor UIs, you can see the **Localization** directory in your final application, like in the following figure:
![](./images/ui-localization-mvc.png)
In this directory, you can see the language files, those are pre-defined for you to directly add localization entries. The related configurations are already made for you, in the module class (inside the `ConfigureLocalization` method) as below:
```csharp
private void ConfigureLocalization(IWebHostEnvironment hostingEnvironment)
{
//code abbreviated for brevity...
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<CloudCrmWebResource>("en")
.AddVirtualJson("/Localization/CloudCrmWeb");
options.DefaultResourceType = typeof(CloudCrmWebResource);
});
}
```
You can define new localization entries in the language files under the **Localization** folder and directly use them in your application by using the `IStringLocalizer<>` or `IHtmlLocalizer<>` services:
```html
@page
@using Microsoft.Extensions.Localization
@inject IStringLocalizer<CloudCrmWebResource> L
<div>
<h1>@L["LongWelcomeMessage"]</h1>
</div>
```
### Angular UI
Angular UI gets the localization resources from the [`application-localization`](../../framework/api-development/standard-apis/localization.md) API's response and merges these resources in the `ConfigStateService` for the localization entries/resources coming from the backend side.
In addition, you may need to define some localization entries and only use them on the UI side. ABP already provides the related configuration for you, so you don't need to make any configurations related to that and instead you can directly define localization entries in the `app.-module.ts` file of your angular application as follows:
```ts
import { provideAbpCore, withOptions } from '@abp/ng.core';
@NgModule({
providers: [
// ...
provideAbpCore(
withOptions({
environment,
registerLocaleFn: registerLocale(),
localizations: [
{
culture: 'en',
resources: [
{
resourceName: 'MyProjectName',
texts: {
"LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information visit"
}
}
]
}
]
}),
),
...
],
})
export class AppModule {}
```
After defining the localization entries, it can be used as below:
{%{
```html
<div>{{ 'MyProjectName::LongWelcomePage' | abpLocalization }}</div>
```
}%}
> For more information, please refer to [UI Localization section of the Angular Localization document](../../framework/ui/angular/localization.md).
## Creating a New Localization Resource
To create a new localization resource, you can create a class named *MicroservicenameResource* in the *Contracts* project for the related microservice, which is already created by the solution template. For example, the *Identity* microservice has an *IdentityServiceResource* class and localization JSON files.
@ -61,4 +173,4 @@ public override void ConfigureServices(ServiceConfigurationContext context)
}
```
> Existing microservices in the solution don't contain the localization text. These localization resources are defined in their own modules. You can add new localization resources to the existing microservices by following the steps above.
> Existing microservices in the solution don't contain the localization text. These localization resources are defined in their own modules. You can add new localization resources to the existing microservices by following the steps above.

61
docs/en/solution-templates/single-layer-web-application/index.md

@ -1,66 +1,15 @@
# Single Layer Application Solution Template
## Introduction
This template provides a simple solution structure with a single project. This document explains that solution structure in details.
### The Difference Between the Application Solution Templates
ABP's [Layered Application Solution Template](../layered-web-application) provides a well-organized and layered solution to create maintainable business applications based on the [Domain Driven Design](../../framework/architecture/domain-driven-design) (DDD) practices. However, some developers find this template a little bit complex for simple and short-term applications. The single-layer application template has been created to provide a simpler development model for such applications. This template has the same functionality, features and modules on runtime with the [Layered Application Solution Template](../layered-web-application) but the development model is minimal and everything is in a single project (`.csproj`).
## How to Start with It?
You can use the [ABP CLI](../../cli) to create a new project using this startup template. Alternatively, you can generate a CLI command for this startup template from the [Get Started](https://abp.io/get-started) page. In this section, we will use the ABP CLI.
Firstly, install the ABP CLI if you haven't installed it before:
```bash
dotnet tool install -g Volo.Abp.Studio.Cli
```
Then, use the `abp new` command in an empty folder to create a new solution:
```bash
abp new Acme.BookStore -t app-nolayers
```
* `Acme.BookStore` is the solution name, like *YourCompany.YourProduct*. You can use single-level, two-level or three-level naming.
* In this example, the `-t` (or `--template`) option specifies the template name.
### Specify the UI Framework
## Getting Started
This template provides multiple UI frameworks:
* `mvc`: ASP.NET Core MVC UI with Razor Pages (default)
* `blazor`: Blazor UI
* `blazor-server`: Blazor Server UI
* `angular`: Angular UI
* `none`: Without UI (for HTTP API development)
Use the `-u` (or `--ui`) option to specify the UI framework while creating the solution:
```bash
abp new Acme.BookStore -t app-nolayers -u angular
```
This example specifies the UI type (the `-u` option) as `angular`. You can also specify `mvc`, `blazor`, `blazor-server` or `none` for the UI type.
### Specify the Database Provider
This template supports the following database providers:
- `ef`: Entity Framework Core (default)
- `mongodb`: MongoDB
Use the `-d` (or `--database-provider`) option to specify the database provider while creating the solution:
```bash
abp new Acme.BookStore -t app-nolayers -d mongodb
```
* Follow the [Getting Started guide](../../get-started/single-layer-web-application.md) to create a new solution using this startup solution template.
* Follow the [TODO application tutorial](../../tutorials/todo/single-layer/index.md) to learn how to create a simple application with this startup solution template.
## Solution Structure
## The Solution Structure
If you don't specify any additional options while creating an `app-nolayers` template, you will have a solution as shown below:
If you created your solution with the default options, you will have a .NET solution as shown below:
![](../../images/bookstore-single-layer-solution-structure.png)

76
docs/en/studio/release-notes.md

@ -2,13 +2,81 @@
This document contains **brief release notes** for each ABP Studio release. Release notes only include **major features** and **visible enhancements**. Therefore, they don't include all the development done in the related version.
## 0.9.13 (2024-11-25)
* Angular - Theme-based Fixes for the Home Page.
## 0.9.12 (2024-11-25)
* Handled the `DynamicPermissionDefinitionsChangedEto` event to automatically add permissions for the admin role.
* Enhanced the Solution Configuration window with a more intuitive design and updated content.
* Improved MAUI application support by displaying all target frameworks in the Solution Runner and automatically setting the appropriate targetFramework based on the operating system.
## 0.9.11 (2024-11-21)
* Fixed the extension loading problem occured in v0.9.9 & v0.9.10.
## 0.9.10 (2024-11-21)
> Recommended to use v0.9.11+ for .NET 9.
* Added shortcut for Build & Start operation (CTRL + Click)
* Fixed extension loading loop problem in v0.9.9
* Fixed MAUI template for android
## 0.9.9 (2024-11-21)
> Recommended to use v0.9.11+ for .NET 9.
* Upgraded templates to .NET 9
* Fixed blazor wasm bundle problem in microservice template
## 0.9.8 (2024-11-20)
* Upgraded templates to version `8.3.4`
## 0.9.7 (2024-11-19)
* Added `AppearanceStyles` component to blazor server templates
* Fixed module import window
* Made several enhancements to the existing features
## 0.9.6 (2024-11-15)
* Added missing imports to templates
* Fixed bugs during EF Core package installation
* Show errors to the user when adding a database migration
* Changed empty solution description on create new solution wizard
* Fixed problems with templates created with Basic Theme
* Ensure the correct version is used when adding a new module/package to an existing solution
## 0.9.5 (2024-11-06)
* Added dynamic localization option to microservice template
* Added new template creation options for the Application (No Layers)
* Fixed the environment variable setting for .NET global tool and verification of tool installation
* Fixed log view auto-scrolling issue, ensuring smooth scrolling experience
* Upgraded templates to version `8.3.3`
## 0.9.4 (2024-10-31)
* Made the `TopMenuLayout` as the default layout type for microservice public website
* Fixed application crashing problem when the ABP Suite is opened
## 0.9.3 (2024-10-30)
* Added the **standard module template**
* Made enhancements on the pre-integrated browser
* Fixed Blazor WebAssembly UI being not run on kubernetes problem
* Added a database migration after a module added to the solution
## 0.9.2 (2024-10-22)
* Added "Sample CRUD Page" option for pro templates
* Generated *Signing-Certificate* for appnolayers template
* Added a status bar to the pre-integrated browser for showing errors
* Added **Sample CRUD Page** option to pro templates
* Added test projects optionally for all templates
* Added automapper configuration to apps/web project for ms template
* Disabled *transaction* for `MongoDB` and `SQLite` by default
* Added **AutoMapper** configurations to microservice host projects
* Disabled **transaction** for *MongoDB* & *SQLite* by default.
## 0.9.1 (2024-10-10)

2
docs/en/studio/running-applications.md

@ -187,6 +187,8 @@ We have several options in C# applications. Those options are `Start`(If the app
> When *Watch* is enable you should see an *eye* icon next to the application name.
> Hint: Performing CTRL+Click on the start icon left to a stopped C# application equals to `Build & Start` command. Same applies for folders.
![csharp-application-context-menu-run-connection](images/solution-runner/csharp-application-context-menu-run-connection.png)
### Build

19
docs/en/studio/version-compatibility.md

@ -1,19 +0,0 @@
# ABP Studio and ABP Solution Templates Version Compatibility
This document provides an overview of the compatibility between various versions of ABP Studio and [ABP Solution Templates](../solution-templates/index.md). Use this reference to ensure that you are using the correct versions of ABP Studio and ABP for your projects.
| **ABP Studio Version** | **ABP Version** |
|------------------------|---------------------------|
| 0.9.2 | 8.3.2 |
| 0.8.4 - 0.9.1 | 8.3.1 |
| 0.8.1 to 0.8.3 | 8.3.0 |
| 0.8.0 | 8.2.3 |
| 0.7.8 - 0.7.9 | 8.2.2 |
| 0.7.4 to 0.7.7 | 8.2.1 |
| 0.7.0 to 0.7.3 | 8.2.0 |
| 0.6.8 - 0.6.9 | 8.1.3 |
| 0.6.7 | 8.1.1 |
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:
![](images/abp-studio-switch-to-preview.png)

24
docs/en/studio/version-mapping.md

@ -0,0 +1,24 @@
# ABP Studio and ABP Startup Template Version Mappings
This document provides a general overview of the relationship between various versions of ABP Studio and the ABP version of the [ABP Solution Templates](../solution-templates/index.md) used when generating a new solution. Each version of ABP Studio is configured to create solutions with a specific ABP version. However, once a solution is created, you can easily update it to the latest version of ABP via ABP Studio or [ABP CLI](../cli/index.md#update).
| **ABP Studio Version** | **ABP Version of Startup Template** |
|------------------------|---------------------------|
| 0.9.9 to 0.9.13 | 9.0.0 |
| 0.9.8 | 8.3.4 |
| 0.9.5 to 0.9.7 | 8.3.3 |
| 0.9.2 to 0.9.4 | 8.3.2 |
| 0.8.4 - 0.9.1 | 8.3.1 |
| 0.8.1 to 0.8.3 | 8.3.0 |
| 0.8.0 | 8.2.3 |
| 0.7.8 - 0.7.9 | 8.2.2 |
| 0.7.4 to 0.7.7 | 8.2.1 |
| 0.7.0 to 0.7.3 | 8.2.0 |
| 0.6.8 - 0.6.9 | 8.1.3 |
| 0.6.7 | 8.1.1 |
# Working with ABP's Preview Versions
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:
![](images/abp-studio-switch-to-preview.png)

2
docs/en/suite/generating-crud-page.md

@ -273,7 +273,7 @@ Alternatively, you can add `IdentityUser` entity (or any other entity) as a navi
### New book dialog
###### ![New book dialog](../images/suite-ui-new-book.png)
### ![New book dialog](../images/suite-ui-new-book.png)
### Book list page

8
docs/en/tutorials/book-store/part-01.md

@ -2,7 +2,7 @@
````json
//[doc-params]
{
"UI": ["MVC","Blazor","BlazorServer","NG"],
"UI": ["MVC","Blazor","BlazorServer", "BlazorWebApp","NG"],
"DB": ["EF","Mongo"]
}
````
@ -36,7 +36,7 @@ abp install-libs
> We suggest you install [Yarn](https://classic.yarnpkg.com/) to prevent possible package inconsistencies, if you haven't installed it yet.
{{if UI=="Blazor" || UI=="BlazorServer"}}
{{if UI=="Blazor" || UI=="BlazorWebApp"}}
### Bundling and Minification
@ -440,7 +440,7 @@ ABP can [**automagically**](../../framework/api-development/auto-controllers.md)
### Swagger UI
The startup template is configured to run the [Swagger UI](https://swagger.io/tools/swagger-ui/) using the [Swashbuckle.AspNetCore](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) library. Run the application ({{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else}}`Acme.BookStore.HttpApi.Host`{{end}}) by pressing `CTRL+F5` and navigate to `https://localhost:<port>/swagger/` on your browser. Replace `<port>` with your own port number.
The startup template is configured to run the [Swagger UI](https://swagger.io/tools/swagger-ui/) using the [Swashbuckle.AspNetCore](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) library. Run the application ({{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer" || UI=="BlazorWebApp"}}`Acme.BookStore.Blazor`{{else}}`Acme.BookStore.HttpApi.Host`{{end}}) by pressing `CTRL+F5` and navigate to `https://localhost:<port>/swagger/` on your browser. Replace `<port>` with your own port number.
You will see some built-in service endpoints as well as the `Book` service and its REST-style endpoints:
@ -480,4 +480,4 @@ If you try to execute the `[GET] /api/app/book` API to get a list of books, the
}
````
That's pretty cool since we haven't written a single line of code to create the API controller, but now we have a fully working REST API!
That's pretty cool since we haven't written a single line of code to create the API controller, but now we have a fully working REST API!

10
docs/en/tutorials/book-store/part-02.md

@ -2,7 +2,7 @@
````json
//[doc-params]
{
"UI": ["MVC","Blazor","BlazorServer","NG"],
"UI": ["MVC","Blazor","BlazorServer", "BlazorWebApp", "NG"],
"DB": ["EF","Mongo"]
}
````
@ -514,13 +514,13 @@ Now you can see the final result on your browser:
![Book list final result](images/bookstore-book-list-angular.png)
{{else if UI == "Blazor" || UI == "BlazorServer"}}
{{else if UI == "Blazor" || UI == "BlazorServer" || UI == "BlazorWebApp"}}
## Create a Books Page
It's time to create something visible and usable! Right click on the `Pages` folder under the {{ if UI == "Blazor"}}`Acme.BookStore.Blazor.Client`{{ else }}`Acme.BookStore.Blazor`{{ end }} project and add a new **razor component**, named `Books.razor`:
It's time to create something visible and usable! Right click on the `Pages` folder under the {{ if UI == "BlazorServer" }}`Acme.BookStore.Blazor`{{ else }}`Acme.BookStore.Blazor.Client`{{ end }} project and add a new **razor component**, named `Books.razor`:
{{ if UI == "Blazor"}}
{{ if UI == "Blazor" || UI == "BlazorWebApp" }}
![blazor-add-books-component](images/blazor-add-books-component-client.png)
{{ else }}
![blazor-add-books-component](images/blazor-add-books-component.png)
@ -540,7 +540,7 @@ Replace the contents of this component as shown below:
### Add the Books Page to the Main Menu
Open the `BookStoreMenuContributor` class in the {{ if UI == "Blazor"}}`Acme.BookStore.Blazor.Client`{{ else }}`Acme.BookStore.Blazor`{{ end }} project add the following code to the end of the `ConfigureMainMenuAsync` method:
Open the `BookStoreMenuContributor` class in the {{ if UI == "BlazorServer"}}`Acme.BookStore.Blazor`{{ else }}`Acme.BookStore.Blazor.Client`{{ end }} project add the following code to the end of the `ConfigureMainMenuAsync` method:
````csharp
context.Menu.AddItem(

8
docs/en/tutorials/book-store/part-03.md

@ -2,7 +2,7 @@
````json
//[doc-params]
{
"UI": ["MVC","Blazor","BlazorServer","NG"],
"UI": ["MVC","Blazor","BlazorServer","BlazorWebApp","NG"],
"DB": ["EF","Mongo"]
}
````
@ -1101,7 +1101,7 @@ Clicking the "Delete" action calls the `delete` method which then shows a confir
{{end}}
{{if UI == "Blazor" || UI == "BlazorServer"}}
{{if UI == "Blazor" || UI == "BlazorServer" || UI == "BlazorWebApp"}}
## Creating a New Book
@ -1292,13 +1292,13 @@ We can now define a modal to edit the book. Add the following code to the end of
The base `AbpCrudPageBase` uses the [object to object mapping](../../framework/infrastructure/object-to-object-mapping.md) system to convert an incoming `BookDto` object to a `CreateUpdateBookDto` object. So, we need to define the mapping.
Open the `BookStoreBlazorAutoMapperProfile` inside the `Acme.BookStore.Blazor.Client` project and change the content as the following:
Open the `BookStoreBlazorAutoMapperProfile` inside the {{ if UI == "BlazorServer" }}`Acme.BookStore.Blazor`{{ else }}`Acme.BookStore.Blazor.Client`{{ end }} project and change the content as the following:
````csharp
using Acme.BookStore.Books;
using AutoMapper;
namespace Acme.BookStore.Blazor.Client;
{{ if UI == "BlazorServer" }}namespace Acme.BookStore.Blazor;{{ else }}namespace Acme.BookStore.Blazor.Client;{{ end }}
public class BookStoreBlazorAutoMapperProfile : Profile
{

2
docs/en/tutorials/book-store/part-04.md

@ -2,7 +2,7 @@
````json
//[doc-params]
{
"UI": ["MVC","Blazor","BlazorServer","NG"],
"UI": ["MVC","Blazor","BlazorServer","BlazorWebApp","NG"],
"DB": ["EF","Mongo"]
}
````

8
docs/en/tutorials/book-store/part-05.md

@ -2,7 +2,7 @@
````json
//[doc-params]
{
"UI": ["MVC","Blazor","BlazorServer","NG"],
"UI": ["MVC","Blazor","BlazorServer","BlazorWebApp","NG"],
"DB": ["EF","Mongo"]
}
````
@ -389,11 +389,11 @@ Open the `/src/app/book/book.component.html` file and replace the edit and delet
* Added `*abpPermission="'BookStore.Books.Edit'"` that hides the edit action if the current user has no editing permission.
* Added `*abpPermission="'BookStore.Books.Delete'"` that hides the delete action if the current user has no delete permission.
{{else if UI == "Blazor"}}
{{else if UI == "Blazor" || UI == "BlazorServer" || UI == "BlazorWebApp"}}
### Authorize the Razor Component
Open the `/Pages/Books.razor` file in the `Acme.BookStore.Blazor.Client` project and add an `Authorize` attribute just after the `@page` directive and the following namespace imports (`@using` lines), as shown below:
Open the `/Pages/Books.razor` file in the {{ if UI == "BlazorServer" }}`Acme.BookStore.Blazor`{{ else }}`Acme.BookStore.Blazor.Client`{{ end }} project and add an `Authorize` attribute just after the `@page` directive and the following namespace imports (`@using` lines), as shown below:
````html
@page "/books"
@ -479,7 +479,7 @@ You can run and test the permissions. Remove a book related permission from the
Even we have secured all the layers of the book management page, it is still visible on the main menu of the application. We should hide the menu item if the current user has no permission.
Open the `BookStoreMenuContributor` class in the `Acme.BookStore.Blazor.Client` project, find the code block below:
Open the `BookStoreMenuContributor` class in the {{ if UI == "BlazorServer" }}`Acme.BookStore.Blazor`{{ else }}`Acme.BookStore.Blazor.Client`{{ end }} project, find the code block below:
````csharp
context.Menu.AddItem(

2
docs/en/tutorials/book-store/part-06.md

@ -2,7 +2,7 @@
````json
//[doc-params]
{
"UI": ["MVC","Blazor","BlazorServer","NG"],
"UI": ["MVC","Blazor","BlazorServer", "BlazorWebApp", "NG"],
"DB": ["EF","Mongo"]
}
````

2
docs/en/tutorials/book-store/part-07.md

@ -2,7 +2,7 @@
````json
//[doc-params]
{
"UI": ["MVC","Blazor","BlazorServer","NG"],
"UI": ["MVC","Blazor","BlazorServer","BlazorWebApp","NG"],
"DB": ["EF","Mongo"]
}
````

2
docs/en/tutorials/book-store/part-08.md

@ -2,7 +2,7 @@
````json
//[doc-params]
{
"UI": ["MVC","Blazor","BlazorServer","NG"],
"UI": ["MVC","Blazor","BlazorServer","BlazorWebApp","NG"],
"DB": ["EF","Mongo"]
}
````

12
docs/en/tutorials/book-store/part-09.md

@ -2,7 +2,7 @@
````json
//[doc-params]
{
"UI": ["MVC","Blazor","BlazorServer","NG"],
"UI": ["MVC","Blazor","BlazorServer","BlazorWebApp","NG"],
"DB": ["EF","Mongo"]
}
````
@ -848,13 +848,13 @@ That's all! This is a fully working CRUD page, you can create, edit and delete a
{{end}}
{{if UI == "Blazor" || UI == "BlazorServer"}}
{{if UI == "Blazor" || UI == "BlazorServer" || UI == "BlazorWebApp"}}
## The Author Management Page
### Authors Razor Component
Create a new Razor Component Page, `/Pages/Authors.razor`, in the `Acme.BookStore.Blazor.Client` project with the following content:
Create a new Razor Component Page, `/Pages/Authors.razor`, in the {{ if UI == "BlazorServer" }}`Acme.BookStore.Blazor`{{ else }}`Acme.BookStore.Blazor.Client`{{ end }} project with the following content:
````xml
@page "/authors"
@ -1055,7 +1055,7 @@ using Blazorise.DataGrid;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;
namespace Acme.BookStore.Blazor.Client.Pages;
{{ if UI == "BlazorServer" }}namespace Acme.BookStore.Blazor.Pages;{{ else }}namespace Acme.BookStore.Blazor.Client.Pages;{{ end }}
public partial class Authors
{
@ -1201,7 +1201,7 @@ This class typically defines the properties and methods used by the `Authors.raz
`Authors` class uses the `IObjectMapper` in the `OpenEditAuthorModal` method. So, we need to define this mapping.
Open the `BookStoreBlazorAutoMapperProfile.cs` in the `Acme.BookStore.Blazor.Client` project and add the following mapping code in the constructor:
Open the `BookStoreBlazorAutoMapperProfile.cs` in the {{ if UI == "BlazorServer" }}`Acme.BookStore.Blazor`{{ else }}`Acme.BookStore.Blazor.Client`{{ end }} project and add the following mapping code in the constructor:
````csharp
CreateMap<AuthorDto, UpdateAuthorDto>();
@ -1211,7 +1211,7 @@ You will need to declare a `using Acme.BookStore.Authors;` statement to the begi
### Add to the Main Menu
Open the `BookStoreMenuContributor.cs` in the `Acme.BookStore.Blazor.Client` project and add the following code to the end of the `ConfigureMainMenuAsync` method:
Open the `BookStoreMenuContributor.cs` in the {{ if UI == "BlazorServer" }}`Acme.BookStore.Blazor`{{ else }}`Acme.BookStore.Blazor.Client`{{ end }} project and add the following code to the end of the `ConfigureMainMenuAsync` method:
````csharp
if (await context.IsGrantedAsync(BookStorePermissions.Authors.Default))

6
docs/en/tutorials/book-store/part-10.md

@ -2,7 +2,7 @@
````json
//[doc-params]
{
"UI": ["MVC","Blazor","BlazorServer","NG"],
"UI": ["MVC","Blazor","BlazorServer","BlazorWebApp","NG"],
"DB": ["EF","Mongo"]
}
````
@ -1071,11 +1071,11 @@ That's all. Just run the application and try to create or edit an author.
{{end}}
{{if UI == "Blazor" || UI == "BlazorServer"}}
{{if UI == "Blazor" || UI == "BlazorServer" || UI == "BlazorWebApp" }}
### The Book List
It is very easy to show the *Author Name* in the book list. Open the `/Pages/Books.razor` file in the `Acme.BookStore.Blazor.Client` project and add the following `DataGridColumn` definition just after the `Name` (book name) column:
It is very easy to show the *Author Name* in the book list. Open the `/Pages/Books.razor` file in the {{ if UI == "BlazorServer" }}`Acme.BookStore.Blazor`{{ else }}`Acme.BookStore.Blazor.Client`{{ end }} project and add the following `DataGridColumn` definition just after the `Name` (book name) column:
````xml
<DataGridColumn TItem="BookDto"

5
docs/en/tutorials/index.md

@ -3,5 +3,6 @@
The following introductory tutorials explain how to build applications based on the ABP platform:
* [TODO Application](todo/index.md): This is a single-part, quick-start tutorial to build a simple application with ABP. Start with this tutorial if you want to quickly understand how ABP works.
* [Book Store Application](book-store/index.md): This is a multi-part, complete tutorial to build a bookstore application with ABP. Start with this tutorial if you want to create a layered solution with ABP and apply DDD best practices.
* [Modular Monolith Application](modular-crm/index.md): This is a multi-part tutorial that demonstrates how to create application modules, compose and communicate them to build a monolith modular web application.
* [Book Store Application](book-store/index.md): A complete tutorial to build a bookstore application with ABP. Start with this tutorial if you want to create a layered solution with ABP and apply DDD best practices.
* [Modular Monolith Application](modular-crm/index.md): Demonstrates how to create application modules, compose and communicate them to build a monolith modular web application.
* [Microservice Solution](microservice/index.md): Explains how to build microservice solutions using ABP.

BIN
docs/en/tutorials/microservice/images/abp-studio-abp-suite-inside.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-command-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-command.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-dialog-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-dialog-additional-options-step.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-dialog-database-step.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-dialog-integration-step.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
docs/en/tutorials/microservice/images/abp-studio-add-new-microservice-dialog.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/en/tutorials/microservice/images/abp-studio-browse-catalog-service-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
docs/en/tutorials/microservice/images/abp-studio-browse-catalog-service.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
docs/en/tutorials/microservice/images/abp-studio-browse-cloud-crm-products.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
docs/en/tutorials/microservice/images/abp-studio-browse-ordering-service.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

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

Loading…
Cancel
Save