Browse Source

Merge branch 'dev' into blazor-binding-runtime

pull/19968/head
liangshiwei 1 year ago
parent
commit
b6dd0713ba
  1. 8
      Directory.Packages.props
  2. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  3. BIN
      docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/community-talks.png
  4. BIN
      docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/cover-image.png
  5. 93
      docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/post.md
  6. BIN
      docs/en/Blog-Posts/2024-11-19 v9_0_Release_Stable/switch-to-stable.png
  7. 385
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/POST.md
  8. BIN
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/chat-example.gif
  9. BIN
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/cover-image.png
  10. BIN
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/image-generation-example.gif
  11. BIN
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/rag-example-1.gif
  12. BIN
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/rag-example-2.gif
  13. BIN
      docs/en/Community-Articles/2024-12-01-OpenAI-Integration/sample-page.png
  14. 234
      docs/en/Community-Articles/2024-12-09-Unit-Test/POST.md
  15. 8
      docs/en/cli/index.md
  16. 6
      docs/en/contribution/index.md
  17. 4
      docs/en/deployment/configuring-openIddict.md
  18. 66
      docs/en/docs-nav.json
  19. 2
      docs/en/framework/fundamentals/dependency-injection.md
  20. 18
      docs/en/framework/infrastructure/audit-logging.md
  21. 2
      docs/en/framework/ui/angular/quick-start.md
  22. 3
      docs/en/framework/ui/maui/index.md
  23. 2
      docs/en/framework/ui/mvc-razor-pages/client-side-package-management.md
  24. 2
      docs/en/framework/ui/react-native/index.md
  25. BIN
      docs/en/get-started/images/abp-studio-microservice-solution-runner-docker-dependencies.png
  26. BIN
      docs/en/get-started/images/abp-studio-microservice-solution-runner-enable-watch-1.png
  27. BIN
      docs/en/get-started/images/abp-studio-microservice-solution-runner-enable-watch-2.png
  28. BIN
      docs/en/get-started/images/abp-studio-microservice-solution-runner-enable-watch.png
  29. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-additional-options-0.9.13.png
  30. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-0.9.13.png
  31. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-configurations-efcore-0.9.13.png
  32. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-configurations-mongo-0.9.13.png
  33. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-provider-efcore-0.9.13.png
  34. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-provider-mongo-0.9.13.png
  35. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-solution-properties-0.9.13.png
  36. BIN
      docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-0.9.13.png
  37. BIN
      docs/en/get-started/images/abp-studio-nolayers-new-solution-dialog-ui-theme-0.9.13.png
  38. 2
      docs/en/get-started/index.md
  39. 6
      docs/en/get-started/layered-web-application.md
  40. 40
      docs/en/get-started/microservice.md
  41. 28
      docs/en/get-started/single-layer-web-application.md
  42. BIN
      docs/en/images/generic-repositories.png
  43. BIN
      docs/en/images/idle-message.png
  44. BIN
      docs/en/images/idle-setting.png
  45. BIN
      docs/en/images/pen-test-alert-list-9.0.png
  46. BIN
      docs/en/images/suite-registry.png
  47. 1
      docs/en/modules/account-pro.md
  48. 19
      docs/en/modules/account/idle-session-timeout.md
  49. 46
      docs/en/others/penetration-test-report.md
  50. 2
      docs/en/samples/easy-crm.md
  51. 4
      docs/en/solution-templates/microservice/guides/add-new-microservice.md
  52. BIN
      docs/en/studio/images/solution-runner/cli-application-context-menu.png
  53. BIN
      docs/en/studio/images/solution-runner/csharp-application-context-menu-build.png
  54. BIN
      docs/en/studio/images/solution-runner/csharp-application-context-menu-monitor.png
  55. BIN
      docs/en/studio/images/solution-runner/csharp-application-context-menu.png
  56. BIN
      docs/en/studio/images/solution-runner/folder-context-menu-add.png
  57. BIN
      docs/en/studio/images/solution-runner/folder-context-menu-build.png
  58. BIN
      docs/en/studio/images/solution-runner/folder-context-menu.png
  59. BIN
      docs/en/studio/images/solution-runner/manage-start-actions.png
  60. BIN
      docs/en/studio/images/solution-runner/profile-root-context-menu-add.png
  61. BIN
      docs/en/studio/images/solution-runner/profile-root-context-menu-build.png
  62. BIN
      docs/en/studio/images/solution-runner/profile-root-context-menu.png
  63. BIN
      docs/en/studio/images/solution-runner/solutioın-runner-properties.png
  64. 4
      docs/en/studio/installation.md
  65. 25
      docs/en/studio/release-notes.md
  66. 67
      docs/en/studio/running-applications.md
  67. 3
      docs/en/studio/version-mapping.md
  68. 18
      docs/en/suite/how-to-start.md
  69. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/abp-suite-generated-tests.png
  70. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/abp-suite-navigation-property.png
  71. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/abp-suite-opening.png
  72. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/abp-suite-solution-test-projects.png
  73. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/book-store-suite-solution-explorer.png
  74. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/bookstore-test-succeed.png
  75. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/studio-browser-suite.png
  76. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-author-entity-1.png
  77. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-author-entity-2.png
  78. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-author-new-entity.png
  79. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-author-pages-1.png
  80. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-1.png
  81. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-2.png
  82. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-3.png
  83. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-4.png
  84. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-5.png
  85. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-6.png
  86. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-entity-selection.png
  87. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-pages-1.png
  88. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-book-with-author-create-modal.png
  89. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-bookstore-advanced-filter-section.png
  90. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-custom-code-result.png
  91. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-enabling-custom-code.png
  92. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-end-of-generation-modal.png
  93. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/suite-repository-custom-code.png
  94. BIN
      docs/en/tutorials/book-store-with-abp-suite/images/test-data-seed-contributors.png
  95. 40
      docs/en/tutorials/book-store-with-abp-suite/index.md
  96. 47
      docs/en/tutorials/book-store-with-abp-suite/part-01.md
  97. 123
      docs/en/tutorials/book-store-with-abp-suite/part-02.md
  98. 79
      docs/en/tutorials/book-store-with-abp-suite/part-03.md
  99. 170
      docs/en/tutorials/book-store-with-abp-suite/part-04.md
  100. 123
      docs/en/tutorials/book-store-with-abp-suite/part-05.md

8
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" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.2" />
<PackageVersion Include="NSubstitute" Version="5.1.0" />
<PackageVersion Include="NuGet.Versioning" Version="6.11.1" />
<PackageVersion Include="NUglify" Version="1.21.9" />
@ -125,7 +125,7 @@
<PackageVersion Include="OpenIddict.Server.AspNetCore" Version="5.8.0" />
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="5.8.0" />
<PackageVersion Include="OpenIddict.Validation.ServerIntegration" Version="5.8.0" />
<PackageVersion Include="Oracle.EntityFrameworkCore" Version="8.23.60" />
<PackageVersion Include="Oracle.EntityFrameworkCore" Version="9.23.60" />
<PackageVersion Include="Polly" Version="8.4.2" />
<PackageVersion Include="Polly.Extensions.Http" Version="3.0.0" />
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="9.0.0-preview.1" />

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

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

234
docs/en/Community-Articles/2024-12-09-Unit-Test/POST.md

@ -0,0 +1,234 @@
# The new Unit Test structure in ABP application
A typical ABP modular project usually consists of three main projects: `Application`, `Domain`, and `EntityFrameworkCore/MongoDB`. In these projects, we may provide many services that require unit testing.
Using abstract unit test classes involves first writing tests in the `Application` and `Domain` layers that are independent of the storage technology, ensuring the correctness of core business logic. These abstract tests are then implemented in `EntityFrameworkCore` or `MongoDB`. The benefits of this approach include:
1. **Reduced Coupling**: Core logic tests do not depend on specific storage technologies, so switching databases does not require rewriting test code.
2. **Better Isolation**: Focuses on verifying business logic correctness, avoiding interference from database operations.
3. **Increased Reusability**: The same abstract tests can be reused with different storage implementations.
4. **Easier Maintenance and Extensibility**: Different storage implementations can be extended independently without breaking existing tests.
5. **Faster and More Reliable Tests**: Reduces dependency on databases, making tests faster and more stable.
## How to migrate old unit tests to the new unit test structure
Assume our project name is `MyCompanyName.MyProjectName`.
### Changes to the `MyCompanyName.MyProjectName.Application.Tests` project:
1. Remove the `MyCompanyName.MyProjectName.Application.Tests` project's `MyProjectNameApplicationCollection` class.
2. Modify the `MyCompanyName.MyProjectName.Application.Tests` project's `MyProjectNameApplicationTestBase` class.
```csharp
public abstract class MyProjectNameApplicationTestBase<TStartupModule> : MyProjectNameTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
//...
}
```
3. Modify the `MyCompanyName.MyProjectName.Application.Tests` project's unit test classes to become abstract unit test classes, such as: `SampleAppServiceTests`.
```csharp
public abstract class SampleAppServiceTests<TStartupModule> : MyProjectNameApplicationTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
[Fact]
public async Task Initial_Data_Should_Contain_Admin_User()
{
//...
}
}
```
### Changes to the `MyCompanyName.MyProjectName.Domain.Tests` project:
1. Remove the `MyCompanyName.MyProjectName.Domain.Tests` project's `MyProjectNameDomainCollection` class.
2. Modify the `MyCompanyName.MyProjectName.Domain.Tests` project's `MyProjectNameDomainTestBase` class.
```csharp
public abstract class MyProjectNameDomainTestBase<TStartupModule> : MyProjectNameTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
//...
}
```
3. Modify the `MyCompanyName.MyProjectName.Domain.Tests` project's unit test classes to become abstract unit test classes, such as: `SampleDomainTests`.
```csharp
public abstract class SampleDomainTests<TStartupModule> : MyProjectNameDomainTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
[Fact]
public async Task Should_Set_Email_Of_A_User()
{
//...
}
}
```
4. Modify the `MyCompanyName.MyProjectName.Domain.Tests` project's `csproj` and module class. Remove references to `EntityFrameworkCore/MongoDB`.
`MyCompanyName.MyProjectName.Domain.Tests.csproj`:
```xml
<Project Sdk="Microsoft.NET.Sdk">
//...
<ItemGroup>
<ProjectReference Include="..\..\src\MyCompanyName.MyProjectName.Domain\MyCompanyName.MyProjectName.Domain.csproj" />
<ProjectReference Include="..\MyCompanyName.MyProjectName.TestBase\MyCompanyName.MyProjectName.TestBase.csproj" />
</ItemGroup>
</Project>
```
`MyProjectNameDomainTestModule.cs`:
```csharp
[DependsOn(
typeof(MyProjectNameDomainModule),
typeof(MyProjectNameTestBaseModule)
)]
public class MyProjectNameDomainTestModule : AbpModule
{
//...
}
```
### Changes to the `MyCompanyName.MyProjectName.EntityFrameworkCore.Tests` project:
Here, we need to create implementation classes for all abstract unit tests.
```csharp
[Collection(MyProjectNameTestConsts.CollectionDefinitionName)]
public class EfCoreSampleAppServiceTests : SampleAppServiceTests<MyProjectNameEntityFrameworkCoreTestModule>
{
//...
}
```
```csharp
[Collection(MyProjectNameTestConsts.CollectionDefinitionName)]
public class EfCoreSampleDomainTests : SampleDomainTests<MyProjectNameEntityFrameworkCoreTestModule>
{
//...
}
```
We also need to modify the project's dependencies and module class, which should directly or indirectly reference the `Application` and `Domain` test projects.
`MyCompanyName.MyProjectName.EntityFrameworkCore.Tests.csproj`:
```xml
<Project Sdk="Microsoft.NET.Sdk">
//...
<ItemGroup>
<ProjectReference Include="..\..\src\MyCompanyName.MyProjectName.EntityFrameworkCore\MyCompanyName.MyProjectName.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\MyCompanyName.MyProjectName.Application.Tests\MyCompanyName.MyProjectName.Application.Tests.csproj" />
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.EntityFrameworkCore.Sqlite\Volo.Abp.EntityFrameworkCore.Sqlite.csproj" />
</ItemGroup>
</Project>
```
`MyProjectNameEntityFrameworkCoreTestModule.cs`:
```csharp
[DependsOn(
typeof(MyProjectNameApplicationTestModule),
typeof(MyProjectNameEntityFrameworkCoreModule),
typeof(AbpEntityFrameworkCoreSqliteModule)
)]
public class MyProjectNameEntityFrameworkCoreTestModule : AbpModule
{
//...
}
```
### Changes to the `MyCompanyName.MyProjectName.MongoDB.Tests` project (skip this step if not using MongoDB):
Like the `EntityFrameworkCore` project, we need to create implementation classes for all abstract unit tests and modify the project's dependencies and module class.
```csharp
[Collection(MyProjectNameTestConsts.CollectionDefinitionName)]
public class MongoDBSampleAppServiceTests : SampleAppServiceTests<MyProjectNameMongoDbTestModule>
{
//...
}
```
```csharp
[Collection(MyProjectNameTestConsts.CollectionDefinitionName)]
public class MongoDBSampleDomainTests : SampleDomainTests<MyProjectNameMongoDbTestModule>
{
//...
}
```
```xml
<Project Sdk="Microsoft.NET.Sdk">
//...
<ItemGroup>
<ProjectReference Include="..\..\src\MyCompanyName.MyProjectName.MongoDB\MyCompanyName.MyProjectName.MongoDB.csproj" />
<ProjectReference Include="..\MyCompanyName.MyProjectName.Application.Tests\MyCompanyName.MyProjectName.Application.Tests.csproj" />
</ItemGroup>
</Project>
```
```csharp
[DependsOn(
typeof(MyProjectNameApplicationTestModule),
typeof(MyProjectNameMongoDbModule)
)]
public class MyProjectNameMongoDbTestModule : AbpModule
{
//...
}
```
### Changes to the `MyCompanyName.MyProjectName.Web.Tests` project:
We need to reference the `EntityFrameworkCore/MongoDB` test projects in this test project.
```xml
<Project Sdk="Microsoft.NET.Sdk">
//...
<ItemGroup>
<ProjectReference Include="..\MyCompanyName.MyProjectName.Application.Tests\MyCompanyName.MyProjectName.Application.Tests.csproj" />
<ProjectReference Include="..\..\src\MyCompanyName.MyProjectName.Web\MyCompanyName.MyProjectName.Web.csproj" />
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AspNetCore.TestBase\Volo.Abp.AspNetCore.TestBase.csproj" />
<ProjectReference Include="..\MyCompanyName.MyProjectName.EntityFrameworkCore.Tests\MyCompanyName.MyProjectName.EntityFrameworkCore.Tests.csproj" />
</ItemGroup>
</Project>
```
```csharp
[DependsOn(
typeof(AbpAspNetCoreTestBaseModule),
typeof(MyProjectNameWebModule),
typeof(MyProjectNameApplicationTestModule),
typeof(MyProjectNameEntityFrameworkCoreTestModule)
)]
public class MyProjectNameWebTestModule : AbpModule
{
//...
}
```
We no longer need the `MyProjectNameWebCollection` class in this project. Please delete it and use `[Collection(MyProjectNameTestConsts.CollectionDefinitionName)]` instead.
## Conclusion
This is our new unit test structure. Decoupling unit tests from storage technologies ensures the independence of business logic and allows easy switching between storage implementations. Abstract unit test classes improve test reusability, maintainability, and efficiency, reducing refactoring costs and providing flexibility for future tech updates.
## References
- [Unit Test](https://abp.io/docs/latest/testing/unit-tests)
- [Abstract all db-related unit tests](https://github.com/abpframework/abp/pull/17880)

8
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,15 +226,16 @@ 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.
* *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-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, or include if you want them (*Available for* ***Team*** *or higher licenses*). Available commands:
* `-no-saas`: Skips the Saas module.
* `-no-gdpr`: Skips the GDPR module.
* `-no-openiddict-admin-ui`: Skips the OpenIddict Admin UI module.
* `-no-audit-logging`: Skips the Audit Logging module.
* `-no-file-management`: Skips the File Management module.
* `-no-language-management`: Skips the Language Management module.
* `-no-text-template-management`: Skips the Text Template Management module.
* `-no-chat`: Skips the Chat module.
* `-file-management`: Includes the File Management module.
* `-chat`: Includes the Chat module.
* `--legacy`: Generates a legacy solution.
* `trust-version`: Trusts the user's version and does not check if the version exists or not. If the template with the given version is found in the cache, it will be used, otherwise throws an exception.

6
docs/en/contribution/index.md

@ -50,6 +50,12 @@ This is the recommended approach, since it automatically finds all missing texts
If you want to make a change on a specific resource file, you can find the file yourself, make the necessary change (or create a new file for your language) and send a pull request on GitHub.
### Commercial Modules
The commercial modules are not open source, and their localization files are not available in the public repository. The open-source module, `Account`, and the commercial module, `Account.Pro`, may have different translations.
If you would like to translate a commercial module, please [create an issue](https://github.com/abpframework/abp/issues/new) on Github, and we will provide the necessary files (`abp-translation.json` for one or all modules).
## Bug Report
If you find any bug, please [create an issue on the Github repository](https://github.com/abpframework/abp/issues/new).

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

@ -4,6 +4,8 @@ This document introduces how to configure `OpenIddict` in the `AuthServer` proje
There are different configurations in the `AuthServer` project for the `Development` and `Production` environments.
> If your solution does not include a project named `.AuthServer`, it means that you might have another project that depends on `AbpAccountPublicWebOpenIddictModule`. The project name can be `MyProject`, `MyProject.Web`, or `MyProject.HttpApi.Host`. They are both `Authentication Server` projects in that context.
````csharp
public override void PreConfigureServices(ServiceConfigurationContext context)
{
@ -38,6 +40,8 @@ To avoid that, consider creating self-signed certificates and storing them in th
You can use the `dotnet dev-certs https -v -ep openiddict.pfx -p 00000000-0000-0000-0000-000000000000` command to generate the `openiddict.pfx` certificate.
> `openiddict.pfx` is just an example of a filename. You can use any filename for the pfx file.
> `00000000-0000-0000-0000-000000000000` is the password of the certificate, you can change it to any password you want.
> Also, please remember to copy `openiddict.pfx` to the [Content Root Folder](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.hosting.ihostingenvironment.contentrootpath?view=aspnetcore-7.0) of the `AuthServer` website.

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"

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

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

@ -106,6 +106,24 @@ Configure<AbpAspNetCoreAuditingOptions>(options =>
`IgnoredUrls` is the only option. It is a list of ignored URLs prefixes. In the preceding example, all URLs starting with `/products` will be ignored for audit logging.
## AbpAspNetCoreAuditingUrlOptions
`AbpAspNetCoreAuditingUrlOptions` is the [options object](../fundamentals/options.md) to configure audit logging in the ASP.NET Core layer. You can configure it in the `ConfigureServices` method of your [module](../architecture/modularity/basics.md):
````csharp
Configure<AbpAspNetCoreAuditingUrlOptions>(options =>
{
options.IncludeQuery = true;
});
````
Here, a list of the options you can configure:
* `IncludeSchema` (default: `false`): If you set to true, it will include the schema in the URL.
* `IncludeHost` (default: `false`): If you set to true, it will include the host in the URL.
* `IncludeQuery` (default: `false`): If you set to true, it will include the query string in the URL.
## Enabling/Disabling Audit Logging for Services
### Enable/Disable for Controllers & Actions

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)

3
docs/en/framework/ui/maui/index.md

@ -40,6 +40,9 @@ Open a command line terminal and run the `adb reverse` command to expose a port
> You should replace "44305" with the real port.
> You should run the command after starting the emulator.
> If you don't have a separate installation of Android Debug Bridge, you can open it from **Visual Studio** by following toolbar menu `Tools` > `Android` > `Android Adb Command Prompt`. Android emulator has to be running for this operation.
### iOS
The iOS simulator uses the host machine network. Therefore, applications running in the simulator can connect to web services running on your local machine via the machines IP address or via the localhost hostname. For example, given a local secure web service that exposes a GET operation via the /api/todoitems/ relative URI, an application running on the iOS simulator can consume the operation by sending a GET request to https://localhost:<port>/api/todoitems/.

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)

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

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

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

BIN
docs/en/images/suite-registry.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 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

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/solution-templates/microservice/guides/add-new-microservice.md

@ -1,3 +1 @@
# ABP Studio Microservice Solution: Adding New Microservices
This document is planned to be written later.
> This document is [moved to here](../adding-new-microservices.md).

BIN
docs/en/studio/images/solution-runner/cli-application-context-menu.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/en/studio/images/solution-runner/csharp-application-context-menu-build.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 27 KiB

BIN
docs/en/studio/images/solution-runner/csharp-application-context-menu-monitor.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/en/studio/images/solution-runner/csharp-application-context-menu.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 22 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 14 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 14 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/en/studio/images/solution-runner/manage-start-actions.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
docs/en/studio/images/solution-runner/profile-root-context-menu-add.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 10 KiB

BIN
docs/en/studio/images/solution-runner/profile-root-context-menu-build.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
docs/en/studio/images/solution-runner/profile-root-context-menu.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/en/studio/images/solution-runner/solutioın-runner-properties.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 16 KiB

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

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

@ -2,6 +2,31 @@
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.15 (2024-12-05)
* Upgraded templates to version `9.0.1`.
* Fixed problems in the microservice service_nolayers template.
* Fixed microservice angular template for wrong file-management module reference.
* Fixed added extra lines in the hosts.txt file.
## 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.

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

@ -41,27 +41,22 @@ When you click *Add New Profile*, it opens the *Create New Profile* window. You
## Using the Profile
After selecting the current profile, which is the *Default* profile that comes pre-configured, we can utilize the tree items. This allows us to execute collective commands and create various tree structures based on our specific needs. You can navigate through the root of the tree and right-click to view the context menu, which includes 3 options: `Run`, `Build` and `Add`.
After selecting the current profile, which is the *Default* profile that comes pre-configured, we can utilize the tree items. This allows us to execute collective commands and create various tree structures based on our specific needs. You can navigate through the root of the tree and right-click to view the context menu, which includes the following options: `Start All`, `Stop All`, `Build`, `Add`, and `Manage Start Actions`.
![profile-root-context-menu](images/solution-runner/profile-root-context-menu.png)
### Run
### Start/Stop All
We can start/stop the applications with this option. Go to root of the tree and right-click to view the context menu, in this example *Acme.Bookstore(Default)* -> *Run*.
![profile-root-context-menu-run](images/solution-runner/profile-root-context-menu-run.png)
We can start/stop the applications with these options. Go to the root of the tree and right-click to view the context menu:
- `Start All`: Start all(CLI, C#) applications.
- `Stop All`: Stop all(CLI, C#) applications.
- `Build & Start All`: Builds each C# application in the [Background Tasks](./overview#background-tasks) and starts all (CLI, C#) applications after the build tasks are completed.
> `Start All` doesn't build the C# applications before running. If you're running it for the first time or if you've made changes, you should build the applications. You can simply use the `Build & Start All`.
> You can change the current profile while applications are running in the previous profile. The applications continue to run under the previous profile. For example if we start the `Acme.BookStore.AdministrationService`, `Acme.BookStore.IdentityService` applications when current profile is *team-1* and after change the current profile to *team-2* the applications continue to run under *team-1*.
> You can change the current profile while applications are running in the previous profile. The applications continue to run under the previous profile. For example, if we start the `Acme.BookStore.AdministrationService`, `Acme.BookStore.IdentityService` applications when the current profile is *team-1* and after changing the current profile to *team-2* the applications continue to run under *team-1*.
### Build
We can use common [dotnet](https://learn.microsoft.com/en-us/dotnet/core/tools) commands in this option. Go to root of the tree and right-click to view the context menu, in this example *Acme.Bookstore(Default)* -> *Build*, there are 4 options available:
We can use common [dotnet](https://learn.microsoft.com/en-us/dotnet/core/tools) commands in this option. Go to the root of the tree and right-click to view the context menu, in this example *Acme.Bookstore(Default)* -> *Build*, there are 4 options available:
![profile-root-context-menu-build](images/solution-runner/profile-root-context-menu-build.png)
@ -80,7 +75,7 @@ We can add 3 different item type to *Profile* for defining the tree structure. T
#### C# Application
When we go to root of the tree and right-click, in this example *Acme.BookStore(Default)* -> *Add* -> *C# Application* it opens the *Add Application* window. There are two methods to add applications: *This solution* and *External*. To add via the *This solution* tab, follow these steps:
When we go to the root of the tree and right-click, in this example *Acme.BookStore(Default)* -> *Add* -> *C# Application* it opens the *Add Application* window. There are two methods to add applications: *This solution* and *External*. To add via the *This solution* tab, follow these steps:
![profile-root-add-csharp-application](images/solution-runner/profile-root-add-csharp-application.png)
@ -98,7 +93,7 @@ The C# project doesn't have to be within the current [Solution Explorer](./solut
- `Path`: Provide the path to the .csproj file you wish to add. The path will be [normalized](https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats#path-normalization), allowing the project location to be flexible, as long as it's accessible from the current [ABP Solution](./concepts.md#solution).
- `Name`: Give an arbitrary name to see in solution runner. This name should be unique for each profile.
- `Launch url`: Is the url when we want to browse. But if added project doesn't have launch url we can leave it empty.
- `Launch url`: This is the url when we want to browse. But if the added project doesn't have launch url we can leave it empty.
- `Kubernetes service`: If you're not using the *Kubernetes* panel leave it empty. But if there is a helm chart for added application we should give the correct regex pattern. It's necessary for browse, when we connect the kubernetes cluster we should browse the services instead *Launch url*. Give the matching regex pattern for your helm chart kubernetes service name.
You can click the `OK` button to add the C# application to the profile.
@ -137,17 +132,27 @@ You can click the `OK` button to add the folder to the profile.
- To remove a folder from the tree, open the context menu by right-clicking the folder and selecting *Delete*.
- When starting applications, they continue to restart until the application starts gracefully. To stop the restarting process when attempting to restart the application, click the icon on the left. Additionally, you can review the *Logs* to understand why the application isn't starting gracefully.
### Manage Start Actions
This command will open a dialog where you can set start actions and start orders of sub-applications and sub-folders.
![manage-start-actions](images/solution-runner/manage-start-actions.png)
You can order the applications by dragging the icon in the first column. In the screenshot above, applications & folders are ordered like this: *Applications under infrastructure* > *Applications under services* > *Applications under gateways* > *AuthServer* > *Angular*. You can also set starting order and other actions for each folder by performing `right click > Manage Start Actions` on them.
- **Action**: There are two options: `Start` and `Don't start`. This is usefull if you want to exclude applications from batch start.
- **Build**: This option allows to disable/enable build before starting the application. If you are working on a single application, you can exclude the other applications from build to save time. This option can also be set by performing `right click > properties` on applications.
- **Watch**: When enabled, changes in your code are watched and dotnet hot-reloads the application or restarts it if needed. This option also can be set by performing `right click > properties` on applications.
## Folder
We already now why we need folder in the [previous](./running-applications.md#folder) section, we can use collective commands within this folder items. To do that go to folder and open the context menu by right-clicking, which includes 5 options `Start`, `Build`, `Add`, `Rename` and `Delete`.
We already now why we need folder in the [previous](./running-applications.md#folder) section, we can use collective commands within this folder items. To do that go to folder and open the context menu by right-clicking, which includes 5 options `Start`, `Stop`, `Build`, `Add`, `Manage Start Actions`, `Rename` and `Delete`.
![folder-context-menu](images/solution-runner/folder-context-menu.png)
### Start
You can see the context menu by right-clicking *Folder* -> *Start*, it's [similar](#run) like *Acme.BookStore(Default)* -> *Run* options, there are 3 options available. The only difference with root of the tree and folder is gonna be execute in selected folder.
### Start/Stop
![folder-context-menu-start](images/solution-runner/folder-context-menu-start.png)
You can see the context menu by right-clicking *Folder*. It will start/stop all the applications under the folder.
### Build
@ -157,7 +162,7 @@ You can see the context menu by right-clicking *Folder* -> *Start*, it's [simila
### Add
*Folder* -> *Add* context menu, it's the [same](#add) options like *Acme.BookStore(Default)* -> *Add* there are 3 options avaiable. The only difference, it's gonna add item to selected folder.
*Folder* -> *Add* context menu, it's the [same](#add) options like *Acme.BookStore(Default)* -> *Add* there are 3 options avaiable. The only difference, it's gonna add item to the selected folder.
![folder-context-menu-add](images/solution-runner/folder-context-menu-add.png)
@ -168,29 +173,16 @@ You can see the context menu by right-clicking *Folder* -> *Start*, it's [simila
## C# Application
The .NET icon indicates that the application is a C# project. After we [add](#c-application) the C# applications to root of the tree or folder, we can go to any C# application and right-click to view the context menu; `Run`, `Build`, `Browse`, `Requests`, `Exceptions`, `Logs`, `Copy URL`, `Properties`, `Remove`.
The .NET icon indicates that the application is a C# project. After we [add](#c-application) the C# applications to the root of the tree or folder, we can go to any C# application and right-click to view the context menu; `Start`, `Build`, `Browse`, `Requests`, `Exceptions`, `Logs`, `Copy URL`, `Properties`, `Remove`.
![csharp-application-context-menu](images/solution-runner/csharp-application-context-menu.png)
### Run
We have several options in C# applications. Those options are `Start`(If the application started this option shown as `Stop`), `Build & Start`(If the application started this option shown as `Build & Restart`), `Enable Watch`(If the watch is enabled this option shown as `Disable Watch`), `Restart`(It's only shown when the application started)
![csharp-application-context-menu-run](images/solution-runner/csharp-application-context-menu-run.png)
### Start
- `Start`: Starts the selected application. This option doesn't build before run. If you're running it for the first time or if you've made changes, you should build the application. If the application is started this option changed as `Stop`.
- `Build & Start`: We can simply use if we wanna build first and start. If the application is started this option changes to `Build & Restart`.
- `Enable Watch`: When this option is enabled, there's no need to perform `Build & Start` after any change. ABP Studio watches for changes, re-builds, and re-runs your application automatically upon saving. If this option is enabled it changes to `Disable Watch`.
- `Restart`: Restarts the application. This option visible only if the application started.
Starts the selected application. Once it is started, *Stop* and *Restart* options will be available.
> When you start the C# application, you should see a *chain* icon next to the application name, that means the started application connected to ABP Studio. C# applications can connect to ABP Studio even when running from outside the ABP Studio environment, for example debugging with Visual Studio. If the application is run from outside the ABP Studio environment, it will display *(external)* information next to the chain icon.
> 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
It's the [similar](#build) options like root of the tree options. The only difference between them it's gonna be execute the selected application.
@ -214,7 +206,10 @@ We can open the *Application Properties* window to change *Launch url*, *Kuberne
![solutioın-runner-properties](images/solution-runner/solutioın-runner-properties.png)
You can click the `OK` button to save the changes.
- **Skip build before starting**: When enabled, application is started without build and it makes starting faster. This is useful when you are working on a single application out of multiple, so you don't need to build others everytime they start.
- **Watch changes while running**: When enabled, you should see an *eye* icon next to the application name.
![csharp-application-context-menu-run-connection](images/solution-runner/csharp-application-context-menu-run-connection.png)
### Miscellaneous
@ -228,7 +223,7 @@ CLI applications uses the [powershell](https://learn.microsoft.com/en-us/powersh
![cli-application-context-menu](images/solution-runner/cli-application-context-menu.png)
- `Run`: This option includes 3 actions: *Start*, *Stop*, and *Restart* for the CLI application.
- `Start`: Starts the application. Once it is started, *Start* and *Restart* options will be available.
- `Browse`: This option is available when a *Launch URL* is specified upon adding the CLI application. It opens the *Browse* tab, can be clicked while the application is running.
- `Logs`: It opens the *Logs* tab, we can see the logs for *Start* and *Stop* commands.
- `Copy URL`: This option copies the *Launch URL* of the selected application. It is visible if there is a specified *Launch URL*

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

@ -4,7 +4,8 @@ This document provides a general overview of the relationship between various ve
| **ABP Studio Version** | **ABP Version of Startup Template** |
|------------------------|---------------------------|
| 0.9.9 to 0.9.11 | 9.0.0 |
| 0.9.15 | 9.0.1 |
| 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 |

18
docs/en/suite/how-to-start.md

@ -26,4 +26,20 @@ abp suite
If you run the ABP Suite with ABP CLI, then it will open in your default browser. Do not close the command line window until you finish your work, otherwise the Suite will not function. When you finish your work, you can return to the command line and press `CTRL+C` to close the Suite.
Remember that, first access to the Suite requires to have an active internet connection, so make sure you are connected to the internet.
Remember that, first access to the Suite requires to have an active internet connection, so make sure you are connected to the internet.
## Starting ABP Suite in Different Port
ABP Suite runs at port 3000 by default. If you want to run the ABP Suite in a different port, you can choose one of the following options:
1. You can pass the `--AbpSuite:ApplicationUrl` commandline parameter to run in a different port:
```bash
abp-suite --AbpSuite:ApplicationUrl="http://localhost:4000"
```
2. Update the `ApplicationUrl` in the _appsettings.json_ file of the dotnet tools directory (_%USERPROFILE%\.dotnet\tools\.store\volo.abp.suite\9.0.0\volo.abp.suite\9.0.0\tools\net9.0\any\appsettings.json_):
![suite-registry](../images/suite-registry.png)
> **Note:** Also, you can use this file to configure ABP Suite options.

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).

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

@ -0,0 +1,47 @@
# Web Application Development (with ABP Suite) Tutorial - Part 1: Creating the Solution
````json
//[doc-params]
{
"UI": ["MVC"],
"DB": ["EF"]
}
````
````json
//[doc-nav]
{
"Previous": {
"Name": "Overview",
"Path": "tutorials/book-store-with-abp-suite/index"
},
"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 Template:** Application (Layered)
* **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}}
* **Public Website:** No
* **Tiered:** No
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
Before creating the `Book` entity, first we can 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
}
```
After creating an _enum_ file in your project, you can define it as a property while creating the entity. ABP Suite asks for an enum path to read the enum file, and set the namespace, and enum name in the generated code accordingly. Then, you can create the `Book` entity with some properties.
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)
While defining the properties, you define a *Type* property with the type of *enum*. ABP Suite asks for an enum path and fill the all other inputs by reading the specified enum file. Therefore, you can specify the enum path for the `Type` property 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.
Here is the all details for the `Book` entity:
* `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*.
* `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...
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. Minimum length is **2** and maximum length is **128**.
* `BirthDate` is a **DateTime** property and **not nullable**.
* `ShortBio` is **required**, it's a **string** property, it's a **textarea**, 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.

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

@ -0,0 +1,170 @@
# 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.
> **Note**: You should delete all existing books in the database (if any), before the code generation. Because, a new foreign-key will be added to the _books_ table and if there is any record in the table, then a new migration can't apply to the database and you may need to update the database manually.
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.

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

Loading…
Cancel
Save