Browse Source

Merge branch 'dev' into openiddict6

pull/20979/head
maliming 2 years ago
parent
commit
7f3b6d2144
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 4
      .github/workflows/auto-pr.yml
  2. 6
      Directory.Packages.props
  3. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  4. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  5. BIN
      docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/community-talks.png
  6. BIN
      docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/cover-image.png
  7. 93
      docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/post.md
  8. BIN
      docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/switch-to-stable.png
  9. BIN
      docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/cover.png
  10. BIN
      docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/img2.png
  11. BIN
      docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/img3.png
  12. 108
      docs/en/Community-Articles/2024-11-13-BuiltIn-OpenApi-Documentation/post.md
  13. 202
      docs/en/Community-Articles/2024-11-14-Csharp-13-Features/Post.md
  14. 165
      docs/en/Community-Articles/2024-11-14-EF-Core-9-Linq-SQL-Translation/POST.md
  15. 385
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/POST.md
  16. BIN
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/chat-example.gif
  17. BIN
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/cover-image.png
  18. BIN
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/image-generation-example.gif
  19. BIN
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/rag-example-1.gif
  20. BIN
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/rag-example-2.gif
  21. BIN
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/sample-page.png
  22. 2
      docs/en/cli/index.md
  23. 73
      docs/en/cli/new-command-samples.md
  24. 84
      docs/en/deployment/forwarded-headers.md
  25. 1
      docs/en/deployment/index.md
  26. 66
      docs/en/docs-nav.json
  27. 1
      docs/en/docs-params.json
  28. 2
      docs/en/framework/fundamentals/dependency-injection.md
  29. 25
      docs/en/framework/infrastructure/event-bus/index.md
  30. 2
      docs/en/framework/ui/angular/quick-start.md
  31. 2
      docs/en/framework/ui/mvc-razor-pages/client-side-package-management.md
  32. 2
      docs/en/framework/ui/react-native/index.md
  33. BIN
      docs/en/get-started/images/abp-studio-microservice-solution-runner-docker-dependencies.png
  34. BIN
      docs/en/get-started/images/abp-studio-microservice-solution-runner-enable-watch-1.png
  35. BIN
      docs/en/get-started/images/abp-studio-microservice-solution-runner-enable-watch-2.png
  36. BIN
      docs/en/get-started/images/abp-studio-microservice-solution-runner-enable-watch.png
  37. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-additional-options-0.9.13.png
  38. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-0.9.13.png
  39. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-configurations-efcore-0.9.13.png
  40. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-configurations-mongo-0.9.13.png
  41. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-provider-efcore-0.9.13.png
  42. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-provider-mongo-0.9.13.png
  43. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-solution-properties-0.9.13.png
  44. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-0.9.13.png
  45. BIN
      docs/en/get-started/images/abp-studio-nolayers-new-solution-dialog-ui-theme-0.9.13.png
  46. 2
      docs/en/get-started/index.md
  47. 16
      docs/en/get-started/layered-web-application.md
  48. 40
      docs/en/get-started/microservice.md
  49. 28
      docs/en/get-started/single-layer-web-application.md
  50. BIN
      docs/en/images/generic-repositories.png
  51. BIN
      docs/en/images/idle-message.png
  52. BIN
      docs/en/images/idle-setting.png
  53. BIN
      docs/en/images/pen-test-alert-list-9.0.png
  54. 1
      docs/en/modules/account-pro.md
  55. 19
      docs/en/modules/account/idle-session-timeout.md
  56. 46
      docs/en/others/penetration-test-report.md
  57. 6
      docs/en/release-info/release-notes.md
  58. 4
      docs/en/release-info/upgrading.md
  59. 2
      docs/en/samples/easy-crm.md
  60. 4
      docs/en/studio/installation.md
  61. 56
      docs/en/studio/release-notes.md
  62. 2
      docs/en/studio/running-applications.md
  63. 6
      docs/en/studio/version-mapping.md
  64. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/abp-suite-generated-tests.png
  65. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/abp-suite-navigation-property.png
  66. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/abp-suite-opening.png
  67. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/abp-suite-solution-test-projects.png
  68. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/book-store-suite-solution-explorer.png
  69. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/bookstore-test-succeed.png
  70. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/studio-browser-suite.png
  71. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-author-entity-1.png
  72. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-author-entity-2.png
  73. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-author-new-entity.png
  74. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-author-pages-1.png
  75. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-1.png
  76. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-2.png
  77. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-3.png
  78. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-4.png
  79. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-5.png
  80. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-6.png
  81. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-selection.png
  82. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-pages-1.png
  83. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-with-author-create-modal.png
  84. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-bookstore-advanced-filter-section.png
  85. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-custom-code-result.png
  86. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-enabling-custom-code.png
  87. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-end-of-generation-modal.png
  88. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-repository-custom-code.png
  89. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/test-data-seed-contributors.png
  90. 40
      docs/en/tutorials/book-store-with-abp-suite/index.md
  91. 40
      docs/en/tutorials/book-store-with-abp-suite/part-01.md
  92. 123
      docs/en/tutorials/book-store-with-abp-suite/part-02.md
  93. 79
      docs/en/tutorials/book-store-with-abp-suite/part-03.md
  94. 168
      docs/en/tutorials/book-store-with-abp-suite/part-04.md
  95. 123
      docs/en/tutorials/book-store-with-abp-suite/part-05.md
  96. 10
      docs/en/tutorials/book-store/part-01.md
  97. 10
      docs/en/tutorials/book-store/part-02.md
  98. 8
      docs/en/tutorials/book-store/part-03.md
  99. 2
      docs/en/tutorials/book-store/part-04.md
  100. 8
      docs/en/tutorials/book-store/part-05.md

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

6
Directory.Packages.props

@ -39,8 +39,8 @@
<PackageVersion Include="EphemeralMongo6.runtime.win-x64" Version="1.1.3" />
<PackageVersion Include="FluentValidation" Version="11.10.0" />
<PackageVersion Include="Google.Cloud.Storage.V1" Version="4.10.0" />
<PackageVersion Include="Hangfire.AspNetCore" Version="1.8.14" />
<PackageVersion Include="Hangfire.SqlServer" Version="1.8.14" />
<PackageVersion Include="Hangfire.AspNetCore" Version="1.8.17" />
<PackageVersion Include="Hangfire.SqlServer" Version="1.8.17" />
<PackageVersion Include="HtmlSanitizer" Version="8.1.870" />
<PackageVersion Include="IdentityModel" Version="7.0.0" />
<PackageVersion Include="IdentityServer4" Version="4.1.2" />
@ -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" />

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

@ -512,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",
@ -658,6 +659,7 @@
"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",

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

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-11-13-BuiltIn-OpenApi-Documentation/cover.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 460 KiB

After

Width:  |  Height:  |  Size: 445 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 289 KiB

After

Width:  |  Height:  |  Size: 175 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

After

Width:  |  Height:  |  Size: 271 KiB

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

@ -6,92 +6,121 @@ Built-in OpenAPI Document Generation with .NET 9 — No more SwaggerUI! 👋
What’s Swagger UI?
------------------
[Swagger UI](https://swagger.io/) is an open-source tool that automatically generates an interactive, web-based documentation interface for APIs defined using the OpenAPI Specification (OAS). It simplifies the process of exploring and testing APIs directly from the browser, making it a popular choice for developers and API consumers. It provides paid also free services.
[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.
---
> Previously, Swagger was included by default from **.NET 5** to **.NET 8**, which provides OpenAPI support.
What’s OpenAPI?
---------------
OpenAPI is a standard specification for defining RESTful APIs. Its website is [https://www.openapis.org/](https://www.openapis.org/). Their specifications let developers create, understand, document, and integrate APIs more efficiently.
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)
---
OpenAPI Microsoft Documentation 👉 [https://aka.ms/aspnet/openapi](https://aka.ms/aspnet/openapi)
Replacement of Swagger UI with OpenAPI for API projects — Bye Swashbuckle 👋
Replacement of Swagger UI with OpenAPI
----------------------------------------------------------------------------
![Docs](D:\Github\abp\docs\en\Community-Articles\2024-11-13-BuiltIn-OpenApi-Documentation\img2.png)
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.
Swagger UI, a third-party tool used for documenting and testing APIs, is no longer integrated into NET 9, as Microsoft wants a solution with first-class support, better control, and enhanced security.
In March 2024, the ASP.NET Core team announced plans to remove the `Swashbuckle.AspNetCore` dependency from web API templates in the upcoming .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.
The team intends to enhance the `Microsoft.AspNetCore.OpenApi` package to provide built-in OpenAPI document generation capabilities, reducing reliance on external tools. Community members expressed concerns about the inactivity of Swashbuckle and discussed alternatives like contributing to or forking the project. The ASP.NET Core team has engaged with the maintainers of both Swashbuckle and NSwag to explore potential collaborations and ensure a smooth transition for developers.
In the below issue, you can see the details of this decision:
* https://github.com/dotnet/aspnetcore/issues/54599
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:
**Jeremy** -Product Manager- at Microsoft answers why they took this decision in [this post](https://github.com/dotnet/aspnetcore/issues/54599#issuecomment-2004975574).
* [github.com/dotnet/aspnetcore/issues/54599](https://github.com/dotnet/aspnetcore/issues/54599)
![Jeremy Comments](D:\Github\abp\docs\en\Community-Articles\2024-11-13-BuiltIn-OpenApi-Documentation\img3.png)
Why is SwaggerUI Removed from .NET 9?
-------------------------------------
**The change is due to a lack of maintenance of the Swagger library**, although it has seen some recent updates.
**Jeremy** -Product Manager- at Microsoft, answers why they took this decision in [this post](https://github.com/dotnet/aspnetcore/issues/54599#issuecomment-2004975574).
This change 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.
![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 Documentation?
---
What are the Benefits of the New OpenAI Package?
---------------------------------------------------------------
1. **Native Support and Reduced Dependency**
### 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.
The new `Microsoft.AspNetCore.OpenApi` package provides first-class support for OpenAPI.Reduces reliance on external tools like Swashbuckle or NSwag for basic documentation needs.
### Simplified Configuration
2. **Simplified Configuration**
No need extra setup or 3rd party integrations. Just by defining controllers and endpoints, ASP.NET Core automatically generates OpenAPI specifications.
No need for extensive setup or third-party integrations. Just by defining controllers and endpoints, the framework can automatically generate OpenAPI specifications.
### Well Integration with Minimal APIs
3. **Better 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.
- The built-in support is optimized for **Minimal APIs**, a feature introduced in .NET 6. Automatically includes metadata for routes, request parameters, and responses.
### Compatibility with Existing Tools
4. **Performance Improvement**
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.
- The native implementation leverages source generators to reduce runtime overhead. Faster and more efficient than traditional runtime-based solutions like Swashbuckle.
---
5. **Compatibility with Existing Tools**
* The OpenAPI output can still be consumed by Swagger UI, NSwag, or other tools for visualization, testing, or client generation.
How to Use the New OpenAPI in .NET9?
------------------------------------
If you are creating a new ASP.NET Core project, you can see the below checkbox to add OpenAPI.
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)
![New .NET 9 Project Screen](D:\Github\abp\docs\en\Community-Articles\2024-11-13-BuiltIn-OpenApi-Documentation\img5.png)
I created a new .NET 9 web project, I saw that OpenAPI had already been added.
When I created a new .NET 9 web project, I saw that OpenAPI had already been added.
![Package Reference](img4.png)
![Package Reference](D:\Github\abp\docs\en\Community-Articles\2024-11-13-BuiltIn-OpenApi-Documentation\img4.png)
## Add OpenAPI Support For Your Existing Project
Add the required NuGet package [Microsoft.AspNetCore.OpenApi](https://www.nuget.org/packages/Microsoft.AspNetCore.OpenApi)
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
```
### Enable OpenAPI Support
###
Add the following services and middleware in `Program.cs`
@ -108,7 +137,11 @@ Your OpenAPI document URL is [_https://localhost:7077/openapi/v1.json_](https://
Change the port to your active port. This is how it looks like:
![Web UI of the Documentation](D:\Github\abp\docs\en\Community-Articles\2024-11-13-BuiltIn-OpenApi-Documentation\img1.png)
![Web UI of the Documentation](img1.png)
---
Alternative 3rd Party Tool: Scalar
==================================
@ -119,6 +152,11 @@ See the repo 👉 [https://github.com/scalar/scalar](https://github.com/scalar/s
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)

385
docs/en/Community-Articles/2024-12-01-OpenAI-Integration/POST.md

@ -0,0 +1,385 @@
# How to Use OpenAI API with ABP Framework
In this article, I will show you how to integrate and use the [OpenAI API](https://github.com/openai/openai-dotnet?tab=readme-ov-file#getting-started) with the [ABP Framework](https://abp.io/). We will explore step-by-step how these technologies can work together to enhance your application with powerful AI capabilities, such as natural language processing, image generation, and more.
![cover-image](cover-image.png)
## Creating an ABP Project
To begin integrating OpenAI API with ABP Framework, you first need to create an ABP project. Follow these steps to create and set up your ABP project:
### Step 1: Install ABP CLI
The ABP CLI is a command-line interface tool that helps you create and manage ABP projects easily. To install the ABP CLI, run the following command in your terminal:
```bash
dotnet tool install -g Volo.Abp.Studio.Cli
```
### Step 2: Create a New ABP Project
Once you have installed the ABP CLI, you can create a new ABP project using the following command:
```bash
abp new Acme.OpenAIIntegration -t app --ui-framework mvc --database-provider ef -dbms PostgreSQL --csf
```
> This command will generate a complete ABP project with an [MVC UI](https://abp.io/docs/latest/framework/ui/mvc-razor-pages/overall). The examples provided in this article make use of UI controllers for demonstration purposes. However, the same approach can easily be applied to other UI types supported by ABP, such as Blazor or Angular. You can find other options [here](https://abp.io/docs/latest/cli).
## OpenAI Integration Setup
To begin integrating OpenAI API with ABP Framework, follow these steps:
### Step 1: Create an API Key
To use the OpenAI services, you first need an API key. To obtain one, first [create a new OpenAI account](https://platform.openai.com/signup) or [log in](https://platform.openai.com/login). Next, navigate to the [API key page](https://platform.openai.com/account/api-keys) and select "Create new secret key", optionally naming the key. Make sure to save your API key somewhere safe and do not share it with anyone.
This key will be used to authenticate your application when making requests to the OpenAI endpoints.
### Step 2: Adding *Microsoft.Extensions.AI* Package
To integrate OpenAI API with ABP, we use [Microsoft.Extensions.AI](https://www.nuget.org/packages/Microsoft.Extensions.AI.OpenAI/). This package offers a unified API for integrating AI services, making it easy for developers to work with different AI providers. You can find more details in [this blog post](https://devblogs.microsoft.com/dotnet/introducing-microsoft-extensions-ai-preview/).
To begin integrating OpenAI API with ABP Framework, follow these steps:
1. Add the **Microsoft.Extensions.AI** and **Microsoft.Extensions.AI.OpenAI** (used to interact specifically with OpenAI services. Additionally, this package has alternatives like [Azure OpenAI](https://www.nuget.org/packages/Microsoft.Extensions.AI.OpenAI/), [Azure AI Inference](https://www.nuget.org/packages/Microsoft.Extensions.AI.AzureAIInference/), and [Ollama](https://www.nuget.org/packages/Microsoft.Extensions.AI.Ollama/), offering flexibility for developers to choose the AI provider that best fits their needs) packages:
```bash
dotnet add package Microsoft.Extensions.AI --prerelease
dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease
```
2. Add the required configuration to the `appsettings.json` file located inside the `Acme.OpenAIIntegration.Web` project and dependencies to your `ConfigureServices` method:
```json
"AI": {
"OpenAI": {
"Key": "YOUR-API-KEY",
"Chat": {
"ModelId": "gpt-4o-mini"
}
}
}
```
> Replace the value of the `Key` with your OpenAI API key.
Next, add the following code to the `ConfigureServices` method in `OpenAIIntegrationBlazorModule`:
```csharp
context.Services.AddSingleton(new OpenAIClient(configuration["AI:OpenAI:Key"]));
context.Services.AddChatClient(services =>
services.GetRequiredService<OpenAIClient>().AsChatClient(configuration["AI:OpenAI:Chat:ModelId"] ?? "gpt-4o-mini"));
```
## Creating a Sample Page
To demonstrate the use of OpenAI API, let's create a page named `Sample` in the `Acme.OpenAIIntegration.Web` project:
Create a `Sample` folder under the `Pages` folder of the `Acme.OpenAIIntegration.Web` project. Add a new Razor Page by right-clicking the `Sample` folder then selecting `Add > Razor Page`. Name it `Index`.
Open the `Index.cshtml` and change the whole content as shown below:
> Note: This example demonstrates a simple implementation of a sample page that interacts with the OpenAI API, covering chat, [retrieval-augmented generation (RAG)](https://github.com/openai/openai-dotnet?tab=readme-ov-file#how-to-use-assistants-with-retrieval-augmented-generation-rag), and image generation features. Each example is explained in detail in the next section, so feel free to continue for a better understanding of the steps and logic involved.
```html
@page
@model Acme.OpenAIIntegration.Web.Pages.Sample
@{
ViewData["Title"] = "OpenAI API Demonstration";
}
<h1>@ViewData["Title"]</h1>
<br/><br/>
<div class="row">
<div class="col-md-4">
<h2>Chat Example</h2>
<form method="post" asp-page-handler="Chat">
<div class="form-group">
<label asp-for="ChatInput">Enter your message:</label>
<textarea asp-for="ChatInput" class="form-control" rows="4"></textarea>
</div>
<button type="submit" class="btn btn-primary mt-2">Send</button>
</form>
@if (!string.IsNullOrEmpty(Model.ChatResponse))
{
<h3 class="mt-3">Response:</h3>
<p>@Model.ChatResponse</p>
}
</div>
<div class="col-md-4">
<h2>RAG Example</h2>
<form method="post" asp-page-handler="RAG">
<div class="form-group mt-2">
<label asp-for="RAGQuery">Query:</label>
<input asp-for="RAGQuery" class="form-control" />
</div>
<button type="submit" class="btn btn-primary mt-2">Ask</button>
</form>
@if (!string.IsNullOrEmpty(Model.RAGResponse))
{
<h3 class="mt-3">Result:</h3>
<p>@Model.RAGResponse</p>
}
</div>
<div class="col-md-4">
<h2>Image Generation Example</h2>
<form method="post" asp-page-handler="ImageGeneration">
<div class="form-group">
<label asp-for="ImagePrompt">Image Description:</label>
<input asp-for="ImagePrompt" class="form-control" />
</div>
<button type="submit" class="btn btn-primary mt-2">Generate Image</button>
</form>
@if (Model.GeneratedImageBytes != null)
{
<h3 class="mt-3">Generated Image:</h3>
<img src="data:image/png;base64,@Convert.ToBase64String(Model.GeneratedImageBytes)" alt="Generated image" class="img-fluid mt-2" />
}
</div>
</div>
```
`Index.cshtml.cs` content should be like that:
```csharp
using System;
using System.ClientModel;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.AI;
using OpenAI;
using OpenAI.Assistants;
using OpenAI.Files;
using OpenAI.Images;
namespace Acme.OpenAIIntegration.Web.Pages;
public class Sample : PageModel
{
[BindProperty]
public string ChatInput { get; set; }
public string ChatResponse { get; set; }
[BindProperty]
public string RAGQuery { get; set; }
public string RAGResponse { get; set; }
[BindProperty]
public string ImagePrompt { get; set; }
public byte[] GeneratedImageBytes { get; set; }
private readonly IChatClient _chatClient;
private readonly OpenAIClient _openAiClient;
public Sample(
IChatClient chatClient,
OpenAIClient openAiClient)
{
_chatClient = chatClient;
_openAiClient = openAiClient;
}
public async Task<IActionResult> OnPostChatAsync()
{
ChatResponse = $"Chat response: {(await _chatClient.CompleteAsync(ChatInput)).Message}";
return Page();
}
public async Task<IActionResult> OnPostRAGAsync()
{
#pragma warning disable OPENAI001
var fileClient = _openAiClient.GetOpenAIFileClient();
var assistantClient = _openAiClient.GetAssistantClient();
using var document = BinaryData.FromBytes(GetExceptionHandlingDocumentContent().ToArray()).ToStream();
var exceptionHandlingDoc = await fileClient.UploadFileAsync(
document,
"ExceptionHandling.md",
FileUploadPurpose.Assistants);
AssistantCreationOptions assistantOptions = new()
{
Name = "Exception Handling Assistant",
Instructions =
"""
This assistant helps you with exception handling in ABP Framework. You can ask questions about exception handling and get answers.
- Do not make any assumptions when asked for information that is not in the document
- Give the most accurate information possible
- Give short(max 1-2 sentence) and concise answers
- Do not provide file citations
""",
Tools =
{
new FileSearchToolDefinition(),
},
ToolResources = new()
{
FileSearch = new()
{
NewVectorStores =
{
new VectorStoreCreationHelper([exceptionHandlingDoc.Value.Id]),
}
}
},
};
var assistant = await assistantClient.CreateAssistantAsync("gpt-4o", assistantOptions);
ThreadCreationOptions threadOptions = new()
{
InitialMessages = { RAGQuery }
};
ThreadRun threadRun = assistantClient.CreateThreadAndRun(assistant.Value.Id, threadOptions);
do
{
Thread.Sleep(TimeSpan.FromSeconds(1));
threadRun = assistantClient.GetRun(threadRun.ThreadId, threadRun.Id);
} while (!threadRun.Status.IsTerminal);
CollectionResult<ThreadMessage> messages
= assistantClient.GetMessages(threadRun.ThreadId,
new MessageCollectionOptions() { Order = MessageCollectionOrder.Ascending });
var response = new StringBuilder();
foreach (var message in messages)
{
response.AppendLine($"[{message.Role.ToString().ToUpper()}]: ");
foreach (var contentItem in message.Content)
{
if (!string.IsNullOrEmpty(contentItem.Text))
{
response.AppendLine(contentItem.Text);
if (contentItem.TextAnnotations.Count > 0)
{
response.AppendLine("");
}
}
}
response.AppendLine("");
#pragma warning restore OPENAI001
}
RAGResponse = response.ToString();
return Page();
}
public async Task<IActionResult> OnPostImageGenerationAsync()
{
var client = _openAiClient.GetImageClient("dall-e-3");
var image = await client.GenerateImageAsync(ImagePrompt, new ImageGenerationOptions
{
ResponseFormat = GeneratedImageFormat.Bytes
});
var imageBytes = image.Value.ImageBytes;
using var memoryStream = new MemoryStream();
await imageBytes.ToStream().CopyToAsync(memoryStream);
GeneratedImageBytes = memoryStream.ToArray();
return Page();
}
public ReadOnlySpan<byte> GetExceptionHandlingDocumentContent()
{
return """
# Exception Handling
ABP provides a built-in infrastructure and offers a standard model for handling exceptions.
* Automatically **handles all exceptions** and sends a standard **formatted error message** to the client for an API/AJAX request.
* Automatically hides **internal infrastructure errors** and returns a standard error message.
* Provides an easy and configurable way to **localize** exception messages.
* Automatically maps standard exceptions to **HTTP status codes** and provides a configurable option to map custom exceptions.
## Automatic Exception Handling
`AbpExceptionFilter` handles an exception if **any of the following conditions** are met:
* Exception is thrown by a **controller action** which returns an **object result** (not a view result).
* The request is an AJAX request (`X-Requested-With` HTTP header value is `XMLHttpRequest`).
* Client explicitly accepts the `application/json` content type (via `accept` HTTP header).
If the exception is handled it's automatically **logged** and a formatted **JSON message** is returned to the client.
## Business Exceptions
Most of your own exceptions will be business exceptions. The `IBusinessException` interface is used to mark an exception as a business exception.
`BusinessException` implements the `IBusinessException` interface in addition to the `IHasErrorCode`, `IHasErrorDetails` and `IHasLogLevel` interfaces. The default log level is `Warning`.
Usually you have an error code related to a particular business exception. For example:
````C#
throw new BusinessException(QaErrorCodes.CanNotVoteYourOwnAnswer);
````
### User Friendly Exception
If an exception implements the `IUserFriendlyException` interface, then ABP does not change it's `Message` and `Details` properties and directly send it to the client.
`UserFriendlyException` class is the built-in implementation of the `IUserFriendlyException` interface. Example usage:
````C#
throw new UserFriendlyException(
"Username should be unique!"
);
````
* The `IUserFriendlyException` interface is derived from the `IBusinessException` and the `UserFriendlyException` class is derived from the `BusinessException` class.
"""u8;
}
}
```
## Running the Application
After completing the setup, you can run the application using the following command:
```bash
dotnet run --project ./src/Acme.OpenAIIntegration.Web
```
Once the application is running, open your browser and navigate to `/Sample`. You should see the `Sample` page we created, which contains sections for Chat, RAG (Retrieval-Augmented Generation), and Image Generation. You can find the screenshot of the page below:
![sample page](sample-page.png)
## Examples Overview
To showcase the integration of the OpenAI API with the ABP Framework, we implemented three different examples:
1. **Chat Example**: This example demonstrates how to use OpenAI's chat capabilities by allowing users to enter a message and receive an AI-generated response. The implementation involves setting up a simple form on the `Sample` page where users can input their message. The form submission triggers the `OnPostChatAsync` method, which uses the `IChatClient` to generate a response.
![chat-example](chat-example.gif)
2. **Retrieval-Augmented Generation (RAG) Example**: In this example, we use OpenAI to answer user queries by referencing custom documents uploaded to the OpenAI API. The implementation involves uploading a document using the `OpenAIFileClient` and creating an assistant with specific instructions to handle the uploaded content. In this case, the document is a section from ABP's Exception Handling documentation, which includes examples on how ABP handles exceptions, user-friendly error messages, and business exceptions. Users can input their query on the `Sample` page, and the `OnPostRAGAsync` method processes the query to generate precise answers based on the document content. If users ask questions that are not covered in the document, the assistant clearly indicates that the information is not available, as per the instructions provided. For example, when asked about `Object Extensions`, the response begins with: "The uploaded document does not contain information about `Object Extensions`...". This demonstrates how the assistant adheres to the provided instructions. You can also find this example illustrated in the GIF below.
![rag-example-1](rag-example-1.gif)
![rag-example-2](rag-example-2.gif)
3. **Image Generation Example**: This example leverages the [DALL-E](https://openai.com/index/dall-e-3/) model to generate images based on user-provided prompts. On the `Sample` page, users can provide a description of the image they want to generate, and the `OnPostImageGenerationAsync` method uses the `OpenAIClient` to generate the image.
![image-generation-example](image-generation-example.gif)
## Conclusion
In this article, we covered how to integrate the OpenAI API with the ABP Framework by creating a sample project, setting up the OpenAI services, and implementing examples for conversational AI, knowledge-based assistance, and image generation. By following these steps, you can add powerful AI-driven capabilities to your application, making it more interactive, intelligent, and capable of meeting user needs effectively.

BIN
docs/en/Community-Articles/2024-12-01-OpenAI-Integration/chat-example.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

BIN
docs/en/Community-Articles/2024-12-01-OpenAI-Integration/cover-image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 KiB

BIN
docs/en/Community-Articles/2024-12-01-OpenAI-Integration/image-generation-example.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 KiB

BIN
docs/en/Community-Articles/2024-12-01-OpenAI-Integration/rag-example-1.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

BIN
docs/en/Community-Articles/2024-12-01-OpenAI-Integration/rag-example-2.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

BIN
docs/en/Community-Articles/2024-12-01-OpenAI-Integration/sample-page.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

2
docs/en/cli/index.md

@ -211,6 +211,7 @@ For more samples, go to [ABP CLI Create Solution Samples](new-command-samples.md
* `leptonx`: LeptonX Theme.
* `basic`: Basic Theme.
* `--public-website`: Public Website is a front-facing website for describing your project, listing your products and doing SEO for marketing purposes. Users can login and register on your website with this website. This option is only included in PRO templates.
* `--no-grafana-dashboard` or `-ngd`: Does not add example Grafana Dashboard to the solution.
* `--output-folder` or `-o`: Specifies the output folder. Default value is the current directory.
* `--local-framework-ref` or `-lfr`: Uses local projects references to the ABP framework instead of using the NuGet packages. It tries to find the paths from `ide-state.json`. The file is located at `%UserProfile%\.abp\studio\ui\ide-state.json` (for Windows) and `~/.abp/studio/ui/ide-state.json` (for MAC).
* `--create-solution-folder` or `-csf`: Specifies if the project will be in a new folder in the output folder or directly the output folder.
@ -225,6 +226,7 @@ For more samples, go to [ABP CLI Create Solution Samples](new-command-samples.md
* `--dont-run-bundling`: Skip bundling for Blazor packages.
* `--no-kubernetes-configuration` or `-nkc`: Skips the Kubernetes configuration files.
* `--no-social-logins` or `-nsl`: Skipts the social login configuration.
* `--no-tests` or `-ntp`: Does not add test projects.
* *Module Options*: You can skip some modules if you don't want to add them to your solution (*Available for* ***Team*** *or higher licenses*). Available commands:
* `-no-saas`: Skips the Saas module.
* `-no-gdpr`: Skips the GDPR module.

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)

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.

66
docs/en/docs-nav.json

@ -115,6 +115,35 @@
}
]
},
{
"text": "Book Store Application (with ABP Suite)",
"items": [
{
"text": "Overview",
"path": "tutorials/book-store-with-abp-suite"
},
{
"text": "1: Creating the Solution",
"path": "tutorials/book-store-with-abp-suite/part-01.md"
},
{
"text": "2: Creating the Books",
"path": "tutorials/book-store-with-abp-suite/part-02.md"
},
{
"text": "3: Creating the Authors",
"path": "tutorials/book-store-with-abp-suite/part-03.md"
},
{
"text": "4: Book to Author Relation",
"path": "tutorials/book-store-with-abp-suite/part-04.md"
},
{
"text": "5: Customizing the Generated Code",
"path": "tutorials/book-store-with-abp-suite/part-05.md"
}
]
},
{
"text": "Modular Monolith Application",
"items": [
@ -156,6 +185,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"

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

2
docs/en/framework/fundamentals/dependency-injection.md

@ -498,6 +498,8 @@ Use `ICachedServiceProvider` (instead of `ITransientCachedServiceProvider`) unle
> ABP also provides the `IAbpLazyServiceProvider` service. It does exists for backward compatibility and works exactly same with the `ITransientCachedServiceProvider` service. So, use the `ITransientCachedServiceProvider` since the `IAbpLazyServiceProvider` might be removed in future ABP versions.
> Another advantage of using `ICachedServiceProvider` is that, during an HTTP request, if a service's constructor requires injecting many dependencies, it can negatively impact performance, as the injected services may not all be used by the current request. By resolving services on-demand, performance degradation can be effectively avoided.
## Advanced Features
### IServiceCollection.OnRegistered Event

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/quick-start.md

@ -6,7 +6,7 @@
Please follow the steps below to prepare your development environment for Angular.
1. **Install Node.js:** Please visit [Node.js downloads page](https://nodejs.org/en/download/) and download proper Node.js `v18.19+` installer for your OS. An alternative is to install [NVM](https://github.com/nvm-sh/nvm) and use it to have multiple versions of Node.js in your operating system.
1. **Install Node.js:** Please visit [Node.js downloads page](https://nodejs.org/en/download/) and download proper Node.js `v20.11+` installer for your OS. An alternative is to install [NVM](https://github.com/nvm-sh/nvm) and use it to have multiple versions of Node.js in your operating system.
2. **[Optional] Install Yarn:** You may install Yarn v1.22+ (not v2) following the instructions on [the installation page](https://classic.yarnpkg.com/en/docs/install). Yarn v1 delivers an arguably better developer experience compared to npm v10 and below. You may skip this step and work with npm, which is built-in in Node.js, instead.
3. **[Optional] Install VS Code:** [VS Code](https://code.visualstudio.com/) is a free, open-source IDE which works seamlessly with TypeScript. Although you can use any IDE including Visual Studio or Rider, VS Code will most likely deliver the best developer experience when it comes to Angular projects. ABP project templates even contain plugin recommendations for VS Code users, which VS Code will ask you to install when you open the Angular project folder. Here is a list of recommended extensions:
- [Angular Language Service](https://marketplace.visualstudio.com/items?itemName=angular.ng-template)

2
docs/en/framework/ui/mvc-razor-pages/client-side-package-management.md

@ -41,7 +41,7 @@ After depending on a NPM package, all you should do is to run the **yarn** comma
yarn
```
Alternatively, you can use `npm install` but [Yarn](https://classic.yarnpkg.com/) is suggested as mentioned before.
Alternatively, you can use `npm install` but [Yarn v1.22+ (not v2)](https://classic.yarnpkg.com/en/docs/install) is suggested as mentioned before.
#### Package Contribution

2
docs/en/framework/ui/react-native/index.md

@ -17,7 +17,7 @@ ABP platform provide basic [React Native](https://reactnative.dev/) startup temp
Please follow the steps below to prepare your development environment for React Native.
1. **Install Node.js:** Please visit [Node.js downloads page](https://nodejs.org/en/download/) and download proper Node.js v16 or v18 installer for your OS. An alternative is to install [NVM](https://github.com/nvm-sh/nvm) and use it to have multiple versions of Node.js in your operating system.
1. **Install Node.js:** Please visit [Node.js downloads page](https://nodejs.org/en/download/) and download proper Node.js v20.11+ installer for your OS. An alternative is to install [NVM](https://github.com/nvm-sh/nvm) and use it to have multiple versions of Node.js in your operating system.
2. **[Optional] Install Yarn:** You may install Yarn v1 (not v2) following the instructions on [the installation page](https://classic.yarnpkg.com/en/docs/install). Yarn v1 delivers an arguably better developer experience compared to npm v6 and below. You may skip this step and work with npm, which is built-in in Node.js, instead.
3. **[Optional] Install VS Code:** [VS Code](https://code.visualstudio.com/) is a free, open-source IDE which works seamlessly with TypeScript. Although you can use any IDE including Visual Studio or Rider, VS Code will most likely deliver the best developer experience when it comes to React Native projects.
4. **Install an Emulator:** React Native applications need an Android emulator or an iOS simulator to run on your OS. See the [Android Studio Emulator](https://docs.expo.io/workflow/android-simulator/) or [iOS Simulator](https://docs.expo.io/workflow/ios-simulator/) on expo.io documentation to learn how to set up an emulator.

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

BIN
docs/en/get-started/images/abp-studio-microservice-solution-runner-enable-watch-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/en/get-started/images/abp-studio-microservice-solution-runner-enable-watch-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/en/get-started/images/abp-studio-microservice-solution-runner-enable-watch.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-0.9.13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-configurations-efcore-0.9.13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-configurations-mongo-0.9.13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-provider-efcore-0.9.13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-provider-mongo-0.9.13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-solution-properties-0.9.13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-0.9.13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
docs/en/get-started/images/abp-studio-nolayers-new-solution-dialog-ui-theme-0.9.13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

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

@ -5,7 +5,7 @@ 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)

16
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"]
}
@ -19,10 +19,10 @@ First things first! Let's setup your development environment before creating the
The following tools should be installed on your development machine:
* [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) (v17.3+) for Windows / [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/). <sup id="a-editor">[1](#f-editor)</sup>
* [.NET 8.0+](https://dotnet.microsoft.com/en-us/download/dotnet)
* [Visual Studio 2022](https://visualstudio.microsoft.com/) or another IDE that supports [.NET 9.0+](https://dotnet.microsoft.com/download/dotnet) development. <sup id="a-editor">[1](#f-editor)</sup>
* [.NET 9.0+](https://dotnet.microsoft.com/en-us/download/dotnet)
{{ if UI != "Blazor" }}
* [Node v18.19+](https://nodejs.org/)
* [Node v20.11+](https://nodejs.org/)
* [Yarn v1.22+ (not v2)](https://classic.yarnpkg.com/en/docs/install) <sup id="a-yarn">[2](#f-yarn)</sup> or npm v10+ (already installed with Node)
{{ end }}
{{ if Tiered == "Yes" }}
@ -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)

40
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:
@ -175,9 +171,11 @@ Once you run the `IdentityService` in Visual Studio, it will be completely integ
As an alternative approach, especially if you don't need to debug your service, you can enable the watching feature of ABP Studio to automatically re-build and re-start when there is change in your application/service.
To enable watching, right-click the application/service you want to watch, select the *Run* -> *Enable Watch* command as shown in the following figure:
To enable watching, right-click the application/service you want to watch, select the *Properties* -> *Watch changes while running* option as shown in the following figure:
![abp-studio-microservice-solution-runner-enable-watch-1](images/abp-studio-microservice-solution-runner-enable-watch-1.png)
![abp-studio-microservice-solution-runner-enable-watch](images/abp-studio-microservice-solution-runner-enable-watch.png)
![abp-studio-microservice-solution-runner-enable-watch-2](images/abp-studio-microservice-solution-runner-enable-watch-2.png)
Now, you can make your development on the `IdentityService`. Whenever you save a code file, it is automatically rebuilt and restarted by ABP Studio, so any change will be effective on the running solution in a few seconds.
@ -185,8 +183,6 @@ When you enable watch for an application an *eye* icon is added near to the appl
![abp-studio-microservice-solution-runner-watch-enabled-icon](images/abp-studio-microservice-solution-runner-watch-enabled-icon.png)
You can disable watching by right-clicking an application and selecting *Run* -> *Disable Watch* command.
## Kubernetes Integration: Working with Helm Charts
Solution Runner is a great way to locally run all the applications and services of your solution. However, there are some drawbacks:
@ -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)

28
docs/en/get-started/single-layer-web-application.md

@ -18,10 +18,10 @@ First things first! Let's setup your development environment before creating the
The following tools should be installed on your development machine:
* [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) (v17.3+) for Windows / [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/). <sup id="a-editor">[1](#f-editor)</sup>
* [.NET 8.0+](https://dotnet.microsoft.com/en-us/download/dotnet)
* [Visual Studio 2022](https://visualstudio.microsoft.com/) or another IDE that supports [.NET 9.0+](https://dotnet.microsoft.com/download/dotnet) development. <sup id="a-editor">[1](#f-editor)</sup>
* [.NET 9.0+](https://dotnet.microsoft.com/en-us/download/dotnet)
{{ if UI != "Blazor" }}
* [Node v18.19+](https://nodejs.org/)
* [Node v20.11+](https://nodejs.org/)
* [Yarn v1.22+ (not v2)](https://classic.yarnpkg.com/en/docs/install) <sup id="a-yarn">[2](#f-yarn)</sup> or npm v10+ (already installed with Node)
{{ end }}
{{ if Tiered == "Yes" }}
@ -50,11 +50,11 @@ Assuming that you have [installed and logged in](../studio/installation.md) to t
Select the *File* -> *New Solution* in the main menu, or click the *New solution* button on the Welcome screen to open the *Create new solution* wizard:
![abp-studio-new-solution-dialog](images/abp-studio-no-layers-new-solution-dialog.png)
![abp-studio-new-solution-dialog](images/abp-studio-no-layers-new-solution-dialog-0.9.13.png)
We will use the *Application (Single Layer)* solution template for this tutorial, so pick it and click the *Next* button:
![abp-studio-new-solution-dialog-solution-properties](images/abp-studio-no-layers-new-solution-dialog-solution-properties.png)
![abp-studio-new-solution-dialog-solution-properties](images/abp-studio-no-layers-new-solution-dialog-solution-properties-0.9.13.png)
On that screen, you choose a name for your solution. You can use different levels of namespaces; e.g. `BookStore`, `Acme.BookStore` or `Acme.Retail.BookStore`.
@ -62,31 +62,35 @@ Then select an *output folder* to create your solution. The *Create solution fol
Once your configuration is done, click the *Next* button to navigate to the *UI Framework* selection:
![abp-studio-new-solution-dialog-ui-framework](images/abp-studio-no-layers-new-solution-dialog-ui-framework.png)
![abp-studio-new-solution-dialog-ui-framework](images/abp-studio-no-layers-new-solution-dialog-ui-framework-0.9.13.png)
Here, you see all the possible UI options supported by that startup solution template. Pick the **{{ UI_Value }}**.
Notice that; Once you select a UI type, some additional options will be available under the UI Framework list. You can further configure the options or leave them as default and click the *Next* button for the *UI Theme* selection screen:
![abp-studio-new-solution-dialog-ui-theme](images/abp-studio-nolayers-new-solution-dialog-ui-theme.png)
![abp-studio-new-solution-dialog-ui-theme](images/abp-studio-nolayers-new-solution-dialog-ui-theme-0.9.13.png)
LeptonX is the suggested UI theme that is proper for production usage. Select one of the themes, configure the additional options, and click the *Next* button for the *Database Provider* selection:
{{ if DB == "EF" }}
![abp-studio-new-solution-dialog-database-provider](images/abp-studio-no-layers-new-solution-dialog-database-provider-efcore.png)
![abp-studio-new-solution-dialog-database-provider](images/abp-studio-no-layers-new-solution-dialog-database-provider-efcore-0.9.13.png)
{{ else }}
![abp-studio-new-solution-dialog-database-provider](images/abp-studio-no-layers-new-solution-dialog-database-provider-mongo.png)
![abp-studio-new-solution-dialog-database-provider](images/abp-studio-no-layers-new-solution-dialog-database-provider-mongo-0.9.13.png)
{{ end }}
On that screen, you can decide on your database provider by selecting one of the provided options. There are some additional options for each database provider. Leave them as default or change them based on your preferences, then click the *Next* button for additional *Database Configurations*:
{{ if DB == "EF" }}
![abp-studio-new-solution-dialog-database-configurations](images/abp-studio-no-layers-new-solution-dialog-database-configurations-efcore.png)
![abp-studio-new-solution-dialog-database-configurations](images/abp-studio-no-layers-new-solution-dialog-database-configurations-efcore-0.9.13.png)
{{ else }}
![abp-studio-new-solution-dialog-database-configurations](images/abp-studio-no-layers-new-solution-dialog-database-configurations-mongo.png)
![abp-studio-new-solution-dialog-database-configurations](images/abp-studio-no-layers-new-solution-dialog-database-configurations-mongo-0.9.13.png)
{{ end }}
Here, you can select the database management systems (DBMS){{ if DB == "EF" }} and the connection string{{ end }}. 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.
Here, you can select the database management systems (DBMS){{ if DB == "EF" }} and the connection string{{ end }}. Then, you can select optional modules and enable additional options according to your preferences.
![abp-studio-no-layers-new-solution-additional-options](images/abp-studio-no-layers-new-solution-additional-options-0.9.13.png)
Now, we are ready to allow ABP Studio to create our solution. Just click the *Create* button and let the ABP Studio do the rest for you.
After clicking the Create button, the dialog is closed and your solution is loaded into ABP Studio:

BIN
docs/en/images/generic-repositories.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 165 KiB

BIN
docs/en/images/idle-message.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
docs/en/images/idle-setting.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

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

@ -358,3 +358,4 @@ This module doesn't define any additional distributed event. See the [standard d
* [Impersonation](./account/impersonation.md)
* [Linked Accounts](./account/linkedaccounts.md)
* [Session Management](./account/session-management.md)
* [Idle Session Timeout](./account/idle-session-timeout.md)]

19
docs/en/modules/account/idle-session-timeout.md

@ -0,0 +1,19 @@
# Idle Session Timeout
The `Idle Session Timeout` feature allows you to automatically log out users after a certain period of inactivity.
## Configure Idle Session Timeout
You can enable/disable the `Idle Session Timeout` feature in the `Setting > Account > Idle Session Timeout` page.
The default idle session timeout is 1 hour. You can change it by selecting a different value from the dropdown list or entering a custom value(in minutes).
![idle-setting](../../images/idle-setting.png)
Once the idle session timeout is reached, the user will see a warning modal before being logged out. if user does not respond for 60 seconds, the user will be logged out automatically.
![idle-setting](../../images/idle-message.png)
## How it works
There is JavaScript code running in the background to detect user activity. such as mouse movement, key press, click, etc. If there is no activity detected for setting time, The warning modal will be shown to the user.

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

@ -1,6 +1,6 @@
# ABP Penetration Test Report
The ABP Commercial MVC `v8.3.0` application template has been tested against security vulnerabilities by the [OWASP ZAP v2.14.0](https://www.zaproxy.org/) tool. The demo web application was started on the `https://localhost:44349` address. The below alerts have been reported by the pentest tool. These alerts are sorted by the risk level as high, medium, and low. The informational alerts are not mentioned in this document.
The ABP Commercial MVC `v9.0.0` application template has been tested against security vulnerabilities by the [OWASP ZAP v2.14.0](https://www.zaproxy.org/) tool. The demo web application was started on the `https://localhost:44349` address. The below alerts have been reported by the pentest tool. These alerts are sorted by the risk level as high, medium, and low. The informational alerts are not mentioned in this document.
Many of these alerts are **false-positive**, meaning the vulnerability scanner detected these issues, but they are not exploitable. It's clearly explained for each false-positive alert why this alert is a false-positive.
@ -10,14 +10,14 @@ In the next sections, you will find the affected URLs, attack parameters (reques
There are high _(red flag)_, medium _(orange flag)_, low _(yellow flag)_, and informational _(blue flag)_ alerts.
![penetration-test-8.3.0](../images/pen-test-alert-list-8.3.png)
![penetration-test-9.0.0](../images/pen-test-alert-list-9.0.png)
> The informational alerts are not mentioned in this document. These alerts are not raising any risks on your application and they are optional.
### Path Traversal [Risk: High] - False Positive
- *[GET] - https://localhost:44349/api/audit-logging/audit-logs?startTime=&endTime=&url=&userName=&applicationName=&clientIpAddress=&correlationId=&httpMethod=audit-logs&httpStatusCode=&maxExecutionDuration=&minExecutionDuration=&hasException=true&sorting=executionTime+desc&skipCount=0&maxResultCount=10* (attack: **httpMethod=audit-logs**)
- *[POST] - https://localhost:44349/Account/Login* (attack: **\Login**)
- *[POST] - https://localhost:44349/Account/LinkLogin* (attack: **\LinkLogin**)
- *[POST] - https://localhost:44349/Account/Register* (attack: **\Register**)
- *[POST] - https://localhost:44349/Account/SecurityLogs* (attack: **\SecurityLogs**)
- *[POST] - https://localhost:44349/Identity/SecurityLogs* (attack: **\SecurityLogs**)
@ -28,19 +28,15 @@ The Path Traversal attack technique allows an attacker access to files, director
**Solution**:
This is a **false-positive** alert since ABP does all related checks for this kind of attack on the backend side for these endpoints.
This is a **false-positive** alert since ABP does all related checks for this kind of attacks on the backend side for these endpoints.
### SQL Injection [Risk: High] - False Positive
* *[POST] — https://localhost:44349/Account/Login* (attack: **1q2w3E* AND 1=1 --**)
* *[POST] — https://localhost:44349/AuditLogs* (attack: **GET' AND '1'='1' --**)
* *[POST] — https://localhost:44349/Identity/SecurityLogs* (attack: **admin' AND '1'='1**)
* *[POST] — https://localhost:44349/api/account/verify-authenticator-code* (attack: **AND '1'='1**)
* *[POST] — https://localhost:44349/Identity/ClaimTypes/CreateModal* (attack: **aaaa AND '1'='1**)
* *[POST] — https://localhost:44349/Account/ImpersonateUser* (attack: **CfDJ8Pyqeg0vtHtJpnK-9eLaft7-JxLJfJ6WHKPOdBZVxz14BDo061qpJ2NLplgAn2Hw16ec0IR38_wWAUkJGxP8hL6PcLfH0bh-ATNTspWyWYTGGbiH-zeKWiS5vWX-br2BA1hE7Dc45eWGUZNcVc_vm2s AND 1=1 --**)
* *[POST] — https://localhost:44349/Abp/MultiTenancy/TenantSwitchModal* (attack: **CfDJ8Pyqeg0vtHtJpnK-9eLaft7-JxLJfJ6WHKPOdBZVxz14BDo061qpJ2NLplgAn2Hw16ec0IR38_wWAUkJGxP8hL6PcLfH0bh-ATNTspWyWYTGGbiH-zeKWiS5vWX-br2BA1hE7Dc45eWGUZNcVc_vm2s AND 1=1 --**)
* *[POST] — https://localhost:44349/Identity/OrganizationUnits/\** (attack: **6f4cd0ab-f4eb-7ce0-8b26-3a138af1840d" AND '1'='1**) (also, several other URLs...)
* *[POST] — https://localhost:44349/Identity/ClaimTypes/EditModal* (attack: **aaaa AND '1'='1**)
* *[POST] — https://localhost:44349/LanguageManagement/Texts* (attack: **true" AND "1"="1" --**)
* *[POST] — https://localhost:44349/Account/Manage?CurrentPassword=ZAP%27+AND+%271%27%3D%271%27+--+&NewPassword=ZAP&NewPasswordConfirm=ZAP*
* *[POST] — https://localhost:44349/Identity/ClaimTypes/CreateModal* (attack: **aaaad AND '1'='1**)
**Description**:
@ -95,11 +91,17 @@ There are only one URL that is reported as exposing error messages. This is a **
### Content Security Policy (CSP) Header Not Set [Risk: Medium] — Positive (Fixed)
- *[GET] — https://localhost:44349*
- *[GET] — https://localhost:44349/AuditLogs*
- *[GET] — https://localhost:44349/CookiePolicy*
- *[GET] — https://localhost:44349/Gdpr/PersonalData*
- *[GET] — https://localhost:44349/Identity/ClaimTypes/{0}* (create & edit modal URLs - also there are other modal related URLs...)
- *[GET] — https://localhost:44349/AbpPermissionManagement/PermissionManagementModal?providerName=R&providerKey=role&providerKeyDisplayName=role*
- *[GET] — https://localhost:44349/Abp/MultiTenancy/TenantSwitchModal*
- *[GET] — https://localhost:44349/Account/AuthorityDelegation/AuthorityDelegationModal*
- *[GET] — https://localhost:44349/Account/AuthorityDelegation/DelegateNewUserModal*
- *[GET] — https://localhost:44349/Account/ForgotPassword _(other several account URLS)_*
- *[GET] — https://localhost:44349/Account/ExternalLogins _(other several account URLS)_*
- *[GET] — https://localhost:44349/Account/SecurityLogs _(other several account URLS)_*
- *[GET] — https://localhost:44349/Account/Login _(other several account URLS)_*
- *[GET] — https://localhost:44349/Account/Register _(other several account URLS)_*
- *[GET] — https://localhost:44349/Account/Manage _(other several account URLS)_*
@ -143,12 +145,13 @@ The first affected URL is a **false-positive** alert since it's already fixed an
The second URL is also a **false-positive** alert because there is no bad character string in the response.
> **Note**: However, it might be possible if you had any sensitive localization key-value pair in your localization entries, because this endpoint returns all localization values to be able to be used in the application. Therefore, keep that in mind while defining new localization entries.
> **Note**: However, it might be possible if you had any sensitive localization key-value pair in your localization entries, because this endpoint returns all localization values to be able to be used in the application. Therefore, keep that in mind while defining new localization entries. Pass the critical values in your code while using the localization entry as a parameter.
### XSLT Injection [Risk: Medium] - False Positive
- *[GET] — https://localhost:44349/Abp/Languages/Switch?culture=%3Cxsl%3Avalue-of+select%3D%22system-property%28%27xsl%3Avendor%27%29%22%2F%3E&returnUrl=%2F&uiCulture=ar*
- *[POST] — https://localhost:44349/Account/Login _(same URL with different parameters...)_*
- *[POST] — https://localhost:44349/Account/ImpersonateUser _(same URL with different parameters...)_*
- *[POST] — https://localhost:44349/Account/Register _(same URL with different parameters...)_*
- *[POST] — https://localhost:44349/Account/Manage _(same URL with different parameters...)_*
- *[POST] — https://localhost:44349/Account/ForgotPassword _(same URL with different parameters...)_*
@ -161,13 +164,14 @@ Injection using XSL transformations may be possible and may allow an attacker to
**Explanation**:
This is a **false-positive** alert. v8.3.0 uses .NET 8 and the XSLT transformation is not possible on .NET5 or higher.
This is a **false-positive** alert. v9.0 uses .NET 9 and the XSLT transformation is not possible on .NET5 or higher.
### Application Error Disclosure [Risk: Low] — False Positive
- *[GET] — https://localhost:44349/Abp/Languages/Switch*
- *[POST] — https://localhost:44349/Account/ImpersonateUser*
- *[POST] — https://localhost:44349/Saas/Host/Editions*
- *[POST] — https://localhost:44349/Saas/Host/Tenants*
- *[GET] — https://localhost:44349/Account/ExternalLogins*
- *[GET] — https://localhost:44349/Account/Logout*
**Description:**
@ -304,6 +308,7 @@ This vulnerability was reported as a positive alert because the application ran
### Timestamp Disclosure - Unix [Risk: Low] - False Positive
- *[GET] — https://localhost:44349/libs/zxcvbn/zxcvbn.js?=*
- *[GET] — https://localhost:44349/libs/sweetalert2/sweetalert2.all.min.js?=*
**Description**:
@ -319,8 +324,9 @@ This vulnerability was reported as a positive alert, because ABP uses the [zxcvb
### X-Content-Type-Options Header Missing [Risk: Low] - Positive (Fixed)
- *[GET] — https://localhost:44349/client-proxies/account-proxy.js?_v=638550091940000000 (and other client-proxies related URLs)*
- *[GET] — https://localhost:44349/client-proxies/account-proxy.js?_v=638550091940000000 (and other client-proxies related URLs...)*
- *[GET] — https://localhost:44349/favicon.svg*
- *[GET] — https://localhost:44349/images/getting-started/bg-01.png* (and other image URLs...)
- *[GET] — https://localhost:44349/global-styles.css?_v=638556076064360335*
- *[GET] — https://localhost:44349/libs/@fortawesome/fontawesome-free/css/all.css?_v=%5CWEB-INF%5Cweb.xml (other several URLs...)*
- other URLs...
@ -340,11 +346,3 @@ If possible, ensure that the end user uses a standards-compliant and modern web
The `X-Content-Type-Options` header allows you to avoid MIME type sniffing by saying that the MIME types are deliberately configured. This headeer is not strictly required, but it is highly recommended for security reasons. While modern browsers have improved security features, you can still set this header for ensuring the security of web applications.
You can add the [ABP's Security Header Middleware](../framework/ui/mvc-razor-pages/security-headers.md#security-headers-middleware) into the request pipeline to set the `X-Content-Type-Options` as *no-sniff*. Also, this middleware adds other pre-defined security headers to your application, including `X-XSS-Protection`, `X-Frame-Options` and `Content-Security-Policy` (if it's enabled). Read [Security Headers](../framework/ui/mvc-razor-pages/security-headers.md) documentation for more info.
## Other Alerts (Fixed)
The following alerts were reported by the community or our customers in v8.2 and fixed:
* https://github.com/abpframework/abp/issues/19576
* https://github.com/abpframework/abp/issues/19588
* https://github.com/abpframework/abp/issues/19589

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)

2
docs/en/samples/easy-crm.md

@ -35,7 +35,7 @@ When you download and open the zip file, you will see two folders:
* First, follow all the steps above to run the server side and seed the sample data.
* Open a command prompt in the angular folder.
* Run the `yarn` command to install NPM packages (requires the [Yarn](https://yarnpkg.com/) package manager).
* Run the `yarn` command to install NPM packages (requires the [Yarn v1.22+ (not v2)](https://classic.yarnpkg.com/en/docs/install) package manager).
* Run the `yarn start` command to run the Angular application. It will automatically open the `localhost://4200` in your default browser once the application initialized.
### Blazor UI

4
docs/en/studio/installation.md

@ -8,7 +8,7 @@
Before you begin the installation process for ABP Studio, ensure that your system meets the following pre-requirements:
### Node
Make sure [Node.js](https://nodejs.org/en) is installed on your system. If you have not installed Node.js, you can download the `v18.19+` version from the official [Node.js website](https://nodejs.org/en/download/prebuilt-installer).
Make sure [Node.js](https://nodejs.org/en) is installed on your system. If you have not installed Node.js, you can download the `v22+` version from the official [Node.js website](https://nodejs.org/en/download/prebuilt-installer).
### WireGuard (Optional)
ABP Studio needs [WireGuard](https://www.wireguard.com/) for Kubernetes operations. You can find the installation instructions for your specific operating system below:
@ -19,7 +19,7 @@ Installation instructions for your Windows operating system are on the official
**For macOS:**
Installation instructions for your macOS operating system are on the official [WireGuard website](https://www.wireguard.com/install/#macos-homebrew-and-macports-basic-cli-homebrew-userspace-go-homebrew-tools-macports-userspace-go-macports-tools).
### Docker (Optional)
### Docker
ABP Studio needs [Docker](https://www.docker.com/) for [Kubernetes](https://kubernetes.io/) operations. Install Docker by following the guidelines on the official [Docker website](https://docs.docker.com/get-docker/).
## Installation

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

@ -2,6 +2,62 @@
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.14 (2024-12-03)
* Refactored `dotnet watch` command in solution runner.
* Added multi-tenancy option for open source startup templates.
* Implemented adding angular library when a new microservice is created.
* Adjusted *Optional Modules* section in solution configurations
* Fixed bugs in the nolayers host project.
## 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

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

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

@ -4,7 +4,9 @@ This document provides a general overview of the relationship between various ve
| **ABP Studio Version** | **ABP Version of Startup Template** |
|------------------------|---------------------------|
| 0.9.5 | 8.3.3 |
| 0.9.9 to 0.9.14 | 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 |
@ -19,4 +21,4 @@ This document provides a general overview of the relationship between various ve
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)
![](images/abp-studio-switch-to-preview.png)

BIN
docs/en/tutorials/book-store-with-abp-suite/images/abp-suite-generated-tests.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/abp-suite-navigation-property.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/abp-suite-opening.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/abp-suite-solution-test-projects.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/book-store-suite-solution-explorer.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/bookstore-test-succeed.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/studio-browser-suite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-author-entity-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-author-entity-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-author-new-entity.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-author-pages-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-selection.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-book-pages-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-book-with-author-create-modal.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-bookstore-advanced-filter-section.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-custom-code-result.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-enabling-custom-code.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-end-of-generation-modal.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/suite-repository-custom-code.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
docs/en/tutorials/book-store-with-abp-suite/images/test-data-seed-contributors.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

40
docs/en/tutorials/book-store-with-abp-suite/index.md

@ -0,0 +1,40 @@
# Web Application Development (with ABP Suite) Tutorial
````json
//[doc-params]
{
"UI": ["MVC"],
"DB": ["EF"]
}
````
````json
//[doc-nav]
{
"Next": {
"Name": "Creating the Solution",
"Path": "tutorials/book-store-with-abp-suite/part-01"
}
}
````
> This tutorial is suitable for those who have an ABP Team or a higher [license](https://abp.io/pricing).
## About This Tutorial
> In this tutorial, you will use the [ABP Suite](../../suite/index.md) to generate everything you need to build the **BookStore** application, such as [*Entities*](../../framework/architecture/domain-driven-design/entities.md), [*Domain Services*](../../framework/architecture/domain-driven-design/domain-services.md), [*Application Services*](../../framework/architecture/domain-driven-design/application-services.md), *CRUD pages* and more...
In this tutorial series, you will build an ABP based web application named `Acme.BookStore`. This application is used to manage a list of books and their authors. It is developed using the following technologies:
* **{{DB_Value}}** as the database provider.
* **{{UI_Value}}** as the UI Framework.
This tutorial is organized as the following parts:
- [Part 1: Creating the Solution](part-01.md)
- [Part 2: Creating the Books](part-02.md)
- [Part 3: Creating the Authors](part-03.md)
- [Part 4: Book to Author Relation](part-04.md)
- [Part 5: Customizing the Generated Code](part-05.md)
### Download the Source Code
After logging in to the ABP website, you can download the source code from [here](https://abp.io/api/download/samples/suite-bookstore-mvc-ef).

40
docs/en/tutorials/book-store-with-abp-suite/part-01.md

@ -0,0 +1,40 @@
# Web Application Development (with ABP Suite) Tutorial - Part 1: Creating the Solution
````json
//[doc-params]
{
"UI": ["MVC"],
"DB": ["EF"]
}
````
````json
//[doc-nav]
{
"Next": {
"Name": "Creating the Books",
"Path": "tutorials/book-store-with-abp-suite/part-02"
}
}
````
Before starting the development, create a new solution named `Acme.BookStore` and run it by following the [getting started tutorial](../../get-started/layered-web-application.md).
You can use the following configurations:
* **Solution Name:** `Acme.BookStore`
* **UI Framework:** {{if UI=="MVC"}} ASP.NET Core MVC / Razor Pages {{end}}
* **UI Theme:** LeptonX
* **Mobile Framework:** None
* **Database Provider:** {{if DB=="EF"}} Entity Framework Core {{end}}
You can select the other options based on your preference.
> **Please complete the [Get Started](../../get-started/layered-web-application.md) guide and run the web application before going further.**
The initial solution structure should be like the following in the ABP Studio's [Solution Explorer](../../studio/solution-explorer.md):
![](./images/book-store-suite-solution-explorer.png)
## Summary
We've created the initial layered monolith solution. In the next part, we will learn how to create entities, and generate CRUD pages based on the specified options (including tests, UI, customizable code support etc.) with [ABP Suite](../../suite/index.md).

123
docs/en/tutorials/book-store-with-abp-suite/part-02.md

@ -0,0 +1,123 @@
# Web Application Development (with ABP Suite) Tutorial - Part 2: Creating the Books
````json
//[doc-params]
{
"UI": ["MVC"],
"DB": ["EF"]
}
````
````json
//[doc-nav]
{
"Previous": {
"Name": "Creating the Solution",
"Path": "tutorials/book-store-with-abp-suite/part-01"
},
"Next": {
"Name": "Creating the Authors",
"Path": "tutorials/book-store-with-abp-suite/part-03"
}
}
````
In this part, you will create a new entity named `Book` and generate CRUD pages for the related entities with everything that you would normally implement manually (including application services, tests, CRUD pages, database relations and more...) via [ABP Suite](../../suite/index.md) with few clicks.
## Opening the ABP Suite
> Please **stop the application** in ABP Studio's *Solution Runner* panel, if it's currently running, because ABP Suite will make changes in the solution and it might need to build the solution in some steps and running the solution prevents to build it.
After creating the solution in the previous part, now you can open the ABP Suite and start generating CRUD pages. You can select the *ABP Suite -> Open* command on the main menu to open ABP Suite:
![opening the ABP Suite](./images/abp-suite-opening.png)
After clicking the related command, pre-integrated browser of ABP Studio should open, then you can start generating entities and all related codes with a few configurations:
![](./images/studio-browser-suite.png)
## Creating the Book Entity
Let's create a `Book` entity with some properties. First, type `Book` for the *Name* field and leave the other options as is. ABP Suite automatically calculates proper values for the rest of the inputs for you:
![](./images/suite-book-entity-1.png)
ABP Suite sets:
* Entity type as **master** (ABP Suite allows you to establish [master-child relationship](../../suite/creating-master-detail-relationship.md)),
* Base class as **FullAuditedAggregateRoot** ([see other possible values](../../framework/architecture/domain-driven-design/entities.md)),
* Primary key type as **Guid**,
* Plural name, database name, namespace, page title, menu item and more...
You can change the menu-item value as **book** to show a proper icon in the generated UI, and also enable **code customization**, **creating unit & integration tests**, and other options as you wish:
![](./images/suite-book-entity-2.png)
After, specifying the entity metadata, open the *Properties* tab and create the properties shown in the following figure:
![](./images/suite-book-entity-3.png)
Here the details:
* `Name` is **required**, it's a **string** property and maximum length is **128**.
* `Type` is an **enum** and the enum file path is *\Acme.BookStore.Domain.Shared\Books\BookType.cs* (we will create the file, in the next section).
* `PublishDate` is a **DateTime** property and **not nullable**.
* `Price` is a **float** property and **required**.
You can leave the other configurations as default.
> ABP Suite allows you to define properties with a great range of options, for example, you can specify the property type as *string*, *int*, *float*, *Guid*, *DateTime*, and even *File* (for file upload) and also you can set any options while defining your properties, such as specifying it as *required*, or *nullable*, setting *max-min length*, *default value* and more...
While defining the properties, you defined a *Type* property with the type of *enum*. ABP Suite asks for an enum path to read the enum file, and set the namespace, and enum name in the generated code.
For that purpose, you should create a `BookType` enum in the `Acme.BookStore.Domain.Shared` project under the **Books** folder as follows:
```csharp
namespace Acme.BookStore.Books;
public enum BookType
{
Undefined,
Adventure,
Biography,
Dystopia,
Fantastic,
Horror,
Science,
ScienceFiction,
Poetry
}
```
Then, you can specify the enum path for the `Type` property in ABP Suite like in the following figure:
![](./images/suite-book-entity-4.png)
> After you select the enum file, ABP Suite automatically sets the namespace and enum name, and lists your enum values in the next section. You can change these values, but for now, you can leave as is.
After that, you can click the **Save and Generate** button to start the code generation process:
![](./images/suite-book-entity-5.png)
ABP Suite will generate the necessary code for you. It generates:
* `Book` entity (also `BookBase` class, which is allow you customizing the generated entity),
* Repository implementation (`EfCoreBookRepository` class),
* `BookManager` domain service,
* Input & Output **DTOs** and **application service** implementations (`IBookAppService` & `BookAppService`),
* **Unit & integration tests**,
* A new **migration** (and also applies to the database),
* All related **permission**, **object mapping** and **navigation menu item** configurations,
* and all required **UI components and pages**.
It will take some time to complete the process. After the process is completed, you will see a success message, you can click the *Ok* button, and build & start the application by clicking the *Run -> Build & Start* button in the *Solution Runner* panel:
![](./images/suite-book-entity-6.png)
After the application is started, you can right-click and *Browse* on the application to open it in the ABP Studio's pre-integrated browser. You can see the Books page in the following figure with a single record:
![](./images/suite-book-pages-1.png)
On this page, you can create a new book, update an existing book, delete a book, export all records (or the filtered records) to excel, filter the records by using the advanced filter section, bulk delete multiple records and so on.
## Summary
In this part, you've created a new entity named `Book` and generated the necessary code for it with [ABP Suite](../../suite/index.md) with a few clicks. ABP Suite generated the all code for you, including the **entity**, **application service**, **database relations**, **unit & integration tests**, **UI** and **defined the custom hooks for code customization**.

79
docs/en/tutorials/book-store-with-abp-suite/part-03.md

@ -0,0 +1,79 @@
# Web Application Development (with ABP Suite) Tutorial - Part 3: Creating the Authors
````json
//[doc-params]
{
"UI": ["MVC"],
"DB": ["EF"]
}
````
````json
//[doc-nav]
{
"Previous": {
"Name": "Creating the Books",
"Path": "tutorials/book-store-with-abp-suite/part-02"
},
"Next": {
"Name": "Book to Author Relation",
"Path": "tutorials/book-store-with-abp-suite/part-04"
}
}
````
In the previous part, you have created the `Book` entity and in this part, you will create a new entity named `Author` and generate all necesssary code via [ABP Suite](../../suite/index.md) with few clicks. After creating the `Author` entity, you will be establishing [one-to-many relationship](../../suite/generating-crud-page.md#step-by-step-creating-a-navigation-property-with-1-to-many-relationship) with *Book* and *Author* entities, in the next part.
## Creating the Author Entity
After generating the all necessary code for the `Book` entity, and testing the *Books* page, by building & starting the application, now you can continue with creating the `Author` entity.
> Before, creating the `Author` entity, please **stop the application** in ABP Studio's *Solution Runner* panel, because ABP Suite will make changes in the solution and it might need to build the solution in some steps and running the solution prevents to build it.
Click the entity selection box in the top right of the *CRUD page generation* page, and select the *-New entity-*:
![](/images/suite-author-new-entity.png)
Then, you can type `Author` for the *Name* field and leave the other options as is (you can change the menu icon as **pen** for a proper menu icon, and/or other options, if you wish). ABP Suite automatically calculates proper values for the rest of the inputs for you:
![](/images/suite-author-entity-1.png)
ABP Suite sets:
* Entity type as **master** (ABP Suite allows you to establish [master-child relationship](../../suite/creating-master-detail-relationship.md)),
* Base class as **FullAuditedAggregateRoot** ([see other possible values](../../framework/architecture/domain-driven-design/entities.md)),
* Primary key type as **Guid**,
* Plural name, database name, namespace, page title, menu item and more...
* Also, it enables **code customization**, **UI code generation**, **unit & integration test generation** and **bulk delete** by default.
After, specifying the entity metadata, open the *Properties* tab and create the properties shown in the following figure:
![](./images/suite-author-entity-2.png)
Here the details:
* `Name` is **required**, it's a **string** property, and it's a **textarea**. Minimum length is **2** and maximum length is **128**.
* `BirthDate` is a **DateTime** property and **not nullable**.
* `ShortBio` is a **string** property, it's **required**, maximum length is **256**.
You can leave the other configurations as default.
> **Note:** All properties are marked as **filterable** by default, and they appear in the advanced filter section because of that. You can set any properties you want as **not filterable** and then the related property will be removed from the advanced filter section and code will be generated accordingly.
You can click the **Save and Generate** button to start the code generation process:
![](./images/suite-book-entity-5.png)
ABP Suite will generate the necessary code for you. It will take some time to complete the process. After the process is completed, you will see a success message, you can click the *Ok* button, and build & start the application by clicking the *Run -> Build & Start* button in the *Solution Runner* panel:
![](./images/suite-book-entity-6.png)
After the application is started, you can right-click and *Browse* on the application to open it in the ABP Studio's pre-integrated browser and try to add a new author:
![](./images/suite-author-pages-1.png)
As you can see, the *Name* field is **required**, the *Birth Date* field shows a datepicker, and the *Short Bio* field is also **required** and it's a **textarea**. You just configured how you want your properties with some options (for example, setting the short bio as **textarea** and **required**), and ABP Suite generated code according that.
## Summary
In this part, you've created a new entity named `Author` and generated the necessary code for it with [ABP Suite](../../suite/index.md) with a few clicks. ABP Suite generated the all code for you, including the **entity**, **application service**, **database relations**, **unit & integration tests**, **UI** and **defined the custom hooks for code customization**.
In the next part, you will establish [one-to-many relation](../../suite/generating-crud-page.md) between the `Book` and `Author` entities.

168
docs/en/tutorials/book-store-with-abp-suite/part-04.md

@ -0,0 +1,168 @@
# Web Application Development (with ABP Suite) Tutorial - Part 4: Book to Author Relation
````json
//[doc-params]
{
"UI": ["MVC"],
"DB": ["EF"]
}
````
````json
//[doc-nav]
{
"Previous": {
"Name": "Creating the Author",
"Path": "tutorials/book-store-with-abp-suite/part-03"
},
"Next": {
"Name": "Customizing the Generated Code",
"Path": "tutorials/book-store-with-abp-suite/part-05"
}
}
````
In the previous parts, you have created the `Book` and `Author` entities (& generated code for all functionalities) for the book store application. However, currently there is no relation between these entities.
In this part, you will establish to **one-to-many relation** between the `Book` and `Author` entities.
## Establishing Relations with ABP Suite
ABP Suite allows establishing both **one-to-many** and [many-to-many](../../suite/creating-many-to-many-relationship.md) relationships.
In this tutorial, you will only establish **one-to-many relation** between `Book` and `Author` entities. It's pretty straightforward to establish a relationship with ABP Suite. You should just need to navigate to the *Navigations* tab, and provide the metadata for navigation property (1-n) or navigation collection (n-n) relations.
## Creating Book to Author Relationship
> Please **stop the application** in ABP Studio's *Solution Runner* panel, because ABP Suite will make changes in the solution and it might need to build the solution in some steps and running the solution prevents to build it.
To establish **one-to-many relations** between *Book* and *Author* entities, select the `Book` entity from the entity selection box on the top-right of the *CRUD page generation* page:
![](./images/suite-book-entity-selection.png)
Then, you can open the *Navigations* tab, and click the **Add navigation property (1-n)** button. After that, a navigation property model will open, and you can fill the fields like in the following figure:
![](./images/abp-suite-navigation-property.png)
Here is the details:
* Selected the entity as `Author`. (ABP Suite will establish one-to-many relation between *Book* and *Author* entities with this configuration)
* Set the property name as *AuthorId*, it will be set as foreign-key restriction in the database and all related database configurations will be made by ABP Suite.
* Selected the display property as *Name*, this will be used in the dropdown component to set an author with a book & also it will be shown in the datatable of the *Books* page.
* Also, made the relation **required** and set it **filterable** so books can be filterable by authors.
After, specifying the metadata, you can click the *Ok* button to close the modal. Then, click the **Save and generate** button to start code generation process. ABP Suite will establish one-to-many relationship between the entities, and will generate all necessary code automatically:
![](./images/suite-end-of-generation-modal.png)
It will take some time to complete the process. After the process is completed, you will see a success message, you can click the *Ok* button, and build & start the application by clicking the *Run -> Build & Start* button in the *Solution Runner* panel:
![](./images/suite-book-entity-6.png)
After the application is started, you can right-click and *Browse* on the application to open it in the ABP Studio's pre-integrated browser. You can first create an author and then create a book with the author for testing:
![](./images/suite-book-with-author-create-modal.png)
Also, notice that, in the advanced filter section, there is an **Author** dropdown, which you can use to filter books by authors (remember you set **filterable** while defining navigation property and thanks to that, ABP Suite generated the code accordingly):
![](./images/suite-bookstore-advanced-filter-section.png)
## Unit & Integration Tests
Since you completed the bookstore application, now we can check the generated tests, and run them to see if all of them pass or not.
There are several test projects in the solution:
![](./images/abp-suite-solution-test-projects.png)
> Test projects slightly differs based on your UI and Database selection. For example, if you select MongoDB, then the `Acme.BookStore.EntityFrameworkCore.Tests` will be `Acme.BookStore.MongoDB.Tests`.
ABP Suite generated unit & integration tests, for the `Book` & `Author` entities. If you open the **Test explorer** in your IDE, you will see the following tests are generated:
![](./images/abp-suite-generated-tests.png)
ABP Suite generated tests for repository implementations & application service implementations for the generated code, if you enable *Create unit & integration tests* option, while creating the entity. Since, you already did that in the previous parts, it generated the all required tests for the entities.
Let's examine one of the generated test classes. Open the *BooksAppServiceTests* (under the *test/Acme.BookStore.Application.Tests/Books/BookApplicationTests.cs*) and check the `CreateAsync` method:
```csharp
[Fact]
public async Task CreateAsync()
{
// Arrange
var input = new BookCreateDto
{
Name = "6c3d1eda8bf04852b7bd5dfdbbd93224b252478c2e474d4c8faf24fa6b182168ca830d4f80e64e4a8e363f33e151d1d34a04be4709274c7fbf2214f9bb3a16c3",
Type = default,
PublishDate = new DateTime(2006, 8, 21),
Price = 754882891,
AuthorId = Guid.Parse("602460f6-df6e-456a-89d9-8c5870dfc583")
};
// Act
var serviceResult = await _booksAppService.CreateAsync(input);
// Assert
var result = await _bookRepository.FindAsync(c => c.Id == serviceResult.Id);
result.ShouldNotBe(null);
result.Name.ShouldBe("6c3d1eda8bf04852b7bd5dfdbbd93224b252478c2e474d4c8faf24fa6b182168ca830d4f80e64e4a8e363f33e151d1d34a04be4709274c7fbf2214f9bb3a16c3");
result.Type.ShouldBe(default);
result.PublishDate.ShouldBe(new DateTime(2006, 8, 21));
result.Price.ShouldBe(754882891);
}
```
ABP Suite;
* Create the `BookCreateDto` input DTO object, and fill its values with dummy data to simulate creating a book,
* Then, it calls the `IBooksAppService.CreateAsync` method to create a book,
* And finally, asserts the returned result to see if it's as expected or not.
Notice, also the *AuthorId* is set in the `BookCreateDto` object. At that point, you might ask yourself that I haven't created the author with that ID before, should not it throw exception?
No, it will not throw an exception, because ABP Suite also generates simple dummy data for the entities just for the tests! You can see the test data seed contributors under the *Acme.BookStore.Domain.Tests* project:
![](./images/test-data-seed-contributors.png)
Here is the content of the `AuthorsDataSeedContributor.SeedAsync` method:
```csharp
public async Task SeedAsync(DataSeedContext context)
{
if (IsSeeded)
{
return;
}
await _authorRepository.InsertAsync(new Author
(
id: Guid.Parse("602460f6-df6e-456a-89d9-8c5870dfc583"),
name: "d7bbb3bff0d54ad799477298c4572e9c05fd1175ab21416da17d0001e2b697cd7fef99fdb4414f26a05789667a97442bd65865510ba34c3599e874ccf08b45e4",
birthDate: new DateTime(2010, 2, 11),
shortBio: "3c2ff43c18e34d7b9ad3f1b9c444cbb000f90808d3774cb6b7702b957f472d74048597f93df744f6a6fdf507be428e016edec982f1174e09b124982cbc40156290ce6bc9fd7b49b4972741956cc847891cb55ad0942f4534b90aa0561d3e0c200340b613c7ad40c38b4b2f2c39298169a853473faed34341a130b31e1eb57e92"
));
await _authorRepository.InsertAsync(new Author
(
id: Guid.Parse("6ea5a6b2-919e-4334-9728-13f4872e5e0e"),
name: "fd332fb58f184716962b08fbaa92f1c3e0963d843ba34c82bb5409517f60da3727c43b05e8d4490f996c5d19265962e53a69ed5e3e144509aad1441e37ce5081",
birthDate: new DateTime(2010, 6, 10),
shortBio: "b7808946c46c42e3935c4d8203d82973cfb98c5d81644f1da4ce1e643767849e23e0eb12a92f48be8f7eec0c07aefa043721fdd3fea542cfa644d2b7d428dc8842647180ef8a47139e097f6674c4f0d86c46765c406042a2a858865cb112ecd78d9ef6f5843e444994641f924a38a2d24ee4e212d41444888d3c0861af0cf9dd"
));
await _unitOfWorkManager!.Current!.SaveChangesAsync();
IsSeeded = true;
}
```
Since ABP Suite generated the test data seed contributors for each entity, you have initial data while testing your services. Also, as you would notice, the id in this example (*602460f6-df6e-456a-89d9-8c5870dfc583*) is same as the *authorId* field in the `BooksAppServiceTests.CreateAsync` method.
Let's execute all tests, and see the results:
![](./images/bookstore-test-succeed.png)
## Summary
So far, you have created the all functionality for the bookstore application without needing to write any single line of code. ABP Suite generated the entities, application services, UI components, unit & integration tests and more...
In the next part, you will write some code and modify the ABP Suite's generated code by writing the code in the specified hookpoints. Thanks to [ABP Suite's Customized Code Support](../../suite/customizing-the-generated-code.md), in the next generation, our custom code will not be overridden and will be preserved.

123
docs/en/tutorials/book-store-with-abp-suite/part-05.md

@ -0,0 +1,123 @@
# Web Application Development (with ABP Suite) Tutorial - Part 5: Customizing the Generated Code
````json
//[doc-params]
{
"UI": ["MVC"],
"DB": ["EF"]
}
````
````json
//[doc-nav]
{
"Previous": {
"Name": "Book to Author Relation",
"Path": "tutorials/book-store-with-abp-suite/part-04"
}
}
````
So far, you have created the all functionality for the bookstore application without needing to write any single line of code. In this part, let's write some code and check one of the great features of the ABP Suite, which is [Customizable Code Support](../../suite/customizing-the-generated-code.md).
## Customizable Code Support
ABP Suite allows you to customize the generated code blocks and preserve your custom code changes in the next CRUD Page Generation. It specifies hook points to allow adding custom code blocks. Then, the code written by you to these hook points will be respected and will not be overridden in the next CRUD Page Generation.
To enable custom code support, you should check the *Customizable code* option in the **CRUD Page Generation** page (it's selected by default), and you enabled it for both entities:
![](./images/suite-enabling-custom-code.png)
## Custom Code Hookpoints
When you enable the *custom code support*, ABP Suite adds some hookpoints that you can write your own custom code without worrying about, are my codes being overridden with the next CRUD page generation.
On the C# side, ABP Suite adds abstract base classes for entities, application services, interfaces, domain services and so on... (and partial classes for interfaces)
You can write your custom code in those classes (with the `*.Extended.cs` extension) and next time when you need to re-generate the entity, your custom code will not be overridden (only the base abstract classes will be re-generated and your changes on Suite will be respected):
![](./images/suite-repository-custom-code.png)
> For example, you can create a new repository method like in the example above, and in the next CRUD page generation, you will ABP Suite won't override your custom code.
On the UI side, ABP Suite provides convenient comment placeholders within pages for MVC, Blazor, and Angular UIs. These comment sections serve as hook points where you can add your custom code.
For example, if you open the *Books/Index.cshtml* file in your IDE, you will see those placeholders like following:
```xml
<!-- Code omitted for brevity -->
@section styles
{
@*//<suite-custom-code-block-1>*@
@*//</suite-custom-code-block-1>*@
}
<!-- ... -->
```
You can write your custom codes between the _**<suite-custom-code-block-n></suite-custom-code-block-n>**_ placeholders and you can also extend these placeholders by customizing the [ABP Suite templates](../../suite/editing-templates.md).
> For more information, please refer to [Customizing the Generated Code documentation](../../suite/customizing-the-generated-code.md)
## Implementing Custom Code
Let's see the custom code support in action. We can demonstrate this feature with an easy example.
Assume that we want to show the author's name with his abbreviated name. For example, for the author *John Ronald Reuel Tolkien*, we want to show the name *John Ronald Reuel Tolkien (a.k.a J.R.R.T)*. Achieving that is pretty straightforward.
We just need to open the *src/Acme.BookStore.Application/Books/BooksAppService.Extended.cs* file and override the base `GetListAsync` method, which is called on the books page:
```csharp
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Caching;
namespace Acme.BookStore.Books
{
public class BooksAppService : BooksAppServiceBase, IBooksAppService
{
//<suite-custom-code-autogenerated>
public BooksAppService(IBookRepository bookRepository, BookManager bookManager, IDistributedCache<BookDownloadTokenCacheItem, string> downloadTokenCache, IRepository<Acme.BookStore.Authors.Author, Guid> authorRepository)
: base(bookRepository, bookManager, downloadTokenCache, authorRepository)
{
}
//</suite-custom-code-autogenerated>
//Write your custom code...
public override async Task<PagedResultDto<BookWithNavigationPropertiesDto>> GetListAsync(GetBooksInput input)
{
var result = await base.GetListAsync(input);
foreach (var book in result.Items)
{
var akaName = book.Author.Name.Split(" ").Select(q => q[0]).JoinAsString(".");
book.Author.Name += $" (a.k.a {akaName})";
}
return result;
}
}
}
```
* Here, we have overridden the `GetListAsync` method and changed its result according to our need.
* Notice, this class is derieved from the `BooksAppServiceBase` class and implements the `IBooksAppService`.
* Thus, ABP Suite only modifies the `BooksAppServiceBase` class and implements the necessary services in each generation, but does not generate the files with the `*.Extended` postfixes and let you implement your own custom code.
* You can create new methods, override an existing method and change its behaviour, add custom hookpoints to extend customization capabilities and more...
Now, we can open ABP Suite and try to regenerate the book entity and see if our custom code is gone or not:
![](./images/suite-end-of-generation-modal.png)
After the regeneration has been completed, we can check the **BooksAppService.Extended.cs** file and we should see our custom code is there without any modification. ABP Suite didn't override our custom code, and finally, we can run the application to see the final result:
![](./images/suite-custom-code-result.png)
ABP Suite's custom code support is not limited to the backend side. You can also override the UI. You can refer to the [Customizing the Generated Code document](../../suite/customizing-the-generated-code.md) for further info.
## Summary
In this tutorial, you created the bookstore application without needing to write a single line of code with ABP Suite. Then, in this last part, you have written custom code in the specified hookpoints and it did not override by ABP Suite.

10
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"]
}
````
@ -34,9 +34,9 @@ For such cases, run the `abp install-libs` command on the root directory of your
abp install-libs
```
> We suggest you install [Yarn](https://classic.yarnpkg.com/) to prevent possible package inconsistencies, if you haven't installed it yet.
> We suggest you install [Yarn v1.22+ (not v2)](https://classic.yarnpkg.com/en/docs/install) 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(

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

Loading…
Cancel
Save