diff --git a/Directory.Packages.props b/Directory.Packages.props
index 361cbacd9c..74579541f2 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -46,7 +46,7 @@
-
+
@@ -145,6 +145,7 @@
+
@@ -155,8 +156,8 @@
-
-
+
+
diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
index de05cb68f6..abd7184278 100644
--- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
+++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
@@ -431,6 +431,9 @@
"WhoWeAre_Expert": "About Me",
"CreateSolutionFolder": "Create Solution Folder",
"CreateSolutionFolderOption": "Specifies if the project will be in a new folder in the output folder or directly the output folder.",
+ "CreateCrudPage": "Create CRUD Page",
+ "CreateCrudPageOption": "Generates a sample CRUD page with a Book entity to demonstrate basic operations (Create, Read, Update, Delete).",
+ "ConnectionString": "Connection string",
"BooksPageTitle": "ABP Books",
"BooksPageDescription": "Explore ABP books to deepen your understanding and mastery of ABP.",
"PackageDetailPage_NuGetPackageInstallationOptions": "There are three ways to install {0} NuGet package to your project",
@@ -907,6 +910,7 @@
"ProudToWorkWith": "Proud to Work With",
"JoinOurConsumers": "Join them and build amazing products fast.",
"AdditionalServicesExplanation": "Do you need additional or custom services? We and our partners can provide;",
+ "CustomLicense": "Custom License",
"CustomProjectDevelopment": "Custom Project Development",
"CustomProjectDevelopmentExplanation": "Dedicated developers for your custom projects.",
"PortingExistingProjects": "Porting Existing Projects",
@@ -1894,6 +1898,18 @@
"SelectAnOption": "Select an option",
"MostPopular": "Most Popular",
"AnnouncmentsPageTitle": "ABP Community Announcements | Stay Updated with the Latest News",
- "AnnouncmentsPageDescription": "Get the latest news, feature updates, release notes, and important announcements about the ABP framework and .NET ecosystem. Stay ahead with timely information directly from the ABP team."
+ "AnnouncmentsPageDescription": "Get the latest news, feature updates, release notes, and important announcements about the ABP framework and .NET ecosystem. Stay ahead with timely information directly from the ABP team.",
+ "CanIUseABPProductsOnMoreThanOneComputer": "Can I use ABP products on more than one computer?",
+ "ABPProductsOnMoreThanOneComputerExplanation": "Yes. Each developer can install the software on up to two machines. A third machine requires approval via email. When you stop using one of your computers, the system understands and automatically invalidates that computer from your paired computer list.",
+ "CanIShareTheLicensedABPCommercialProducts": "Can I share the licensed ABP commercial products publicly or make them open source?",
+ "ShareTheLicensedABPCommercialProductsExplanation": "No! Sharing or sublicensing a Commercial (PRO) ABP package is strictly prohibited.",
+ "AreSubscriptionRenewalsAutomatic": "Are subscription renewals automatic?",
+ "SubscriptionRenewalsAutomaticExplanation": "By default, no, the renewals are manual. On the other hand, when you purchase a new license and use the payment gateway 'Iyzico' with your credit card, you will see a checkbox called 'Automatic Renewal' in the purchase steps which allows ABP system automatically renew your license. When you check that checkbox, the auto-renewal process lets you renew your license without losing this discount, and your development will never be interrupted. ABP does not save your credit card information, but our payment gateway does secure savings. You can disable auto-renewal at any time by accessing your Organization Management page.",
+ "DoYouProvideSupportForThird-partyLibraries": "Do you provide support for third-party libraries?",
+ "ProvideSupportForThird-partyExplanation": "No. Support only covers ABP Framework, ABP commercial packages and products which have been created by Volosoft.",
+ "DoYouSupportCustomABPArchitectures": "Do you support custom ABP architectures?",
+ "SupportCustomABPArchitecturesExplanation": "No. Support is only provided for standard ABP solution structures. On the other hand, you can always get support for your custom needs with a paid consultancy from the ABP Team.",
+ "DoesABPCollectAnyPersonalOrTechnicalData": "Does ABP collect any personal or technical data?",
+ "ABPCollectAnyDataExplanation": "The software may collect information about you and your use of the software, and send that to Volosoft. Volosoft as the software and service provider may use this information to provide services and improve its products & services. You may opt-out of these scenarios, as described in the EULA under PRIVACY AND COLLECTION OF PERSONAL DATA topic ."
}
}
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/1752664190317-min.jpeg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/1752664190317-min.jpeg
index de317b4647..7cd0f2aa47 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/1752664190317-min.jpeg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/1752664190317-min.jpeg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15941-min.jpg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15941-min.jpg
index fe52494de8..8539d5be5c 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15941-min.jpg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15941-min.jpg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15944-min.jpg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15944-min.jpg
index 2692dd576d..2502d8904c 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15944-min.jpg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15944-min.jpg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15947-min.jpg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15947-min.jpg
index f3f6350c09..372f41e3a5 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15947-min.jpg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15947-min.jpg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15948-min.jpg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15948-min.jpg
index c875ad61e3..9d98fe4585 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15948-min.jpg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15948-min.jpg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15949-min.jpg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15949-min.jpg
index 69840520e0..dac9184cf3 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15949-min.jpg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15949-min.jpg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15959-min.jpg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15959-min.jpg
index fb6d3f520c..af4c2b300a 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15959-min.jpg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15959-min.jpg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15963-min.jpg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15963-min.jpg
index a9595acaa9..e2c3a297f7 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15963-min.jpg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15963-min.jpg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15995-min.jpg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15995-min.jpg
index 60546b5c9f..bc4220f83a 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15995-min.jpg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15995-min.jpg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15996-min.jpg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15996-min.jpg
index 147babb883..e5dd4c0c9d 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15996-min.jpg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15996-min.jpg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15998-min.jpg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15998-min.jpg
index 7c2d080da7..d2ae92ff0e 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15998-min.jpg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15998-min.jpg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15999-min.jpg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15999-min.jpg
index 0cf89bc0e4..22c32abd22 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15999-min.jpg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_15999-min.jpg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_16011-min.jpg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_16011-min.jpg
index c96d3a8d37..392a680bdf 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_16011-min.jpg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_16011-min.jpg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_16012-min.jpg b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_16012-min.jpg
index 62a16ac428..15a3fbf143 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_16012-min.jpg and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/IMG_16012-min.jpg differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/cover.png b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/cover.png
index 946fdc2ab0..595446cefa 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/cover.png and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/cover.png differ
diff --git a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/image-20250722203102576.png b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/image-20250722203102576.png
index 175fd45289..8b8f3a978b 100644
Binary files a/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/image-20250722203102576.png and b/docs/en/Blog-Posts/2025-07-22-My-Impressionf-at-WeAreDevelopers/image-20250722203102576.png differ
diff --git a/docs/en/Blog-Posts/2025-08-08 v9_3_Release_Stable/POST.md b/docs/en/Blog-Posts/2025-08-08 v9_3_Release_Stable/POST.md
new file mode 100644
index 0000000000..3acf9a7dd0
--- /dev/null
+++ b/docs/en/Blog-Posts/2025-08-08 v9_3_Release_Stable/POST.md
@@ -0,0 +1,79 @@
+# ABP.IO Platform 9.3 Final Has Been Released!
+
+We are glad to announce that [ABP](https://abp.io/) 9.3 stable version has been released today.
+
+## What's New With Version 9.3?
+
+All the new features were explained in detail in the [9.3 RC Announcement Post](https://abp.io/community/announcements/announcing-abp-9-3-release-candidate-4dqgiryf), so there is no need to review them again. You can check it out for more details.
+
+## Getting Started with 9.3
+
+### 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.
+
+> **Note**: ABP Studio **v1.2.1** has been released with support for **ABP 9.3**. If you already have ABP Studio installed, update it to v1.2.1 (or later, if available) to create new applications targeting 9.3. ABP Studio checks for updates automatically and will prompt you in-app modal to update to the latest version, or you can download the latest installer from the [Studio](https://abp.io/studio) page. See the [upgrading guide](https://abp.io/docs/latest/studio/installation#upgrading) for details. After updating, the New Solution wizard will create applications with ABP 9.3 by default. You can check the [ABP Studio and ABP Startup Template Version Mappings](https://abp.io/docs/latest/studio/version-mapping) documentation to see the corresponding ABP versions for other versions of Studio.
+
+### 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. 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 **Upgrade ABP Packages** action button to instantly upgrade your solution:
+
+
+
+### 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.
+
+## 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 v9.2: [ABP Version 9.3 Migration Guide](https://abp.io/docs/9.3/release-info/migration-guides/abp-9-3)
+
+## Community News
+
+### New ABP Community Articles
+
+As always, exciting articles have been contributed by the ABP community. I will highlight some of them here:
+
+* [Fahri Gedik](https://abp.io/community/members/fahrigedik) has published 2 new articles:
+ * [A Modern Approach to Angular Dependency Injection using inject function](https://abp.io/community/articles/a-modern-approach-to-angular-dependency-injection-using-8np4o1ap)
+ * [Angular Application Builder: Transitioning from Webpack to Esbuild](https://abp.io/community/articles/angular-application-builder-transitioning-from-webpack-to-3yzhzfl0)
+* [Benjamin Fadina](https://abp.io/community/members/benjaminsqlserver@gmail.com) has published several videos on various topics such as **Blazor Web Assembly Using ABP.IO**, **CQRS Implementation with MediatR in ABP** and more. You can see all his videos [here](https://abp.io/community/members/benjaminsqlserver@gmail.com).
+* [Mansur Besleney](https://abp.io/community/members/mansur.besleney) has published [How to Build Persistent Background Jobs with ABP Framework and Quartz](https://abp.io/community/articles/how-to-build-persistent-background-jobs-with-abp-framework-n9aloh93)
+* [Halil Ibrahim Kalkan](https://x.com/hibrahimkalkan) has published [Multitenancy with Separate Databases in .NET and ABP](https://abp.io/community/articles/multitenancy-with-separate-databases-in-dotnet-and-abp-51nvl4u9)
+* [Alex Maiereanu](https://abp.io/community/members/alex.maiereanu@3sstudio.com) has published [ABP-Hangfire-AzurePostgreSQL](https://abp.io/community/articles/abphangfireazurepostgresql-s1jnf3yg)
+* [Jack Fistelmann](https://abp.io/community/members/jfistelmann) has published [ABP and maildev](https://abp.io/community/articles/abp-and-maildev-gy13cr1p)
+* [Harsh Gupta](https://abp.io/community/members/harshgupta) has published [How to Add a Module in the ABP.io Application?](https://abp.io/community/articles/how-to-add-a-module-in-the-abp.io-application-sdeajkn6)
+* [Tarık Özdemir](https://abp.io/community/members/mtozdemir) has published [AI-First Architecture for .NET Projects: A Modern Blueprint Inspired by McKinsey](https://abp.io/community/articles/AI-First%20Architecture%20for%20.NET%20Projects%3A%20A%20Modern%20Blueprint-h2wgcoq3)
+* [Liming Ma](https://github.com/maliming) has published [Using Hangfire Dashboard in ABP API Website](https://abp.io/community/articles/using-hangfire-dashboard-in-abp-api-website--r32ox497)
+
+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/create) to the ABP Community.
+
+## About the Next Version
+
+The next feature version will be 10.0. You can follow the [release planning here](https://github.com/abpframework/abp/milestones). Please [submit an issue](https://github.com/abpframework/abp/issues/new) if you have any problems with this version.
diff --git a/docs/en/Blog-Posts/2025-08-08 v9_3_Release_Stable/cover-image.png b/docs/en/Blog-Posts/2025-08-08 v9_3_Release_Stable/cover-image.png
new file mode 100644
index 0000000000..291da0d04f
Binary files /dev/null and b/docs/en/Blog-Posts/2025-08-08 v9_3_Release_Stable/cover-image.png differ
diff --git a/docs/en/Blog-Posts/2025-08-08 v9_3_Release_Stable/upgrade-abp-packages.png b/docs/en/Blog-Posts/2025-08-08 v9_3_Release_Stable/upgrade-abp-packages.png
new file mode 100644
index 0000000000..ad5e9bd462
Binary files /dev/null and b/docs/en/Blog-Posts/2025-08-08 v9_3_Release_Stable/upgrade-abp-packages.png differ
diff --git a/docs/en/Community-Articles/2022-04-18-abp-community-talks-20223/post.md b/docs/en/Community-Articles/2022-04-18-abp-community-talks-20223/post.md
index fcd7043594..5d9c9e0d3e 100644
--- a/docs/en/Community-Articles/2022-04-18-abp-community-talks-20223/post.md
+++ b/docs/en/Community-Articles/2022-04-18-abp-community-talks-20223/post.md
@@ -6,7 +6,7 @@
* ABP Community Talks are scheduled to be held on a monthly basis.
* ABP Community Talks are and always will be completely free to attend. Everyone is welcome to join, ask questions and make suggestions before, during and after the event.
* ABP Community Talks are created and announced on [Kommunity](https://kommunity.com/volosoft/events).
- * ABP Community Talks are announced regularly on [ABP Framework Twitter Account](https://twitter.com/abpframework), [Volosoft LinkedIn account](https://www.linkedin.com/company/volosoft), [Volosoft Facebook Account](https://www.facebook.com/volosoftcompany), [ABP Community Discord Server](https://discord.gg/CrYrd5vcGh). We highly encourage everyone to follow us and make suggestions.
+ * ABP Community Talks are announced regularly on [ABP Framework Twitter Account](https://twitter.com/abpframework), [Volosoft LinkedIn account](https://www.linkedin.com/company/volosoft), [Volosoft Facebook Account](https://www.facebook.com/volosoftcompany), [ABP Community Discord Server](https://abp.io/join-discord). We highly encourage everyone to follow us and make suggestions.
* ABP Community Talks are available to watch after the event on YouTube. See [ABP Community Talks YouTube Playlist](https://www.youtube.com/playlist?list=PLsNclT2aHJcOsPustEkzG6DywiO8eh0lB).
# ABP Community Talks 2022.3
diff --git a/docs/en/Community-Articles/2022-04-19-official-abp-discord-server-is-here/post.md b/docs/en/Community-Articles/2022-04-19-official-abp-discord-server-is-here/post.md
index 5d099cc1c3..ca765a5860 100644
--- a/docs/en/Community-Articles/2022-04-19-official-abp-discord-server-is-here/post.md
+++ b/docs/en/Community-Articles/2022-04-19-official-abp-discord-server-is-here/post.md
@@ -1,9 +1,9 @@
- We are excited to announce Official ABP Discord Server is created! You can join the ABP Discord Community by clicking [here](https://discord.gg/wbcQAsUrs9).
+ We are excited to announce Official ABP Discord Server is created! You can join the ABP Discord Community by clicking [here](https://abp.io/join-discord).
In the first week of opening ABP Discord Server, member amount reached more than 500. We are grateful to and blessed by your interest. Thanks to all of you! This also made us sure that an ABP Discord Server was actually a need for the community members to interact with each other.
ABP Community is growing by the second, and we are grateful for all your contributions towards ABP Framework. We noticed that ABP Community’s communication were significant on ABP Framework’s GitHub, we wanted to take it to the next level and have an area where all of us can easily chat with each other.
-> [Join ABP Discord Server Now](https://discord.gg/wbcQAsUrs9)
+> [Join ABP Discord Server Now](https://abp.io/join-discord)
# What Can You Do on ABP Community Discord Server?
@@ -42,11 +42,11 @@
# How Can You Join To ABP Discord Server?
- You can join ABP Discord Server by simply clicking to [https://discord.gg/abp](https://discord.gg/wbcQAsUrs9).
+ You can join ABP Discord Server by simply clicking to [https://abp.io/join-discord](https://abp.io/join-discord).
We are excited to welcome you in ABP Discord Server!
-> [Click Here to Join ABP Discord Server Now](https://discord.gg/wbcQAsUrs9)
+> [Click Here to Join ABP Discord Server Now](https://abp.io/join-discord)
### What is Discord?
@@ -62,4 +62,4 @@
In Discord Servers, users communicate with each other in a way that is convenient for them. Discord allows people to make voice calls, video chats, or simply text messages. Communities are created by wether fans of a specific topic(games, open-source frameworks, NFT, etc.) or by the official authorities of that specific topic(game creator, framework core team, creator of a token, etc).
- In ABP Community Discord Server’s case, it is a server created by official authorities with core team being present in the server along with the community members. Even though it is created for the framework community members to communicate with each other easily, everyone who is interested in following the latest news about ABP Platform are welcome to [join ABP Discord Server](https://discord.gg/wbcQAsUrs9)!
\ No newline at end of file
+ In ABP Community Discord Server’s case, it is a server created by official authorities with core team being present in the server along with the community members. Even though it is created for the framework community members to communicate with each other easily, everyone who is interested in following the latest news about ABP Platform are welcome to [join ABP Discord Server](https://abp.io/join-discord)!
\ No newline at end of file
diff --git a/docs/en/Community-Articles/2022-05-10-abpio-platform-53-rc-has-been-published/post.md b/docs/en/Community-Articles/2022-05-10-abpio-platform-53-rc-has-been-published/post.md
index eb157010b8..cc0e57db93 100644
--- a/docs/en/Community-Articles/2022-05-10-abpio-platform-53-rc-has-been-published/post.md
+++ b/docs/en/Community-Articles/2022-05-10-abpio-platform-53-rc-has-been-published/post.md
@@ -254,4 +254,4 @@ We've created an official ABP Discord server so the ABP Community can interact w
Thanks to the ABP Community, **700+** people joined our Discord Server so far and it grows every day.
-You can join our Discord Server from [here](https://discord.gg/abp), if you haven't yet.
\ No newline at end of file
+You can join our Discord Server from [here](https://abp.io/join-discord), if you haven't yet.
\ No newline at end of file
diff --git a/docs/en/Community-Articles/2023-02-21-abp-year-review-2022-wrap-up/post.md b/docs/en/Community-Articles/2023-02-21-abp-year-review-2022-wrap-up/post.md
index 6abf2f3d12..a27aeb9f2c 100644
--- a/docs/en/Community-Articles/2023-02-21-abp-year-review-2022-wrap-up/post.md
+++ b/docs/en/Community-Articles/2023-02-21-abp-year-review-2022-wrap-up/post.md
@@ -1,100 +1,200 @@
-
ABP Framework is an open source infrastructure that enables developers to create modern web applications by following the best practices and conventions of software development. In 2022, ABP Framework continued to thrive, achieving significant milestones and making waves in the software development community. With more than 9K GitHub stars and over 10 millions of downloads on NuGet, ABP Framework has become a go-to framework for developers seeking a reliable and efficient way to build web applications.
-
-
As ABP Team, we owe our success to our vibrant community, and we are immensely grateful for the support and contributions of each and every member. With your help, we achieved a lot in 2022. We remained committed to our values of transparency, openness, and collaboration, engaging with our community members as much as possible to ensure that we are creating a framework that meets their needs.
-
-
One of the major highlights of 2022 was the release of .NET Core 7, which provided a powerful platform for ABP Framework to build upon. Additionally, ABP Commercial and our training programs continued to help developers and businesses to leverage the power of the ABP Framework, enabling them to build modern web applications more efficiently and effectively than ever before.
-
-
In this article, we'll take a closer look at the key highlights of 2022 for ABP Framework, from major updates to achivements and the community insights. We are excited to share our progress with you and provide insights into how ABP Framework is continuing to shape the future of software development. So, let's dive in!
- br>
-
-
-
-
NuGet Downloads
-
NuGet is a package manager designed specifically for the .NET ecosystem. It simplifies the process of creating and consuming packages, thanks to the NuGet client tools. By using these tools, developers can easily manage their project dependencies and improve their workflow.
Implementing Domain Driven Design: You can download it for free from here.
-
Building Microservice Solutions: You can download it for free from here.
-
-
-
-
Tutorial Videos
-
In 2022, we tried to be as much active as we could. To give you more insight and let you understand ABP Framework with short videos according to your interests, we published 48 tutorial videos. Though the videos were created by overall team members of ABP Framework, someone deserves a special mention here. Shout out to our ABP Core Team member Hamza Albreem for his hard work.
ABP Framework GitHub repository reached more than 9K stars. We appreciate your interest and support for ABP Framework GitHub repository. We are working hard to be worthy of your interest and reach out to more people to simplify and streamline their development processes.
-
-
Community Talks
-
ABP Community Talks is our monthly event that brings together members of the ABP Framework community to discuss and exchange ideas. Prior to each event, we collect suggestions from our contributors, monitor trending topics in the industry, and review updates and news related to the ABP Platform to curate the topics for discussion. Once the topics are finalized, we announce them through our social media and community channels to ensure everyone is aware and can join in on the conversation.
The ABP Community is a hub that offers resources such as articles, video tutorials, and updates on ABP's development progress and events for ABP Framework, .NET, and software development. Developers can also connect with others, help each other, and share their expertise in ABP Community.
-
You can check out each source from the list below.
-
ABP Community Events: You can reach them from here.
ABP Community Videos: You can reach them from here.
-
ABP Community Stackoverflow: You can reach them from here.
-
-
In 2022, the community's contribution reached a point where more than 100 resources. Thank you for all your effort! Please keep it going! It is becoming a more and more rich resource thanks to your variety of contributions and help.
-
-
-
ABP Community Discord Server
-
To take community interaction to the next level, we created the official ABP Discord server, providing a platform for the ABP Community to connect and communicate instantly through chatting.
-
We were so excited announcing the official ABP Discord Server. In the first week of announcing it, the server quickly attracted over 500 members. We're grateful for your interest and support, which confirms the need for a dedicated platform for community interaction.
In 2022, ABP Core Team worked hard to achieve milestones and give the best value with ABP Framework so users can benefit from its features. Additional to our team's work, ABP Framework is perfected in 2022 with ABP Community members' contributions, 3157 commits pushed from 48 different contributors.
-
We appreciate your hard work and effort you put into making ABP Framework better and improved.
-
-
-
Events/Summits
-
We try to contribute to the developers community as much as we can since day 1. This year was no different. We tried to give value through sponsorships for developer communities. Especially with us leaving the pandemic behind every day, we try to keep up with the in-person events as well as online events. We plan to do more in next year. So, stay tuned!
ABP Framework released 4 versions from 5.1 to 7.1 in 2022. You can check the release logs from ABP Framework Release Logs.
-
The most important milestone in these releases is that we upgraded ABP Framework to .NET 7.0 in ABP v7.0.
-
Additionally, we switched to OpenIddict for the startup templates in ABP v6.0.
-
-
-
ABP Commercial
-
It has been a successful year for ABP Commercial as well as ABP Framework. We have already reached to more than 100 countries over the years of ABP Commercial's release. This year, we continued to be streamline businesses' development processes with ABP Commercial.
-
-
We have served to different sizes of businesses from more than 50 countries and more than 40 industries .
-
We performed 286 hours of training to simplify users' learning curve of ABP Framework.
-
1771 support tickets resolved in the premium support forum in which ABP Commercial users can ask their questions directly to ABP Core Team members via ABP Commercial Support Center in addition to community support we provide for ABP Framework users/developers.
-
We received 39 new testimonials, all from satisfied customers which led us to the other headline, Gartner Badges.
-
-
-
-
LeptonX Theme
-
The Lepton Theme is a module that offers a theme for abp.io-based applications, featuring an Admin Dashboard designed by the ABP Platform. We released a version we called LeptonX Theme which is an upgraded version of Lepton Theme. You can view a live preview of the LeptonX Theme. While the LeptonX theme is currently exclusive to ABP Commercial users, ABP Framework users can still access the Lite version. You can see the documentation for ABP LeptonX Theme light from here.
-
-
-
Gartner Badges
-
Gartner badges are given as an award to the listed softwares within their software review/suggestion platforms. To be able to get these awards, certain criterias have to be met such as ease of use, likelihood of recommend, functionality, etc. and they are calculated completely according to the users' real reviews.
-
In 2022, ABP Commercial reached to such success thanks to its users' support on Gartner, it has been recognized with 2 badges in Application Development category.
-
ABP Commercial was selected in the following platforms of Gartner:
-
Thank you all for all these recognition you deemed us worthy of.
+
ABP Framework is an open source infrastructure that enables developers to create modern web applications by following the best practices and conventions of software development. In 2022, ABP Framework continued to thrive, achieving significant milestones and making waves in the software development community. With more than 9K GitHub stars and over 10 millions of downloads on NuGet, ABP Framework has become a go-to framework for developers seeking a reliable and efficient way to build web applications.
+
+
+
+
As ABP Team, we owe our success to our vibrant community, and we are immensely grateful for the support and contributions of each and every member. With your help, we achieved a lot in 2022. We remained committed to our values of transparency, openness, and collaboration, engaging with our community members as much as possible to ensure that we are creating a framework that meets their needs.
+
+
+
+
One of the major highlights of 2022 was the release of .NET Core 7, which provided a powerful platform for ABP Framework to build upon. Additionally, ABP Commercial and our training programs continued to help developers and businesses to leverage the power of the ABP Framework, enabling them to build modern web applications more efficiently and effectively than ever before.
+
+
+
+
In this article, we'll take a closer look at the key highlights of 2022 for ABP Framework, from major updates to achivements and the community insights. We are excited to share our progress with you and provide insights into how ABP Framework is continuing to shape the future of software development. So, let's dive in!
+
+ br>
+
+
+
+
+
+
+
+
NuGet Downloads
+
+
NuGet is a package manager designed specifically for the .NET ecosystem. It simplifies the process of creating and consuming packages, thanks to the NuGet client tools. By using these tools, developers can easily manage their project dependencies and improve their workflow.
Implementing Domain Driven Design: You can download it for free from here.
+
+
Building Microservice Solutions: You can download it for free from here.
+
+
+
+
+
+
+
+
Tutorial Videos
+
+
In 2022, we tried to be as much active as we could. To give you more insight and let you understand ABP Framework with short videos according to your interests, we published 48 tutorial videos. Though the videos were created by overall team members of ABP Framework, someone deserves a special mention here. Shout out to our ABP Core Team member Hamza Albreem for his hard work.
ABP Framework GitHub repository reached more than 9K stars. We appreciate your interest and support for ABP Framework GitHub repository. We are working hard to be worthy of your interest and reach out to more people to simplify and streamline their development processes.
+
+
+
+
Community Talks
+
+
ABP Community Talks is our monthly event that brings together members of the ABP Framework community to discuss and exchange ideas. Prior to each event, we collect suggestions from our contributors, monitor trending topics in the industry, and review updates and news related to the ABP Platform to curate the topics for discussion. Once the topics are finalized, we announce them through our social media and community channels to ensure everyone is aware and can join in on the conversation.
The ABP Community is a hub that offers resources such as articles, video tutorials, and updates on ABP's development progress and events for ABP Framework, .NET, and software development. Developers can also connect with others, help each other, and share their expertise in ABP Community.
+
+
You can check out each source from the list below.
+
+
ABP Community Events: You can reach them from here.
ABP Community Videos: You can reach them from here.
+
+
ABP Community Stackoverflow: You can reach them from here.
+
+
+
+
In 2022, the community's contribution reached a point where more than 100 resources. Thank you for all your effort! Please keep it going! It is becoming a more and more rich resource thanks to your variety of contributions and help.
+
+
+
+
+
+
ABP Community Discord Server
+
+
To take community interaction to the next level, we created the official ABP Discord server, providing a platform for the ABP Community to connect and communicate instantly through chatting.
+
+
We were so excited announcing the official ABP Discord Server. In the first week of announcing it, the server quickly attracted over 500 members. We're grateful for your interest and support, which confirms the need for a dedicated platform for community interaction.
In 2022, ABP Core Team worked hard to achieve milestones and give the best value with ABP Framework so users can benefit from its features. Additional to our team's work, ABP Framework is perfected in 2022 with ABP Community members' contributions, 3157 commits pushed from 48 different contributors.
+
+
We appreciate your hard work and effort you put into making ABP Framework better and improved.
+
+
+
+
+
+
Events/Summits
+
+
We try to contribute to the developers community as much as we can since day 1. This year was no different. We tried to give value through sponsorships for developer communities. Especially with us leaving the pandemic behind every day, we try to keep up with the in-person events as well as online events. We plan to do more in next year. So, stay tuned!
ABP Framework released 4 versions from 5.1 to 7.1 in 2022. You can check the release logs from ABP Framework Release Logs.
+
+
The most important milestone in these releases is that we upgraded ABP Framework to .NET 7.0 in ABP v7.0.
+
+
Additionally, we switched to OpenIddict for the startup templates in ABP v6.0.
+
+
+
+
+
+
ABP Commercial
+
+
It has been a successful year for ABP Commercial as well as ABP Framework. We have already reached to more than 100 countries over the years of ABP Commercial's release. This year, we continued to be streamline businesses' development processes with ABP Commercial.
+
+
+
+
We have served to different sizes of businesses from more than 50 countries and more than 40 industries .
+
+
We performed 286 hours of training to simplify users' learning curve of ABP Framework.
+
+
1771 support tickets resolved in the premium support forum in which ABP Commercial users can ask their questions directly to ABP Core Team members via ABP Commercial Support Center in addition to community support we provide for ABP Framework users/developers.
+
+
We received 39 new testimonials, all from satisfied customers which led us to the other headline, Gartner Badges.
+
+
+
+
+
+
+
+
LeptonX Theme
+
+
The Lepton Theme is a module that offers a theme for abp.io-based applications, featuring an Admin Dashboard designed by the ABP Platform. We released a version we called LeptonX Theme which is an upgraded version of Lepton Theme. You can view a live preview of the LeptonX Theme. While the LeptonX theme is currently exclusive to ABP Commercial users, ABP Framework users can still access the Lite version. You can see the documentation for ABP LeptonX Theme light from here.
+
+
+
+
+
+
Gartner Badges
+
+
Gartner badges are given as an award to the listed softwares within their software review/suggestion platforms. To be able to get these awards, certain criterias have to be met such as ease of use, likelihood of recommend, functionality, etc. and they are calculated completely according to the users' real reviews.
+
+
In 2022, ABP Commercial reached to such success thanks to its users' support on Gartner, it has been recognized with 2 badges in Application Development category.
+
+
ABP Commercial was selected in the following platforms of Gartner:
+
+
Thank you all for all these recognition you deemed us worthy of.
+
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/POST.md b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/POST.md
index 5567b42aad..e63db935a5 100644
--- a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/POST.md
+++ b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/POST.md
@@ -22,7 +22,7 @@ In the shared database model, all the application data stored in a single physic

-This is the default behavior when you [create a new ABP application](https://abp.io/docs/latest/get-started), because it is simple to begin with and proper for must applications.
+This is the default behavior when you [create a new ABP application](https://abp.io/docs/latest/get-started), because it is simple to begin with and proper for most applications.
In this model, a single database table may contain data of multiple tenants. Each row in these tables have a `TenantId` field which is used to distinguish the tenant data and isolate a tenant's data from other tenant users. To make your entities multi-tenant aware, all you have to do is to implement the `IMultiTenant` interface provided by the ABP Framework.
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-saas-tenants-page.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-saas-tenants-page.png
index 5b67b21bd1..9f3a0ce5ca 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-saas-tenants-page.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-saas-tenants-page.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration-select-dbcontext.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration-select-dbcontext.png
index 38c18c1221..17b89bee80 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration-select-dbcontext.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration-select-dbcontext.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration-set-name.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration-set-name.png
index f3f48c8e39..9ff5ea75f4 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration-set-name.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration-set-name.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration.png
index c509020c10..fe59e93230 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-add-migration.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-browse.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-browse.png
index 7ea0ae2116..3134203343 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-browse.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-browse.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-context-selection.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-context-selection.png
index af47462005..dc1a993088 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-context-selection.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-context-selection.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-open-with-terminal.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-open-with-terminal.png
index 03cd29c3e1..17dd1fa4dd 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-open-with-terminal.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-open-with-terminal.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-solution-runner.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-solution-runner.png
index b965356dab..a246d01c81 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-solution-runner.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/abp-studio-solution-runner.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/acme-tenant-screen.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/acme-tenant-screen.png
index 1274c7e415..65f7aa5b48 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/acme-tenant-screen.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/acme-tenant-screen.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/added-product-entity-migration-main-context.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/added-product-entity-migration-main-context.png
index b6da1d9e58..a727bcea86 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/added-product-entity-migration-main-context.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/added-product-entity-migration-main-context.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/added-product-entity-migration-tenant-context.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/added-product-entity-migration-tenant-context.png
index b214b13f8c..f77c5e1e75 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/added-product-entity-migration-tenant-context.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/added-product-entity-migration-tenant-context.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/builder-check-tenant-side.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/builder-check-tenant-side.png
index bfc89e9dda..8b913d4292 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/builder-check-tenant-side.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/builder-check-tenant-side.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/dbcontext-factories.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/dbcontext-factories.png
index 17b7272435..b7f72d9a32 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/dbcontext-factories.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/dbcontext-factories.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/dbmigrator-logs.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/dbmigrator-logs.png
index 2fdfbcb45c..648d9ccaa8 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/dbmigrator-logs.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/dbmigrator-logs.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/hybrid-database-multi-tenancy.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/hybrid-database-multi-tenancy.png
index e5e5364302..45930e7fb9 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/hybrid-database-multi-tenancy.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/hybrid-database-multi-tenancy.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/multi-tenancy-dbcontext-structure.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/multi-tenancy-dbcontext-structure.png
index 0bd76b7d59..5bb7ad8410 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/multi-tenancy-dbcontext-structure.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/multi-tenancy-dbcontext-structure.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-1.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-1.png
index cc2e7b1975..76a2a33087 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-1.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-1.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-2.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-2.png
index 0c002b8718..614689552e 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-2.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-2.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-conn-string-1.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-conn-string-1.png
index bb1327fc34..5c6aee61d9 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-conn-string-1.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-conn-string-1.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-conn-string-2.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-conn-string-2.png
index 1f68b3d76b..9404e38a26 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-conn-string-2.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/new-tenant-dialog-conn-string-2.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/product-database-table.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/product-database-table.png
index cb5a1967f9..58ef8463f2 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/product-database-table.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/product-database-table.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-database.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-database.png
index 26a3bb3064..1ec6c36ad7 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-database.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-database.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-tenant-database-multi-tenancy.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-tenant-database-multi-tenancy.png
index 4df29f02ae..69c2bb4940 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-tenant-database-multi-tenancy.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-tenant-database-multi-tenancy.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-tenant-schema-option.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-tenant-schema-option.png
index bd7d86ce45..40c9c42770 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-tenant-schema-option.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/separate-tenant-schema-option.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/single-shared-database.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/single-shared-database.png
index af51e1d423..4363dc792e 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/single-shared-database.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/single-shared-database.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/switch-host-side.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/switch-host-side.png
index 46c185901c..e4e5f8943d 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/switch-host-side.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/switch-host-side.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/switch-tenant-dialog.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/switch-tenant-dialog.png
index 36dd1c9a19..2828906d1e 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/switch-tenant-dialog.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/switch-tenant-dialog.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/tenant-acme-name.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/tenant-acme-name.png
index 94f159ed53..a08537ee4e 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/tenant-acme-name.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/tenant-acme-name.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/tenant-database.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/tenant-database.png
index 492c6a00cb..32f7292e3c 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/tenant-database.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/tenant-database.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/user-login.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/user-login.png
index 425ed5cc5f..39cdac5aaf 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/user-login.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/user-login.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/user-logout.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/user-logout.png
index 4b9d8e9e05..ae7885fa0e 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/user-logout.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/user-logout.png differ
diff --git a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/users-table-new-tenant.png b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/users-table-new-tenant.png
index 0fc5eecda9..0433da73b5 100644
Binary files a/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/users-table-new-tenant.png and b/docs/en/Community-Articles/2025-07-26-Separate-Tenant-Schema/users-table-new-tenant.png differ
diff --git a/docs/en/Community-Articles/2025-07-31-How-to-build-persistent-background-jobs-with-abp-framework-and-quartz/Post.md b/docs/en/Community-Articles/2025-07-31-How-to-build-persistent-background-jobs-with-abp-framework-and-quartz/Post.md
new file mode 100644
index 0000000000..eb69c93908
--- /dev/null
+++ b/docs/en/Community-Articles/2025-07-31-How-to-build-persistent-background-jobs-with-abp-framework-and-quartz/Post.md
@@ -0,0 +1,548 @@
+
+# How to Build Persistent Background Jobs with ABP Framework and Quartz
+
+## Introduction
+
+In modern SaaS applications, automated background processing is essential for delivering reliable user experiences. Whether you're sending subscription reminders, processing payments, or generating reports, background jobs ensure critical tasks happen on schedule without blocking your main application flow.
+
+### What is `Quartz.NET`?
+
+`Quartz.NET` is a powerful, open-source job scheduling library for .NET applications that provides cron-based scheduling for complex time patterns, job persistence across application restarts, clustering support for high-availability scenarios, flexible trigger types, and the ability to pass parameters to jobs through job data maps. It's the de facto standard for enterprise-grade job scheduling in the .NET ecosystem.
+
+### Quartz Storage Options: In-Memory vs Persistent
+
+When configuring **Quartz**, you have two primary storage options, each with significant implications for how your application behaves:
+
+### 🧠 In-Memory Storage (`RAMJobStore`)
+- Keeps all job information in application memory.
+- **Very fast** – no database overhead.
+- **Volatile** – all jobs, triggers, and schedules are lost when the application stops or restarts.
+- Best suited for:
+ - Development environments.
+ - Scenarios where job loss is acceptable.
+
+### 🗃️ Persistent Storage (`JobStoreTX` or similar)
+- Stores all job information in a database.
+- **Reliable** – schedules persist across:
+ - Application restarts
+ - Server crashes
+ - Deployments
+- **Supports horizontal scaling** – multiple application instances can share the same job queue.
+- **Slight performance overhead** due to database I/O.
+- Best choice for:
+ - Production systems.
+ - Any scenario where **business continuity and reliability** are critical.
+
+### How ABP Simplifies Quartz Integration
+
+ABP handles Quartz configuration, dependency injection, and lifecycle management automatically. Developers define jobs using `QuartzBackgroundWorkerBase` and access services via `ICachedServiceProvider`, following ABP's standard conventions and leveraging optimal service caching for background job scenarios.
+
+### Benefits of the Integration
+
+- Full support for ABP’s cross-cutting concerns (e.g., multi-tenancy, localization)
+- Robust scheduling powered by Quartz
+- Built-in logging, error handling, and performance monitoring
+- Scales easily without modifying business logic
+
+### Real-World Use Case: Subscription Reminders
+
+In this tutorial, we'll build a subscription reminder system that monitors client subscriptions, identifies those nearing expiration, sends professional email reminders seven days before expiration, tracks reminder history to prevent duplicates, and runs automatically every day at 9:00 AM using Quartz scheduling with PostgreSQL persistence. This system demonstrates how ABP and Quartz work together to solve real business problems with clean, maintainable code that follows enterprise-grade patterns.
+
+## Installing and Configuring Quartz
+
+Getting Quartz up and running in an ABP application is straightforward thanks to ABP's dedicated integration package. We'll replace the default background job system with Quartz for persistent job storage and robust scheduling capabilities.
+
+### Adding the Quartz Package
+
+The easiest way to add Quartz support to your ABP application is using the ABP CLI. Open a terminal in your project directory and run:
+
+```bash
+abp add-package Volo.Abp.BackgroundWorkers.Quartz
+```
+
+This command automatically adds the necessary NuGet package reference and updates your module dependencies. The ABP CLI handles all the heavy lifting, ensuring you get the correct version that matches your ABP Framework version.
+
+### Configuring Quartz for Persistent Storage
+
+Once the package is installed, you need to configure Quartz to use your database (in my case it is PostgreSQL) for job persistence. This configuration goes in your main module's `PreConfigureServices` method:
+
+```csharp
+[DependsOn(
+ // ... other dependencies
+ typeof(AbpBackgroundJobsQuartzModule),
+ typeof(AbpBackgroundWorkersQuartzModule)
+)]
+public class MySaaSApplicationModule : AbpModule
+{
+ public override void PreConfigureServices(ServiceConfigurationContext context)
+ {
+ var hostingEnvironment = context.Services.GetHostingEnvironment();
+ var configuration = context.Services.GetConfiguration();
+
+ ConfigureAuthentication(context, configuration);
+ ConfigureUrls(configuration);
+ ConfigureImpersonation(context, configuration);
+ ConfigureQuartz(); // Add this line
+ }
+
+ private void ConfigureQuartz()
+ {
+ PreConfigure(options =>
+ {
+ options.Properties = new NameValueCollection
+ {
+ ["quartz.scheduler.instanceName"] = "QuartzScheduler",
+ ["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz",
+ ["quartz.jobStore.tablePrefix"] = "qrtz_",
+ ["quartz.jobStore.dataSource"] = "myDS",
+ ["quartz.dataSource.myDS.connectionString"] = _configuration.GetConnectionString("Default"),
+ ["quartz.dataSource.myDS.provider"] = "Npgsql",
+ ["quartz.serializer.type"] = "json"
+ };
+ });
+ }
+}
+```
+
+This configuration tells Quartz to store all job information in your PostgreSQL database using tables prefixed with "qrtz_". The key points are:
+
+- **Job Store Type**: Uses ADO.NET with transaction support for reliable job persistence
+- **Connection String**: Shares your application's existing database connection
+- **Table Prefix**: Keeps Quartz tables separate with the "qrtz_" prefix
+- **JSON Serialization**: Makes job data readable and debuggable
+- **PostgreSQL Provider**: Uses Npgsql for optimal PostgreSQL integration
+
+When your application starts, ABP automatically initializes the Quartz scheduler with these settings. Any background workers you create will be registered and scheduled automatically, with their state persisted to the database for reliability across application restarts.
+
+For detailed installation options and advanced configuration scenarios, check the official [ABP documentation.](https://abp.io/docs/latest/framework/infrastructure/background-workers/quartz)
+
+
+## Database Setup for Quartz
+
+With Quartz configured for persistent storage, we need to create the necessary database tables where Quartz will store job definitions, triggers, and execution history. Rather than running SQL scripts directly against the database, we'll use Entity Framework migrations to maintain consistency with ABP's database management approach.
+
+### Creating an Empty Migration for Quartz Tables
+
+Instead of executing raw SQL scripts against the database, we created an empty Entity Framework migration and populated it with the required Quartz table definitions. This approach keeps all database changes within the migration system, ensuring they're version-controlled, repeatable, and consistent across different environments.
+
+To create the empty migration, we used the standard Entity Framework CLI command:
+
+```bash
+dotnet ef migrations add AddQuartzTables
+```
+
+This generates a new migration file with empty `Up` and `Down` methods that we can populate with the Quartz table creation scripts.
+
+### Adding Quartz SQL Schema to Migration
+
+Once the empty migration was created, we populated it with the PostgreSQL-specific SQL needed to create all Quartz tables. The SQL scripts were obtained from the official Quartz repository, which provides database schema scripts for various database providers:
+
+```csharp
+public partial class AddQuartzTables : Migration
+{
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.Sql(@"
+ CREATE TABLE qrtz_job_details (
+ sched_name VARCHAR(120) NOT NULL,
+ job_name VARCHAR(200) NOT NULL,
+ job_group VARCHAR(200) NOT NULL,
+ description VARCHAR(250) NULL,
+ job_class_name VARCHAR(250) NOT NULL,
+ is_durable BOOLEAN NOT NULL,
+ is_nonconcurrent BOOLEAN NOT NULL,
+ is_update_data BOOLEAN NOT NULL,
+ requests_recovery BOOLEAN NOT NULL,
+ job_data BYTEA NULL,
+ PRIMARY KEY (sched_name, job_name, job_group)
+ );
+
+ CREATE TABLE qrtz_triggers (
+ sched_name VARCHAR(120) NOT NULL,
+ trigger_name VARCHAR(200) NOT NULL,
+ trigger_group VARCHAR(200) NOT NULL,
+ job_name VARCHAR(200) NOT NULL,
+ job_group VARCHAR(200) NOT NULL,
+ -- ... additional columns and constraints
+ PRIMARY KEY (sched_name, trigger_name, trigger_group),
+ FOREIGN KEY (sched_name, job_name, job_group) REFERENCES qrtz_job_details(sched_name, job_name, job_group)
+ );
+
+ -- Additional tables: qrtz_simple_triggers, qrtz_cron_triggers,
+ -- qrtz_simprop_triggers, qrtz_blob_triggers, qrtz_calendars,
+ -- qrtz_paused_trigger_grps, qrtz_fired_triggers, qrtz_scheduler_state, qrtz_locks
+ ");
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.Sql(@"
+ DROP TABLE IF EXISTS qrtz_locks;
+ DROP TABLE IF EXISTS qrtz_scheduler_state;
+ -- ... drop all other Quartz tables in reverse order
+ DROP TABLE IF EXISTS qrtz_triggers;
+ DROP TABLE IF EXISTS qrtz_job_details;
+ ");
+ }
+}
+```
+
+The complete SQL scripts for all supported database providers, including PostgreSQL, MySQL, SQL Server, and others, can be found in the official `Quartz.NET` repository. You should use the script that matches your specific database provider and version requirements.
+
+### Why Use Migrations Instead of Direct SQL Scripts?
+
+This migration-based approach offers several important advantages over running SQL scripts directly:
+
+**Version Control Integration**: The migration becomes part of your codebase, tracked in source control alongside your application changes. This means every developer and deployment environment gets the exact same database schema.
+
+**Rollback Capability**: The `Down` method provides a clean way to remove Quartz tables if needed, something that's much harder to manage with standalone SQL scripts.
+
+**Environment Consistency**: Whether you're setting up a development machine, staging server, or production deployment, running DBMigrator or `dotnet ef database update` command ensures the same schema is created everywhere.
+
+**Integration with ABP's Database Management**: This approach aligns perfectly with how ABP manages all other database changes, keeping your database evolution strategy consistent.
+
+The Quartz tables created by this migration handle all aspects of job persistence - from storing job definitions and triggers to tracking execution history and managing scheduler state. With these tables in place, your Quartz scheduler can reliably persist jobs across application restarts and coordinate work across multiple application instances if needed.
+
+After creating this migration, running DBMigrator `dotnet ef database update` will create all the necessary Quartz infrastructure in your PostgreSQL database, ready to store and manage your background jobs.
+
+For complete SQL scripts for your specific database provider, visit the official [Quartz documentation.](https://www.quartz-scheduler.net/documentation/quartz-3.x/quick-start.html#creating-and-initializing-database)
+## Building the Business Logic
+
+Before implementing our Quartz background job, we needed to create the essential business entities and services that our subscription reminder system would work with. Since this article focuses on Quartz integration rather than general ABP development patterns, we'll keep this section brief and move quickly to the background job implementation.
+
+### Core Entities and Services
+
+For our subscription reminder system, we created the following core components:
+
+**Entities:**
+- **`Client`**: Represents customers with subscription information (Name, Email, SubscriptionEnd, IsActive)
+- **`ReminderLog`**: Tracks when reminder emails have been sent to prevent duplicates
+
+**Application Services:**
+- **`ClientAppService`**: Handles CRUD operations and provides methods to find clients with expiring subscriptions
+- **`ReminderLogAppService`**: Manages reminder history and prevents duplicate notifications
+- **`EmailService`**: Sends professional HTML reminder emails via SMTP
+
+**Data Transfer Objects (DTOs):**
+- Complete set of DTOs for both entities following ABP conventions
+- Input/output DTOs for all service operations
+
+### Business Logic Overview
+
+The system follows standard ABP patterns with entities inheriting from `FullAuditedAggregateRoot`, services implementing `ICrudAppService` interfaces, and proper AutoMapper configurations for entity-DTO mapping. We also included a data seeder to create sample clients for testing purposes.
+
+The key business methods our background job will use are:
+- `GetExpiringClientsAsync()` - Finds clients whose subscriptions expire in the next 7 days
+- `CreateAsync()` - Logs when a reminder has been sent
+- `SendSubscriptionExpiryReminderAsync()` - Sends professional email reminders
+
+### Focus on Background Operations
+
+Rather than diving deep into ABP entity creation, repository patterns, or service layer implementation details, we'll move directly to the heart of this article: implementing robust background jobs with Quartz. The entities and services we created simply provide the business context for our background job to operate within.
+
+The real value of this tutorial lies in showing how ABP's `QuartzBackgroundWorkerBase` integrates seamlessly with your business logic to create reliable, persistent background operations that survive application restarts and scale across multiple instances.
+
+Let's now implement the background job that ties everything together and demonstrates the power of ABP + Quartz integration.
+
+
+## Implementing the Background Job (The ABP Way)
+
+This is where the magic happens. ABP's integration with Quartz provides a clean, powerful way to create background jobs that follow framework conventions while leveraging Quartz's robust scheduling capabilities. Let's dive into how we implemented our subscription reminder job and explore the advanced features ABP provides.
+
+### Creating a QuartzBackgroundWorkerBase Job
+
+Instead of implementing Quartz's raw `IJob` interface, ABP provides `QuartzBackgroundWorkerBase`, which integrates seamlessly with ABP's dependency injection, logging, and lifecycle management systems:
+
+```csharp
+public class SubscriptionExpiryNotifierJob : QuartzBackgroundWorkerBase
+{
+ public SubscriptionExpiryNotifierJob()
+ {
+ // Configure the job to run daily at 9:00 AM
+ JobDetail = JobBuilder.Create()
+ .WithIdentity(nameof(SubscriptionExpiryNotifierJob))
+ .Build();
+
+ Trigger = TriggerBuilder.Create()
+ .WithIdentity(nameof(SubscriptionExpiryNotifierJob))
+ .WithCronSchedule("0 0 9 * * ?") // Every day at 9:00 AM
+ .Build();
+
+ ScheduleJob = async scheduler =>
+ {
+ if (!await scheduler.CheckExists(JobDetail.Key))
+ {
+ await scheduler.ScheduleJob(JobDetail, Trigger);
+ }
+ };
+ }
+
+ public override async Task Execute(IJobExecutionContext context)
+ {
+ // Use ICachedServiceProvider for better performance and proper scoping
+ var serviceProvider = ServiceProvider.GetRequiredService();
+
+ // These services will be cached and reused throughout the job execution
+ var clientAppService = serviceProvider.GetRequiredService();
+ var reminderLogAppService = serviceProvider.GetRequiredService();
+ var emailService = serviceProvider.GetRequiredService();
+
+ Logger.LogInformation("🔄 Starting subscription expiry notification job...");
+
+ // 1. Get clients expiring in 7 days
+ var expiringClients = await clientAppService.GetExpiringClientsAsync(7);
+
+ Logger.LogInformation("📋 Found {Count} clients with expiring subscriptions", expiringClients.Count);
+
+ // 2. Process each client
+ foreach (var client in expiringClients)
+ {
+ await ProcessClientAsync(client, emailService, reminderLogAppService);
+ }
+
+ Logger.LogInformation("✅ Job completed successfully");
+ }
+}
+```
+
+### Key Implementation Features
+
+**Constructor-Based Configuration**: Unlike traditional Quartz jobs that require external scheduling code, ABP's approach lets you define both the job and its schedule directly in the constructor. This keeps related configuration together and makes the job self-contained.
+
+**ABP Service Integration**: The `ICachedServiceProvider` gives you access to any service in ABP's dependency injection container, enabling you to use application services, repositories, domain services, or any other ABP component with optimized caching and proper scoping.
+
+**Built-in Logging**: The `Logger` property provides access to ABP's logging infrastructure, automatically including context like correlation IDs and tenant information in multi-tenant applications.
+
+**Custom Scheduling Logic**: The `ScheduleJob` property allows you to customize how the job gets registered with Quartz. In our example, we check if the job already exists before scheduling it, preventing duplicate registrations during application restarts.
+
+### Understanding Quartz Trigger Types
+
+Quartz provides several trigger types to handle different scheduling requirements. Choosing the right trigger type is crucial for your job's behavior and performance.
+
+#### CronTrigger - Complex Time-Based Scheduling
+
+CronTrigger uses cron expressions for sophisticated scheduling patterns. This is what we used for our daily subscription reminders:
+
+```csharp
+// Daily at 9:00 AM
+Trigger = TriggerBuilder.Create()
+ .WithIdentity("DailyReminder")
+ .WithCronSchedule("0 0 9 * * ?")
+ .Build();
+
+// Every weekday at 2:30 PM
+Trigger = TriggerBuilder.Create()
+ .WithIdentity("WeekdayReport")
+ .WithCronSchedule("0 30 14 ? * MON-FRI")
+ .Build();
+
+// First day of every month at midnight
+Trigger = TriggerBuilder.Create()
+ .WithIdentity("MonthlyCleanup")
+ .WithCronSchedule("0 0 0 1 * ?")
+ .Build();
+```
+
+**Cron Expression Format**: `Seconds Minutes Hours Day-of-Month Month Day-of-Week Year(optional)`
+- `0 0 9 * * ?` = 9:00 AM every day
+- `0 */15 * * * ?` = Every 15 minutes
+- `0 0 12 ? * SUN` = Every Sunday at noon
+
+#### SimpleTrigger - Interval-Based Scheduling
+
+SimpleTrigger is perfect for jobs that need to run at regular intervals or a specific number of times:
+
+```csharp
+// Run every 30 seconds indefinitely
+Trigger = TriggerBuilder.Create()
+ .WithIdentity("HealthCheck")
+ .StartNow()
+ .WithSimpleSchedule(x => x
+ .WithIntervalInSeconds(30)
+ .RepeatForever())
+ .Build();
+
+// Run every 5 minutes, but only 10 times
+Trigger = TriggerBuilder.Create()
+ .WithIdentity("LimitedRetry")
+ .StartNow()
+ .WithSimpleSchedule(x => x
+ .WithIntervalInMinutes(5)
+ .WithRepeatCount(9)) // 0-based, so 9 = 10 executions
+ .Build();
+
+// One-time execution after 1 hour delay
+Trigger = TriggerBuilder.Create()
+ .WithIdentity("DelayedCleanup")
+ .StartAt(DateTimeOffset.UtcNow.AddHours(1))
+ .Build();
+```
+
+#### CalendarIntervalTrigger - Calendar-Aware Intervals
+
+CalendarIntervalTrigger handles intervals that need to respect calendar boundaries:
+
+```csharp
+// Every month on the same day (handles varying month lengths)
+Trigger = TriggerBuilder.Create()
+ .WithIdentity("MonthlyBilling")
+ .WithCalendarIntervalSchedule(x => x
+ .WithIntervalInMonths(1))
+ .Build();
+
+// Every week, starting Monday
+Trigger = TriggerBuilder.Create()
+ .WithIdentity("WeeklyReport")
+ .WithCalendarIntervalSchedule(x => x
+ .WithIntervalInWeeks(1))
+ .Build();
+```
+
+#### DailyTimeIntervalTrigger - Time Windows
+
+DailyTimeIntervalTrigger runs jobs within specific time windows on certain days:
+
+```csharp
+// Every 2 hours between 8 AM and 6 PM, Monday through Friday
+Trigger = TriggerBuilder.Create()
+ .WithIdentity("BusinessHoursSync")
+ .WithDailyTimeIntervalSchedule(x => x
+ .OnMondayThroughFriday()
+ .StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(8, 0))
+ .EndingDailyAt(TimeOfDay.HourAndMinuteOfDay(18, 0))
+ .WithIntervalInHours(2))
+ .Build();
+```
+
+### Choosing the Right Trigger Type
+
+For different scenarios, you'd choose different trigger types:
+
+- **Daily/Weekly/Monthly Operations**: Use **CronTrigger** for maximum flexibility
+- **High-Frequency Tasks**: Use **SimpleTrigger** for performance (every few seconds/minutes)
+- **Business Calendar Operations**: Use **CalendarIntervalTrigger** for month-end reports, quarterly tasks
+- **Business Hours Operations**: Use **DailyTimeIntervalTrigger** for operations that should only run during specific hours
+
+### Automatic Job Registration
+
+One of ABP's most powerful features is automatic job discovery and registration. When your application starts, ABP automatically:
+
+1. **Scans for Background Workers**: ABP discovers all classes inheriting from `QuartzBackgroundWorkerBase`
+2. **Registers with DI Container**: Each job is registered as a service in the dependency injection container
+3. **Schedules with Quartz**: ABP calls the `ScheduleJob` delegate to register the job with the Quartz scheduler
+4. **Handles Lifecycle**: ABP manages starting and stopping jobs with the application lifecycle
+
+This means you simply create your job class, and ABP handles everything else. No manual registration, no startup code, no configuration files - it just works.
+
+### Understanding Misfire Handling
+
+Misfires occur when a scheduled job cannot execute at its intended time, typically due to system downtime, resource constraints, or the scheduler being paused. Quartz provides several misfire instructions to handle these scenarios:
+
+#### CronTrigger Misfire Instructions
+
+For cron-based schedules like our daily reminder job, Quartz offers these misfire behaviors:
+
+**`MisfireInstruction.DoNothing`** (Default):
+```csharp
+Trigger = TriggerBuilder.Create()
+ .WithIdentity(nameof(SubscriptionExpiryNotifierJob))
+ .WithCronSchedule("0 0 9 * * ?", x => x.WithMisfireHandlingInstructionDoNothing())
+ .Build();
+```
+- Skips all missed executions
+- Waits for the next naturally scheduled time
+- Best for jobs where missing executions is acceptable
+
+**`MisfireInstruction.FireOnceNow`**:
+```csharp
+.WithCronSchedule("0 0 9 * * ?", x => x.WithMisfireHandlingInstructionFireAndProceed())
+```
+- Immediately executes one missed job upon recovery
+- Then continues with the normal schedule
+- Useful when you need to catch up on missed work
+
+**`MisfireInstruction.IgnoreMisfires`**:
+```csharp
+.WithCronSchedule("0 0 9 * * ?", x => x.WithMisfireHandlingInstructionIgnoreMisfires())
+```
+- Executes all missed jobs immediately upon recovery
+- Can cause a burst of executions after extended downtime
+- Use carefully to avoid overwhelming the system
+
+#### SimpleTrigger Misfire Instructions
+
+Simple triggers have their own set of misfire behaviors:
+
+**`MisfireInstruction.FireNow`**: Execute immediately when recovered
+**`MisfireInstruction.RescheduleNowWithExistingRepeatCount`**: Start over with remaining repeat count
+**`MisfireInstruction.RescheduleNowWithRemainingRepeatCount`**: Continue as if no misfire occurred
+**`MisfireInstruction.RescheduleNextWithExistingCount`**: Wait for next interval, keep original repeat count
+
+### Real-World Misfire Considerations
+
+For our subscription reminder system, we chose the default `DoNothing` behavior because:
+
+- **Business Logic**: Sending yesterday's reminder today might confuse customers
+- **Duplicate Prevention**: Our job checks for existing reminders, so running late won't cause duplicate emails
+- **Resource Management**: We avoid overwhelming the email system after extended downtime
+
+However, for other scenarios you might choose differently:
+- **Financial reporting**: Use `FireOnceNow` to ensure reports are always generated
+- **Data synchronization**: Use `IgnoreMisfires` to process all missed sync operations
+- **Cache warming**: Use `DoNothing` since stale cache warming provides no value
+
+### Advanced Job Features
+
+**Error Handling and Resilience**: Our job implementation includes comprehensive error handling for individual client processing, ensuring one failed email doesn't stop the entire batch:
+
+```csharp
+try
+{
+ await emailService.SendSubscriptionExpiryReminderAsync(/*...*/);
+ await LogReminderAsync(client.Id, client.SubscriptionEnd, "Email sent successfully", reminderLogAppService);
+}
+catch (Exception ex)
+{
+ Logger.LogError(ex, "❌ Failed to send reminder to {ClientName}", client.Name);
+ await LogReminderAsync(client.Id, client.SubscriptionEnd, $"Failed: {ex.Message}", reminderLogAppService);
+}
+```
+
+**Duplicate Prevention**: The job checks for existing reminders to prevent sending multiple emails on the same day, even if the job runs multiple times:
+
+```csharp
+private async Task AlreadySentTodayAsync(Guid clientId, IReminderLogAppService reminderLogAppService)
+{
+ var todayReminders = await reminderLogAppService.GetByClientIdAsync(clientId);
+ var today = DateTime.UtcNow.Date;
+
+ return todayReminders.Any(r => r.ReminderDate.Date == today);
+}
+```
+
+This implementation demonstrates how ABP's `QuartzBackgroundWorkerBase` provides a clean, powerful foundation for building robust background jobs that integrate seamlessly with your business logic while leveraging Quartz's enterprise-grade scheduling capabilities.
+
+## Conclusion
+
+You've successfully built a production-ready subscription reminder system that demonstrates the powerful synergy between ABP Framework and `Quartz.NET`. This isn't just a tutorial example - it's a robust, enterprise-grade solution that handles real business requirements.
+
+### What We Accomplished
+
+**✅ Enterprise-Grade Reliability**: PostgreSQL persistence ensures jobs survive restarts and deployments
+**✅ ABP Best Practices**: Used `QuartzBackgroundWorkerBase`, `ICachedServiceProvider`, and ABP's logging infrastructure
+**✅ Real Business Value**: Automated subscription reminders with duplicate prevention and audit logging
+**✅ Flexible Scheduling**: Explored cron expressions, trigger types, and misfire handling strategies
+
+### The Power of ABP + Quartz Integration
+
+The combination delivers exceptional value through automatic job discovery, persistent scheduling, built-in dependency injection, and seamless framework integration. You get enterprise reliability with developer-friendly simplicity.
+
+### Final Thoughts
+
+Complex background processing doesn't have to be complicated to implement. ABP's thoughtful abstractions combined with Quartz's proven engine create a development experience that's both powerful and enjoyable.
+
+Whether you're building subscription management, financial reporting, or data synchronization, these patterns provide a solid foundation for reliable, maintainable solutions.
+
+You can reach sample project's source code from [here](https://github.com/MansurBesleney/MySaaSApplication)
+
+**Happy coding, and may your background jobs never miss a beat!** 🚀
diff --git a/docs/en/Community-Articles/2025-08-12-Integration-Services-Explained/integration-services.jpeg b/docs/en/Community-Articles/2025-08-12-Integration-Services-Explained/integration-services.jpeg
new file mode 100644
index 0000000000..19b1392843
Binary files /dev/null and b/docs/en/Community-Articles/2025-08-12-Integration-Services-Explained/integration-services.jpeg differ
diff --git a/docs/en/Community-Articles/2025-08-12-Integration-Services-Explained/post.md b/docs/en/Community-Articles/2025-08-12-Integration-Services-Explained/post.md
new file mode 100644
index 0000000000..0e11c505da
--- /dev/null
+++ b/docs/en/Community-Articles/2025-08-12-Integration-Services-Explained/post.md
@@ -0,0 +1,138 @@
+# Integration Services in ABP — What they are, when to use them, and how they behave 🚦
+
+If you’ve been building with ABP for a while, you’ve probably used Application Services for your UI and APIs in your .NET and ASP.NET Core apps. Integration Services are similar—but with a different mission: they exist for service-to-service or module-to-module communication, not for end users.
+
+If you want the formal spec, see the official doc: [Integration Services](../../framework/api-development/integration-services.md). This post is the practical, no-fluff guide.
+
+## What is an Integration Service?
+
+An Integration Service is an application service or ASP.NET Core MVC controller marked with the `[IntegrationService]` attribute. That marker tells ABP “this endpoint is for internal communication.”
+
+- They are not exposed by default (safer for reusable modules and monoliths).
+- When exposed, their route prefix is `/integration-api` (so you can easily protect them at your gateway or firewall).
+- Auditing is disabled by default for them (less noise for machine-to-machine calls).
+
+Quick look:
+
+```csharp
+[IntegrationService]
+public interface IProductIntegrationService : IApplicationService
+{
+ Task> GetProductsByIdsAsync(List ids);
+}
+
+public class ProductIntegrationService : ApplicationService, IProductIntegrationService
+{
+ public Task> GetProductsByIdsAsync(List ids)
+ {
+ // fetch and return minimal product info for other services/modules
+ }
+}
+```
+
+## Are they HTTP endpoints?
+
+- By default: no (they won’t be reachable over HTTP in the ASP.NET Core routing pipeline).
+- If you need them over HTTP (typically for microservices), explicitly enable:
+
+```csharp
+Configure(options =>
+{
+ options.ExposeIntegrationServices = true;
+});
+```
+
+Once exposed, ABP puts them under `/integration-api/...` instead of `/api/...` in the ASP.NET Core routing pipeline. That’s your hint to restrict them from public internet access.
+
+## Enable auditing (optional)
+
+If you want audit logs for integration calls, enable it explicitly:
+
+```csharp
+Configure(options =>
+{
+ options.IsEnabledForIntegrationServices = true;
+});
+```
+
+## When should you use Integration Services?
+
+- Internal, synchronous operations between services or modules.
+- You need a “thin” API designed for other services (not for UI): minimal DTOs, no view concerns, predictable contracts.
+- You want to hide these endpoints from public clients, or only allow them inside your private network or k8s cluster.
+- You’re packaging a reusable module that might be used in both monolith and microservice deployments.
+
+## When NOT to use them
+
+- Public APIs or anything intended for browsers/mobile apps → use regular application services/controllers.
+- Asynchronous cross-service workflows → consider domain events + outbox/inbox; use Integration Services for sync calls.
+- Complex, chatty UI endpoints → those belong to your external API surface, not internal integration.
+
+## Common use-cases and examples
+
+- Identity lookups across services: an Ordering service needs basic user info from the Identity service.
+- Permission checks from another module: a CMS module asks a Permission service for access decisions.
+- Product data hydrations: a Cart service needs minimal product details (price, name) from Catalog.
+- Internal admin/maintenance operations that aren’t meant for end users but are needed by other services.
+
+## Example: microservice-to-microservice call
+
+1) Mark and expose the integration service in the target service:
+
+```csharp
+[IntegrationService]
+public interface IUserIntegrationService : IApplicationService
+{
+ Task FindByIdAsync(Guid id);
+}
+
+Configure(o => o.ExposeIntegrationServices = true);
+```
+
+2) In the caller service, add an HTTP client proxy only for Integration Services if you like to keep things clean:
+
+```csharp
+services.AddHttpClientProxies(
+ typeof(TargetServiceApplicationModule).Assembly,
+ remoteServiceConfigurationName: "TargetService",
+ asDefaultServices: true,
+ applicationServiceTypes: ApplicationServiceTypes.IntegrationServices);
+```
+
+3) Call it just like a local service (ABP’s HTTP proxy handles the wire):
+
+```csharp
+public class OrderAppService : ApplicationService
+{
+ private readonly IUserIntegrationService _userIntegrationService;
+
+ public OrderAppService(IUserIntegrationService userIntegrationService)
+ {
+ _userIntegrationService = userIntegrationService;
+ }
+
+ public async Task PlaceOrderAsync(CreateOrderDto input)
+ {
+ var user = await _userIntegrationService.FindByIdAsync(CurrentUser.GetId());
+ // validate user status, continue placing order...
+ }
+}
+```
+
+## Monolith vs. Microservices
+
+- Monolith: keep them unexposed and call via DI in-process. You get the same clear contract with zero network overhead.
+- Microservices: expose them and route behind your gateway. The `/integration-api` prefix makes it easy to firewall/gateway-restrict.
+
+## Practical tips
+
+- Keep integration DTOs lean and stable. These are machine contracts—don’t mix UI concerns.
+- Name them clearly (e.g., `UserIntegrationService`) so intent is obvious.
+- Guard your ASP.NET Core gateway application: block `/integration-api/*` from public traffic.
+- Enable auditing only if you truly need the logs for these calls.
+
+## Further reading
+
+- Official docs: [Integration Services](../../framework/api-development/integration-services.md)
+
+That’s it! Integration Services give you a clean, intentional way to design internal APIs—great in monoliths, essential in microservices.
diff --git a/docs/en/framework/architecture/multi-tenancy/index.md b/docs/en/framework/architecture/multi-tenancy/index.md
index 98a4c9afb5..1bc151bddf 100644
--- a/docs/en/framework/architecture/multi-tenancy/index.md
+++ b/docs/en/framework/architecture/multi-tenancy/index.md
@@ -42,6 +42,8 @@ ABP supports all the following approaches to store the tenant data in the databa
[Saas module (PRO)](../../../modules/saas.md) allows you to set a connection string for any tenant (as optional), so you can achieve any of the approaches.
+> You can see the community article *[Multi-Tenancy with Separate Databases in .NET and ABP Framework](https://abp.io/community/articles/multitenancy-with-separate-databases-in-dotnet-and-abp-51nvl4u9)* for more details about different database architectures with practical implementation details.
+
## Usage
Multi-tenancy system is designed to **work seamlessly** and make your application code **multi-tenancy unaware** as much as possible.
@@ -456,8 +458,9 @@ The [Tenant Management module](../../../modules/tenant-management.md) provides a
### A note about separate database per tenant approach in open source version
While ABP fully supports this option, managing connection strings of tenants from the UI is not available in open source version. You need to have [Saas module (PRO)](../../../modules/saas.md).
-Alternatively you can implement this feature yourself by customizing the tenant management module and tenant application service to create and migrate the database on the fly.
+Alternatively, you can implement this feature yourself by customizing the tenant management module and tenant application service to create and migrate the database on the fly.
## See Also
* [Features](../../infrastructure/features.md)
+* [Article: Multi-Tenancy with Separate Databases in .NET and ABP Framework](https://abp.io/community/articles/multitenancy-with-separate-databases-in-dotnet-and-abp-51nvl4u9)
diff --git a/docs/en/framework/fundamentals/object-extensions.md b/docs/en/framework/fundamentals/object-extensions.md
index b12be63dc0..87ece27f75 100644
--- a/docs/en/framework/fundamentals/object-extensions.md
+++ b/docs/en/framework/fundamentals/object-extensions.md
@@ -394,6 +394,22 @@ public class MyProfile : Profile
It has the same parameters with the `MapExtraPropertiesTo` method.
+#### Mapperly Integration
+
+If you're using the [Mapperly](https://github.com/riok/mapperly) library, the ABP also provides an extension method to utilize the `MapExtraPropertiesTo` method defined above.
+
+You can use the `MapExtraProperties` attribute to Mapperly class:
+
+````csharp
+[Mapper]
+[MapExtraProperties]
+public partial class IdentityUserToProfileDtoMapper : MapperBase
+{
+ public override partial IdentityUserDto Map(IdentityUser source);
+ public override partial void Map(IdentityUser source, IdentityUserDto destination);
+}
+````
+
## Entity Framework Core Database Mapping
If you're using the EF Core, you can map an extra property to a table field in the database. Example:
diff --git a/docs/en/framework/infrastructure/object-to-object-mapping.md b/docs/en/framework/infrastructure/object-to-object-mapping.md
index 8961d804c7..5a9ea5f82a 100644
--- a/docs/en/framework/infrastructure/object-to-object-mapping.md
+++ b/docs/en/framework/infrastructure/object-to-object-mapping.md
@@ -84,7 +84,7 @@ public class UserAppService : ApplicationService
}
````
-You should have defined the mappings before to be able to map objects. See the AutoMapper integration section to learn how to define mappings.
+You should have defined the mappings before to be able to map objects. See the AutoMapper/Mapperly integration section to learn how to define mappings.
## AutoMapper Integration
@@ -217,13 +217,120 @@ public class MyProfile : Profile
}
````
+## Mapperly Integration
+
+[Mapperly](https://github.com/riok/mapperly) is a .NET source generator for generating object mappings. [Volo.Abp.Mapperly](https://www.nuget.org/packages/Volo.Abp.Mapperly) package defines the Mapperly integration for the `IObjectMapper`.
+
+Once you define mappings class as below, you can use the `IObjectMapper` interface just like explained before.
+
+### Define Mapping Classes
+
+You can define a mapper class by using the `Mapper` attribute. The class and methods must be `partial` to allow the Mapperly to generate the implementation during the build process:
+
+````csharp
+[Mapper]
+public partial class UserToUserDtoMapper : MapperBase
+{
+ public override partial UserDto Map(User source);
+ public override partial void Map(User source, UserDto destination);
+}
+````
+
+If you also want to map `UserDto` to `User`, you can inherit from the `TwoWayMapperBase` class:
+
+````csharp
+[Mapper]
+public partial class UserToUserDtoMapper : TwoWayMapperBase
+{
+ public override partial UserDto Map(User source);
+ public override partial void Map(User source, UserDto destination);
+
+ public override partial User ReverseMap(UserDto destination);
+ public override partial void ReverseMap(UserDto destination, User source);
+}
+````
+
+### Before and After Mapping Methods
+
+The base class provides `BeforeMap` and `AfterMap` methods that can be overridden to perform actions before and after the mapping:
+
+````csharp
+[Mapper]
+public partial class UserToUserDtoMapper : TwoWayMapperBase
+{
+ public override partial UserDto Map(User source);
+ public override partial void Map(User source, UserDto destination);
+
+ public override partial void BeforeMap(User source)
+ {
+ //TODO: Perform actions before the mapping
+ }
+
+ public override partial void AfterMap(User source, UserDto destination)
+ {
+ //TODO: Perform actions after the mapping
+ }
+
+ public override partial User ReverseMap(UserDto destination);
+ public override partial void ReverseMap(UserDto destination, User source);
+
+ public override partial void BeforeReverseMap(UserDto destination)
+ {
+ //TODO: Perform actions before the reverse mapping
+ }
+
+ public override partial void AfterReverseMap(UserDto destination, User source)
+ {
+ //TODO: Perform actions after the reverse mapping
+ }
+}
+````
+
+### Mapping the Object Extensions
+
+[Object extension system](../fundamentals/object-extensions.md) allows to define extra properties for existing classes. ABP provides a mapping definition extension to properly map extra properties of two objects:
+
+````csharp
+[Mapper]
+[MapExtraProperties]
+public partial class UserToUserDtoMapper : MapperBase
+{
+ public override partial UserDto Map(User source);
+ public override partial void Map(User source, UserDto destination);
+}
+````
+
+It is suggested to use the `MapExtraPropertiesAttribute` attribute if both classes are extensible objects (implement the `IHasExtraProperties` interface). See the [object extension document](../fundamentals/object-extensions.md) for more.
+
+### Lists and Arrays Support
+
+ABP Mapperly integration also supports mapping lists and arrays as explained in the [IObjectMapper Interface](#iobjectmappertsource-tdestination-interface) section.
+
+**Example**:
+
+````csharp
+[Mapper]
+public partial class UserToUserDtoMapper : MapperBase
+{
+ public override partial UserDto Map(User source);
+ public override partial void Map(User source, UserDto destination);
+}
+
+var users = await _userRepository.GetListAsync(); // returns List
+var dtos = ObjectMapper.Map, List>(users); // creates List
+````
+
+### More Mapperly Features
+
+Most of Mapperly's features such as `Ignore` can be configured through its attributes. See the [Mapperly documentation](https://mapperly.riok.app/docs/intro/) for more details.
+
## Advanced Topics
### IObjectMapper Interface
-Assume that you have created a **reusable module** which defines AutoMapper profiles and uses `IObjectMapper` when it needs to map objects. Your module then can be used in different applications, by nature of the [modularity](../architecture/modularity/basics.md).
+Assume that you have created a **reusable module** which defines AutoMapper/Mapperly profiles and uses `IObjectMapper` when it needs to map objects. Your module then can be used in different applications, by nature of the [modularity](../architecture/modularity/basics.md).
-`IObjectMapper` is an abstraction and can be replaced by the final application to use another mapping library. The problem here that your reusable module is designed to use the AutoMapper library, because it only defines mappings for it. In such a case, you will want to guarantee that your module always uses AutoMapper even if the final application uses another default object mapping library.
+`IObjectMapper` is an abstraction and can be replaced by the final application to use another mapping library. The problem here that your reusable module is designed to use the AutoMapper/Mapperly library, because it only defines mappings for it. In such a case, you will want to guarantee that your module always uses AutoMapper/Mapperly even if the final application uses another default object mapping library.
`IObjectMapper` is used to contextualize the object mapper, so you can use different libraries for different modules/contexts.
@@ -281,6 +388,8 @@ public class UserAppService : ApplicationService
While using the contextualized object mapper is same as the normal object mapper, you should register the contextualized mapper in your module's `ConfigureServices` method:
+When using AutoMapper:
+
````csharp
[DependsOn(typeof(AbpAutoMapperModule))]
public class MyModule : AbpModule
@@ -298,6 +407,20 @@ public class MyModule : AbpModule
}
````
+When using Mapperly:
+
+````csharp
+[DependsOn(typeof(AbpMapperlyModule))]
+public class MyModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ //Use Mapperly for MyModule
+ context.Services.AddMapperlyObjectMapper();
+ }
+}
+````
+
`IObjectMapper` is an essential feature for a reusable module where it can be used in multiple applications each may use a different library for object to object mapping. All pre-built ABP modules are using it. But, for the final application, you can ignore this interface and always use the default `IObjectMapper` interface.
### IObjectMapper Interface
diff --git a/docs/en/framework/ui/angular/quick-start.md b/docs/en/framework/ui/angular/quick-start.md
index dec3a23262..3dd6e2f32d 100644
--- a/docs/en/framework/ui/angular/quick-start.md
+++ b/docs/en/framework/ui/angular/quick-start.md
@@ -1,12 +1,12 @@
# ABP Angular Quick Start
-**In this version ABP uses Angular [17.3.x](https://github.com/angular/angular/tree/17.3.x) version. You don't have to install Angular CLI globally**
+**In this version ABP uses Angular [20.0.x](https://github.com/angular/angular/tree/20.0.x) version. You don't have to install Angular CLI globally**
## How to Prepare Development Environment
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 `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.
+1. **Install Node.js:** Please visit [Node.js downloads page](https://nodejs.org/en/download/) and download proper Node.js `v20.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.
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)
diff --git a/docs/en/framework/ui/blazor/layout-hooks.md b/docs/en/framework/ui/blazor/layout-hooks.md
index 9e29ff69cd..d54b225c6d 100644
--- a/docs/en/framework/ui/blazor/layout-hooks.md
+++ b/docs/en/framework/ui/blazor/layout-hooks.md
@@ -2,7 +2,7 @@
ABP theming system places the page layout into the [theme](theming.md) NuGet packages. That means the final application doesn't include a layout, so you can't directly change the layout code to customize it.
-> If you create a Blazor WASM project, the `index.html` file will be included within the template. You can also customize it to your needs.
+> If you created your Blazor application with ABP templates, then you'll have an `App.razor` file in your project. You can customize it to your needs and even extend it with layout hooks.
You can copy the theme code into your solution. In this case, you are completely free to customize it. However, then you won't be able to get automatic updates of the theme (by upgrading the theme NuGet package).
@@ -101,11 +101,41 @@ See the *Layouts* section below to learn more about the layout system.
There are some pre-defined layout hook points. The standard hook points are:
+* `LayoutHooks.Head.First`: Used to add a component as the first item in the HTML head tag.
+* `LayoutHooks.Head.Last`: Used to add a component as the last item in the HTML head tag.
* `LayoutHooks.Body.First`: Used to add a component as the first item in the HTML body tag.
* `LayoutHooks.Body.Last`: Used to add a component as the last item in the HTML body tag.
> You (or the modules you are using) can add **multiple items to the same hook point**. All of them will be added to the layout in the order they were added.
+### Render LayoutHooks.Head in App.razor
+
+In your Blazor application, there is an `App.razor` file, which acts as the entry point of your application. If you need to render layout hooks between the **head** tags, then you should manually register the layout hooks as below:
+
+```csharp
+@using Volo.Abp.AspNetCore.Components.Web.Theming.Components.LayoutHooks;
+@using Volo.Abp.Ui.LayoutHooks;
+@using Volo.Abp.AspNetCore.Components.Web.Theming.Layout;
+
+
+
+
+
+
+ // Your head content
+ // ...
+
+
+
+
+ // Your body content
+ // ...
+
+
+```
+
+After registering the related layout hooks, you can define components to render in the specific place accordingly as mentioned above.
+
## Layouts
The layout system allows themes to define the standard named layouts and allows any page to select a proper layout for its purpose. There is one pre-defined layout:
diff --git a/docs/en/get-started/images/abp-studio-created-new-solution_dark.png b/docs/en/get-started/images/abp-studio-created-new-solution_dark.png
new file mode 100644
index 0000000000..1375f384c4
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-created-new-solution_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-additional-options_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-additional-options_dark.png
new file mode 100644
index 0000000000..aa483a8f02
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-additional-options_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-database-configurations-efcore_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-database-configurations-efcore_dark.png
new file mode 100644
index 0000000000..3bbb0cf2d3
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-database-configurations-efcore_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-database-configurations-mongo_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-database-configurations-mongo_dark.png
new file mode 100644
index 0000000000..53f65e05b2
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-database-configurations-mongo_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-database-provider-efcore_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-database-provider-efcore_dark.png
new file mode 100644
index 0000000000..1b101fe134
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-database-provider-efcore_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-database-provider-mongo_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-database-provider-mongo_dark.png
new file mode 100644
index 0000000000..51b9fb1687
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-database-provider-mongo_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-mobile-framework_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-mobile-framework_dark.png
new file mode 100644
index 0000000000..9e3b961b92
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-mobile-framework_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-modularity_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-modularity_dark.png
new file mode 100644
index 0000000000..4e03f136ed
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-modularity_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-multi-tenancy_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-multi-tenancy_dark.png
new file mode 100644
index 0000000000..5cfa2fb425
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-multi-tenancy_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-optional-modules_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-optional-modules_dark.png
new file mode 100644
index 0000000000..f5921aeb64
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-optional-modules_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-public-website_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-public-website_dark.png
new file mode 100644
index 0000000000..7dc6796f21
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-public-website_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-solution-properties_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-solution-properties_dark.png
new file mode 100644
index 0000000000..7d9b180991
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-solution-properties_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-solution-structure-tiered_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-solution-structure-tiered_dark.png
new file mode 100644
index 0000000000..abfad1996d
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-solution-structure-tiered_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-solution-structure_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-solution-structure_dark.png
new file mode 100644
index 0000000000..e03f424b22
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-solution-structure_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-blazor-server_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-blazor-server_dark.png
new file mode 100644
index 0000000000..98849d3b62
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-blazor-server_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-blazor-wasm_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-blazor-wasm_dark.png
new file mode 100644
index 0000000000..b58698db00
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-blazor-wasm_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-blazor-webapp_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-blazor-webapp_dark.png
new file mode 100644
index 0000000000..394d049398
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-blazor-webapp_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-mvc_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-mvc_dark.png
new file mode 100644
index 0000000000..4dbac112cd
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-mvc_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-ng_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-ng_dark.png
new file mode 100644
index 0000000000..cd804b5308
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-framework-ng_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-theme_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-theme_dark.png
new file mode 100644
index 0000000000..544a3df51c
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog-ui-theme_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-dialog_dark.png b/docs/en/get-started/images/abp-studio-new-solution-dialog_dark.png
new file mode 100644
index 0000000000..b131e76ed0
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-dialog_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-new-solution-language-selection_dark.png b/docs/en/get-started/images/abp-studio-new-solution-language-selection_dark.png
new file mode 100644
index 0000000000..ac8315e116
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-new-solution-language-selection_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-created-new-solution_dark.png b/docs/en/get-started/images/abp-studio-no-layers-created-new-solution_dark.png
new file mode 100644
index 0000000000..4939b13d12
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-created-new-solution_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-additional-options_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-additional-options_dark.png
new file mode 100644
index 0000000000..f34f6c415b
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-additional-options_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-configurations-efcore_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-configurations-efcore_dark.png
new file mode 100644
index 0000000000..075f9224c7
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-configurations-efcore_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-configurations-mongo_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-configurations-mongo_dark.png
new file mode 100644
index 0000000000..973758b1a6
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-configurations-mongo_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-provider-efcore_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-provider-efcore_dark.png
new file mode 100644
index 0000000000..c31eaee8e3
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-provider-efcore_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-provider-mongo_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-provider-mongo_dark.png
new file mode 100644
index 0000000000..a3915f2ff9
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-database-provider-mongo_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-multi-tenancy_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-multi-tenancy_dark.png
new file mode 100644
index 0000000000..a64debc8db
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-multi-tenancy_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-solution-properties_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-solution-properties_dark.png
new file mode 100644
index 0000000000..1f8351d656
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-solution-properties_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-blazor-server_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-blazor-server_dark.png
new file mode 100644
index 0000000000..d4a126c5b8
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-blazor-server_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-blazor-wasm_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-blazor-wasm_dark.png
new file mode 100644
index 0000000000..bf2cfb8c44
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-blazor-wasm_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-blazor-webapp_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-blazor-webapp_dark.png
new file mode 100644
index 0000000000..4b3c75467e
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-blazor-webapp_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-mvc_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-mvc_dark.png
new file mode 100644
index 0000000000..45e0e0b89d
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-mvc_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-ng_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-ng_dark.png
new file mode 100644
index 0000000000..fbc97bbf6e
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog-ui-framework-ng_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog_dark.png
new file mode 100644
index 0000000000..3453bd976d
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-dialog_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-language-selection_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-language-selection_dark.png
new file mode 100644
index 0000000000..23da11bfbf
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-language-selection_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-modularity_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-modularity_dark.png
new file mode 100644
index 0000000000..accd5e6739
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-modularity_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-new-solution-optional-modules_dark.png b/docs/en/get-started/images/abp-studio-no-layers-new-solution-optional-modules_dark.png
new file mode 100644
index 0000000000..9992d266c5
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-new-solution-optional-modules_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-open-in-visual-studio_dark.png b/docs/en/get-started/images/abp-studio-no-layers-open-in-visual-studio_dark.png
new file mode 100644
index 0000000000..f599c9bc8c
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-open-in-visual-studio_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-quick-start-application-solution-runner_dark.png b/docs/en/get-started/images/abp-studio-no-layers-quick-start-application-solution-runner_dark.png
new file mode 100644
index 0000000000..5a0aba31b6
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-quick-start-application-solution-runner_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-quick-start-browse-command_dark.png b/docs/en/get-started/images/abp-studio-no-layers-quick-start-browse-command_dark.png
new file mode 100644
index 0000000000..a90b3fe57f
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-quick-start-browse-command_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-quick-start-browse-user-list_dark.png b/docs/en/get-started/images/abp-studio-no-layers-quick-start-browse-user-list_dark.png
new file mode 100644
index 0000000000..fbdd1cb355
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-quick-start-browse-user-list_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-quick-start-browse_dark.png b/docs/en/get-started/images/abp-studio-no-layers-quick-start-browse_dark.png
new file mode 100644
index 0000000000..aa9e95bf4f
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-quick-start-browse_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-no-layers-quick-start-example-applications-in-solution-runner_dark.png b/docs/en/get-started/images/abp-studio-no-layers-quick-start-example-applications-in-solution-runner_dark.png
new file mode 100644
index 0000000000..f18fc2c646
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-no-layers-quick-start-example-applications-in-solution-runner_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-nolayers-new-solution-dialog-ui-theme_dark.png b/docs/en/get-started/images/abp-studio-nolayers-new-solution-dialog-ui-theme_dark.png
new file mode 100644
index 0000000000..64788b9b45
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-nolayers-new-solution-dialog-ui-theme_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-open-in-visual-studio_dark.png b/docs/en/get-started/images/abp-studio-open-in-visual-studio_dark.png
new file mode 100644
index 0000000000..59f8877e9f
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-open-in-visual-studio_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-quick-start-application-solution-runner_dark.png b/docs/en/get-started/images/abp-studio-quick-start-application-solution-runner_dark.png
new file mode 100644
index 0000000000..382461de06
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-quick-start-application-solution-runner_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-quick-start-browse-command_dark.png b/docs/en/get-started/images/abp-studio-quick-start-browse-command_dark.png
new file mode 100644
index 0000000000..d0d3b3af06
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-quick-start-browse-command_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-quick-start-browse-user-list_dark.png b/docs/en/get-started/images/abp-studio-quick-start-browse-user-list_dark.png
new file mode 100644
index 0000000000..84b4bb8f4d
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-quick-start-browse-user-list_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-quick-start-browse_dark.png b/docs/en/get-started/images/abp-studio-quick-start-browse_dark.png
new file mode 100644
index 0000000000..dab624fa75
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-quick-start-browse_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-quick-start-example-applications-in-solution-runner_dark.png b/docs/en/get-started/images/abp-studio-quick-start-example-applications-in-solution-runner_dark.png
new file mode 100644
index 0000000000..f06b2b4ca7
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-quick-start-example-applications-in-solution-runner_dark.png differ
diff --git a/docs/en/get-started/images/abp-studio-welcome-screen_dark.png b/docs/en/get-started/images/abp-studio-welcome-screen_dark.png
new file mode 100644
index 0000000000..5aeabbce38
Binary files /dev/null and b/docs/en/get-started/images/abp-studio-welcome-screen_dark.png differ
diff --git a/docs/en/get-started/images/bookstore-browser-users-page_dark.png b/docs/en/get-started/images/bookstore-browser-users-page_dark.png
new file mode 100644
index 0000000000..85cd35c81d
Binary files /dev/null and b/docs/en/get-started/images/bookstore-browser-users-page_dark.png differ
diff --git a/docs/en/get-started/images/no-layers-bookstore-browser-users-page_dark.png b/docs/en/get-started/images/no-layers-bookstore-browser-users-page_dark.png
new file mode 100644
index 0000000000..85cd35c81d
Binary files /dev/null and b/docs/en/get-started/images/no-layers-bookstore-browser-users-page_dark.png differ
diff --git a/docs/en/get-started/images/no-layers-visual-studio-bookstore-application_dark.png b/docs/en/get-started/images/no-layers-visual-studio-bookstore-application_dark.png
new file mode 100644
index 0000000000..4f7bd3dd19
Binary files /dev/null and b/docs/en/get-started/images/no-layers-visual-studio-bookstore-application_dark.png differ
diff --git a/docs/en/get-started/images/solution-runner-public-website.png b/docs/en/get-started/images/solution-runner-public-website.png
index b1e76a4ce6..3b08bc3e9a 100644
Binary files a/docs/en/get-started/images/solution-runner-public-website.png and b/docs/en/get-started/images/solution-runner-public-website.png differ
diff --git a/docs/en/get-started/images/visual-studio-bookstore-application_dark.png b/docs/en/get-started/images/visual-studio-bookstore-application_dark.png
new file mode 100644
index 0000000000..a1530f0036
Binary files /dev/null and b/docs/en/get-started/images/visual-studio-bookstore-application_dark.png differ
diff --git a/docs/en/get-started/layered-web-application.md b/docs/en/get-started/layered-web-application.md
index e314f6a5b0..3dcbb90f75 100644
--- a/docs/en/get-started/layered-web-application.md
+++ b/docs/en/get-started/layered-web-application.md
@@ -29,15 +29,15 @@ First things first! Let's setup your development environment before creating the
Assuming that you have [installed and logged in](../studio/installation.md) to the application, you should see the following screen when you open ABP Studio:
-
+
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:
-
+
We will use the *Application (Layered)* solution template for this tutorial, so pick it and click the *Next* button:
-
+
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`.
@@ -45,29 +45,61 @@ 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:
-
+{{ if UI == "MVC" }}
+
+{{ else if UI == "Blazor" }}
+
+{{ else if UI == "BlazorServer" }}
+
+{{ else if UI == "BlazorWebApp" }}
+
+{{ else if UI == "NG" }}
+
+{{ end }}
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:
+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 *Database Provider* selection screen:
+
+{{ if DB == "EF" }}
+
+{{ else }}
+
+{{ 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" }}
+
+{{ else }}
+
+{{ end }}
+
+Here, you can select the database management systems (DBMS){{ if DB == "EF" }} and the connection string{{ end }}. Then, click the *Next* button for additional *Multi-Tenancy* selection:
-
+
+
+Here, you can enable or disable multi-tenancy for your solution. You can further configure the options or leave them as default and click the *Next* button for the *UI Theme* selection screen:
+
+
+
+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 *Database Provider* selection screen:
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 *Mobile Framework* selection:
-
+
Here, you see all the mobile applications available in that startup solution template. These mobile applications are well-integrated into your solution and can use the same backend with your web application. They are simple (do not have pre-built features as much as the web application) but a very good starting point to build your mobile application.
Pick the one best for you, or select the *None* if you don't want a mobile application in your solution, then click Next to navigate to the *Public website* screen:
-
+
That startup solution template also provides an option to create a second web application inside the solution. The second application is called the Public website, an ASP.NET Core MVC / Razor Page application. It can be used to create a public landing/promotion for your product. It is well integrated into the solution (can share the same services, entities, database, and the same authentication logic, for example). If you want, you can also include the [CMS Kit module](../modules/cms-kit) to your solution to add dynamic content features to your web application.
So, either select the *Public website* or skip it and click the Next button for the *Optional Modules* selection:
-
+
Each item in that list is a pre-built application module. You can click the blue icon near to the module name to get more information about the module. You can leave the list as is (so, it installs the most common and used modules for you) or customize based on your preference.
@@ -77,11 +109,11 @@ Once you select the desired modules, click the *Next* button for the *Solution S
{{ if Tiered == "Yes" }}
-
+
{{ else }}
-
+
{{ end }}
@@ -89,25 +121,23 @@ It creates a separate host application that only serves the HTTP (REST) APIs. Th
The tiered architecture allows you to host the web (UI) application in a server that can not access to your database server. However, it brings a slight loss of performance (because of the HTTP calls between UI and HTTP API applications) and makes your architecture, development, and deployment more complex. If you don't understand the tiered structure, just skip it.
-After making your *Tiered* selection, you can click the *Next* button for the *Database Provider* selection:
+After making your *Tiered* selection, you can click the *Next* button for the *Language Selection* page:
-{{ if DB == "EF" }}
-
-{{ else }}
-
-{{ 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*:
+In this step, you can choose which languages your application will support.
-{{ if DB == "EF" }}
-
-{{ else }}
-
-{{ end }}
+* Default Language: Select the main language for your app.
+
+* Localizable User Interface: Turn this on to support multiple languages.
+
+* Available Languages: Check the languages you want to include.
+
+* Click Add Custom Language if you want to add a language that is not listed.
-Here, you can select the database management systems (DBMS){{ if DB == "EF" }} and the connection string{{ end }}. Click *Next* button to see the *Additional Options*.
+You can change these settings later if needed. Thenk click the *Next* button for the *Additional Options* page:
-
+
If you uncheck the *Kubernetes Configuration* option, the solution will not include the Kubernetes configuration files, such as Helm charts and other Kubernetes-related files. You can also specify *Social Logins*; if you uncheck this option, the solution will not be configured for social login. Lastly, you can specify the *Include Tests* option to include or exclude the test projects from the solution.
@@ -115,11 +145,11 @@ On the next screen, you can configure the modularity options for your solution:
> If you select the *Setup as a modular solution* option, the solution is created more ready for [modular monolith development](../tutorials/modular-crm/index.md) and allows you to add sub-modules during the solution creation phase.
-
+
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:
-
+
You can explore the solution, but you need to wait for background tasks to be completed before running any application in the solution.
@@ -133,13 +163,13 @@ Open the [Solution Runner](../studio/running-applications.md) section on the lef
> The solution runner structure can be different in your case based on the options you've selected.
-
+
Once you click the *Play* icon on the left side, the section is open in the same place as the Solution Explorer section. ABP Studio also opens the *Application Monitor* view on the main content area. *Application Monitor* shows useful insights for your applications (e.g. *HTTP Request*, *Events* and *Exceptions*) in real-time. You can use it to see the happenings in your applications, so you can easily track errors and many helpful details.
In the Solution Runner section (on the left side) you can see all the runnable applications in the current solution. For the MVC with public website and MAUI mobile example, we have four applications:
-
+
You can run all the applications or start them one by one. To start an application, either click the *Play* icon near to the application or right-click and select the *Run* -> *Start* context menu item.
@@ -172,17 +202,17 @@ You can start the following application(s):
Once the `Acme.BookStore.{{ if UI == "NG" }}Angular{{ else if UI == "BlazorServer" || UI == "Blazor" || UI == "BlazorWebApp" }}Blazor{{ else }}Web{{ end }}` application started, you can right-click it and select the *Browse* command:
-
+
The *Browse* command opens the UI of the web application in the built-in browser:
-
+
You can browse your application in a full-featured web browser in ABP Studio. Click the *Login* button in the application UI, enter `admin` as username and `1q2w3E*` as password to login to the application.
The following screenshot was taken from the *User Management* page of the [Identity module](../modules/identity.md) that is pre-installed in the application:
-
+
## Open the Solution in Visual Studio
@@ -192,7 +222,7 @@ First of all, we can stop the application(s) in ABP Studio, so it won't conflict
You can use ABP Studio to open the solution with Visual Studio. Right-click to the `Acme.BookStore` [module](../modules), and select the *Open with* -> *Visual Studio* command:
-
+
If the *Visual Studio* command is not available, that means ABP Studio could not detect it on your computer. You can open the solution folder in your local file system (you can use the *Open with* -> *Explorer* as a shortcut) and manually open the solution in Visual Studio.
@@ -200,11 +230,11 @@ Once the solution is opened in Visual Studio, you should see a screen like shown
> The solution structure can be different in your case based on the options you've selected.
-
+
Right-click the `Acme.BookStore.{{ if UI == "NG" || UI == "Blazor" }}HttpApi.Host{{ else if UI == "BlazorServer" || UI == "BlazorWebApp" }}Blazor{{ else }}Web{{ end }}` project and select the *Set as Startup Project* command. You can then hit *F5* or *Ctrl + F5* to run the web application. It will run and open the application UI in your default browser:
-
+
You can use `admin` as username and `1q2w3E*` as default password to login to the application.
@@ -238,4 +268,4 @@ Before starting the mobile application, ensure that you configure it for [react-
> For example in non-tiered MVC with public website application:
-
+
\ No newline at end of file
diff --git a/docs/en/get-started/single-layer-web-application.md b/docs/en/get-started/single-layer-web-application.md
index d75c3f2031..630c2a9046 100644
--- a/docs/en/get-started/single-layer-web-application.md
+++ b/docs/en/get-started/single-layer-web-application.md
@@ -29,15 +29,15 @@ First things first! Let's setup your development environment before creating the
Assuming that you have [installed and logged in](../studio/installation.md) to the application, you should see the following screen when you open ABP Studio:
-
+
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:
-
+
We will use the *Application (Single Layer)* solution template for this tutorial, so pick it and click the *Next* button:
-
+
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`.
@@ -45,45 +45,79 @@ 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:
-
-
-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:
+{{ if UI == "MVC" }}
+
+{{ else if UI == "Blazor" }}
+
+{{ else if UI == "BlazorServer" }}
+
+{{ else if UI == "BlazorWebApp" }}
+
+{{ else if UI == "NG" }}
+
+{{ end }}
-
+Here, you see all the possible UI options supported by that startup solution template. Pick the **{{ UI_Value }}**.
-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:
+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 *Database Provider* selection screen:
{{ if DB == "EF" }}
-
+
{{ else }}
-
+
{{ 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" }}
-
+
{{ else }}
-
+
{{ end }}
-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.
+Here, you can select the database management systems (DBMS){{ if DB == "EF" }} and the connection string{{ end }}. Then, click the *Next* button for additional *Multi-Tenancy* selection:
+
+
+
+Here, you can enable or disable multi-tenancy for your solution. You can further configure the options or leave them as default and click the *Next* button for the *UI Theme* selection screen:
+
+
+
+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 *Optional Modules* selection:
+
+Then, you can select optional modules according to your preferences.
+
+
+
+Select the modules you want to use in your project; you can disable the ones you don’t need based on your preferences. Then, click the *Next* button for the *Language Selection* page:
+
+
+
+In this step, you can choose which languages your application will support.
+
+* Default Language: Select the main language for your app.
+
+* Localizable User Interface: Turn this on to support multiple languages.
+
+* Available Languages: Check the languages you want to include.
+
+* Click Add Custom Language if you want to add a language that is not listed.
+
+You can change these settings later if needed. Thenk click the *Next* button for the *Additional Options* page:
-
+
Configure any additional options as needed and click the *Next* button to continue. On the next screen, you can configure the modularity options for your solution:
> If you select the *Setup as a modular solution* option, the solution is created more ready for [modular monolith development](../tutorials/modular-crm/index.md) and allows you to add sub-modules during the solution creation phase.
-
+
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:
-
+
You can explore the solution, but you need to wait for background tasks to be completed before running any application in the solution.
@@ -95,13 +129,13 @@ Open the [Solution Runner](../studio/running-applications.md) section on the lef
> The solution runner structure can be different in your case based on the options you've selected.
-
+
Once you click the *Play* icon on the left side, the section is open in the same place as the Solution Explorer section. ABP Studio also opens the *Application Monitor* view on the main content area. *Application Monitor* shows useful insights for your applications (e.g. *HTTP Request*, *Events*, and *Exceptions*) in real-time. You can use it to see the happenings in your applications, so you can easily track errors and many helpful details.
In the Solution Runner section (on the left side) you can see all the runnable applications in the current solution. For the MVC website example, we have only one application:
-
+
To start an application, either click the *Play* icon near to the application or right-click and select the *Run* -> *Start* context menu item.
@@ -109,17 +143,17 @@ You can start the `Acme.BookStore`{{ if UI == "NG" }} and `Acme.BookStore.Angula
Once the `Acme.BookStore{{ if UI == "NG" }}.Angular{{ end }}` application started, you can right-click it and select the *Browse* command:
-
+
The *Browse* command opens the UI of the web application in the built-in browser:
-
+
You can browse your application in a full-featured web browser in ABP Studio. Click the *Login* button in the application UI, enter `admin` as username and `1q2w3E*` as password to login to the application.
The following screenshot was taken from the *User Management* page of the [Identity module](../modules/identity.md) that is pre-installed in the application:
-
+
## Open the Solution in Visual Studio
@@ -129,7 +163,7 @@ First of all, we can stop the application(s) in ABP Studio, so it won't conflict
You can use ABP Studio to open the solution with Visual Studio. Right-click to the `Acme.BookStore` [module](../modules), and select the *Open with* -> *Visual Studio* command:
-
+
If the *Visual Studio* command is not available, that means ABP Studio could not detect it on your computer. You can open the solution folder in your local file system (you can use the *Open with* -> *Explorer* as a shortcut) and manually open the solution in Visual Studio.
@@ -137,10 +171,10 @@ Once the solution is opened in Visual Studio, you should see a screen like shown
> The solution structure can be different in your case based on the options you've selected.
-
+
You can then hit *F5* or *Ctrl + F5* to run the web application. It will run and open the application UI in your default browser:
-
+
You can use `admin` as username and `1q2w3E*` as default password to login to the application.
diff --git a/docs/en/release-info/migration-guides/AutoMapper-To-Mapperly.md b/docs/en/release-info/migration-guides/AutoMapper-To-Mapperly.md
new file mode 100644
index 0000000000..11112e2bc6
--- /dev/null
+++ b/docs/en/release-info/migration-guides/AutoMapper-To-Mapperly.md
@@ -0,0 +1,211 @@
+# Migrating from AutoMapper to Mapperly
+
+## Introduction
+
+The AutoMapper library is **no longer free for commercial use**. For more details, you can refer to [this announcement post](https://www.jimmybogard.com/automapper-and-mediatr-going-commercial/).
+
+ABP Framework provides both AutoMapper and Mapperly integrations. If your project currently uses AutoMapper and you don't have a commercial license, you can switch to Mapperly by following the steps outlined below.
+
+## Migration Steps
+
+Please open your project in an IDE(`Visual Studio`, `VS Code` or `JetBrains Rider`), then perform the following global search and replace operations:
+
+1. Replace `Volo.Abp.AutoMapper` with `Volo.Abp.Mapperly` in all `*.csproj` files.
+2. Replace `using Volo.Abp.AutoMapper;` with `using Volo.Abp.Mapperly;` in all `*.cs` files.
+3. Replace `AbpAutoMapperModule` with `AbpMapperlyModule` in all `*.cs` files.
+4. Replace `AddAutoMapperObjectMapper` with `AddMapperlyObjectMapper` in all `*.cs` files.
+5. Remove any code sections that configure `Configure`.
+6. Review any existing AutoMapper `Profile` classes and ensure all newly created Mapperly mapping classes are registered appropriately. (You can refer to the example below for guidance)
+
+**Example:**
+
+Here is an AutoMapper's `Profile` class:
+
+```csharp
+public class ExampleAutoMapper : Profile
+{
+ public AbpIdentityApplicationModuleAutoMapperProfile()
+ {
+ CreateMap()
+ .MapExtraProperties()
+ .Ignore(x => x.IsLockedOut)
+ .Ignore(x => x.SupportTwoFactor)
+ .Ignore(x => x.RoleNames);
+
+ CreateMap();
+
+ CreateMap()
+ .MapExtraProperties();
+
+ CreateMap()
+ .ReverseMap();
+
+ CreateMap()
+ .ForMember(dest => dest.RoleId, src => src.MapFrom(r => r.Id));
+
+ CreateMap()
+ .ForMember(dest => dest.Active, src => src.MapFrom(r => r.IsActive ? "Yes" : "No"))
+ .ForMember(dest => dest.EmailConfirmed, src => src.MapFrom(r => r.EmailConfirmed ? "Yes" : "No"))
+ .ForMember(dest => dest.TwoFactorEnabled, src => src.MapFrom(r => r.TwoFactorEnabled ? "Yes" : "No"))
+ .ForMember(dest => dest.AccountLookout, src => src.MapFrom(r => r.LockoutEnd != null && r.LockoutEnd > DateTime.UtcNow ? "Yes" : "No"))
+ .Ignore(x => x.Roles);
+ }
+}
+```
+
+And the Mapperly mapping class:
+
+```csharp
+[Mapper]
+[MapExtraProperties]
+public partial class IdentityUserToIdentityUserDtoMapper : MapperBase
+{
+ [MapperIgnoreTarget(nameof(IdentityUserDto.IsLockedOut))]
+ [MapperIgnoreTarget(nameof(IdentityUserDto.SupportTwoFactor))]
+ [MapperIgnoreTarget(nameof(IdentityUserDto.RoleNames))]
+ public override partial IdentityUserDto Map(IdentityUser source);
+
+ [MapperIgnoreTarget(nameof(IdentityUserDto.IsLockedOut))]
+ [MapperIgnoreTarget(nameof(IdentityUserDto.SupportTwoFactor))]
+ [MapperIgnoreTarget(nameof(IdentityUserDto.RoleNames))]
+ public override partial void Map(IdentityUser source, IdentityUserDto destination);
+}
+
+[Mapper]
+public partial class IdentityUserClaimToIdentityUserClaimDtoMapper : MapperBase
+{
+ public override partial IdentityUserClaimDto Map(IdentityUserClaim source);
+
+ public override partial void Map(IdentityUserClaim source, IdentityUserClaimDto destination);
+}
+
+[Mapper]
+[MapExtraProperties]
+public partial class OrganizationUnitToOrganizationUnitDtoMapper : MapperBase
+{
+ public override partial OrganizationUnitDto Map(OrganizationUnit source);
+ public override partial void Map(OrganizationUnit source, OrganizationUnitDto destination);
+}
+
+[Mapper]
+public partial class OrganizationUnitRoleToOrganizationUnitRoleDtoMapper : TwoWayMapperBase
+{
+ public override partial OrganizationUnitRoleDto Map(OrganizationUnitRole source);
+ public override partial void Map(OrganizationUnitRole source, OrganizationUnitRoleDto destination);
+
+ public override partial OrganizationUnitRole ReverseMap(OrganizationUnitRoleDto destination);
+ public override partial void ReverseMap(OrganizationUnitRoleDto destination, OrganizationUnitRole source);
+}
+
+[Mapper]
+[MapExtraProperties]
+public partial class OrganizationUnitToOrganizationUnitWithDetailsDtoMapper : MapperBase
+{
+ [MapperIgnoreTarget(nameof(OrganizationUnitWithDetailsDto.Roles))]
+ [MapperIgnoreTarget(nameof(OrganizationUnitWithDetailsDto.UserCount))]
+ public override partial OrganizationUnitWithDetailsDto Map(OrganizationUnit source);
+
+ [MapperIgnoreTarget(nameof(OrganizationUnitWithDetailsDto.Roles))]
+ [MapperIgnoreTarget(nameof(OrganizationUnitWithDetailsDto.UserCount))]
+ public override partial void Map(OrganizationUnit source, OrganizationUnitWithDetailsDto destination);
+}
+
+[Mapper]
+public partial class IdentityRoleToOrganizationUnitRoleDtoMapper : MapperBase
+{
+ [MapProperty(nameof(IdentityRole.Id), nameof(OrganizationUnitRoleDto.RoleId))]
+ public override partial OrganizationUnitRoleDto Map(IdentityRole source);
+
+ [MapProperty(nameof(IdentityRole.Id), nameof(OrganizationUnitRoleDto.RoleId))]
+ public override partial void Map(IdentityRole source, OrganizationUnitRoleDto destination);
+}
+
+[Mapper]
+public partial class IdentityUserToIdentityUserExportDtoMapper : MapperBase
+{
+ [MapperIgnoreTarget(nameof(IdentityUserExportDto.Roles))]
+ public override partial IdentityUserExportDto Map(IdentityUser source);
+
+ [MapperIgnoreTarget(nameof(IdentityUserExportDto.Roles))]
+ public override partial void Map(IdentityUser source, IdentityUserExportDto destination);
+
+ public override void AfterMap(IdentityUser source, IdentityUserExportDto destination)
+ {
+ destination.Active = source.IsActive ? "Yes" : "No";
+ destination.EmailConfirmed = source.EmailConfirmed ? "Yes" : "No";
+ destination.TwoFactorEnabled = source.TwoFactorEnabled ? "Yes" : "No";
+ destination.AccountLookout = source.LockoutEnd != null && source.LockoutEnd > DateTime.UtcNow ? "Yes" : "No";
+ }
+}
+```
+
+## Mapperly Mapping Class
+
+To use Mapperly, you'll need to create a dedicated mapping class for each source and destination types.
+
+* Use the `[Mapper]` attribute to designate the class as a Mapperly mapper.
+* Replace AutoMapper's `Ignore()` method with the `[MapperIgnoreTarget]` attribute.
+* Replace the `MapExtraProperties()` method with the `[MapExtraProperties]` attribute.
+* Use the `TwoWayMapperBase` class as an alternative to AutoMapper’s `ReverseMap()` functionality.
+* Implement the `AfterMap()` method to execute logic after the mapping is completed.
+
+### Dependency Injection in Mapper Class
+
+All Mapperly mapping classes automatically registered in the the [dependency injection (DI)](../../framework/fundamentals/dependency-injection.md) container. To use a service within a Mapper class, simply add it to the constructor, Mapperly will inject it automatically.
+
+**Example:**
+
+```csharp
+public partial class IdentityUserToIdentityUserDtoMapper : MapperBase
+{
+ public IdentityUserToIdentityUserDtoMapper(MyService myService)
+ {
+ _myService = myService;
+ }
+
+ public override partial IdentityUserDto Map(IdentityUser source);
+ public override partial void Map(IdentityUser source, IdentityUserDto destination);
+
+ public override void AfterMap(IdentityUser source, IdentityUserDto destination)
+ {
+ destination.MyProperty = _myService.GetMyProperty(source.MyProperty);
+ }
+}
+```
+
+## Mapperly Documentation
+
+Please refer to the [Mapperly documentation](https://mapperly.riok.app/docs/intro/) for more details.
+
+**Key points:**
+
+- [Mapperly Configuration](https://mapperly.riok.app/docs/configuration/mapper/)
+- [Mapperly Enums](https://mapperly.riok.app/docs/configuration/enum/)
+- [Mapperly Flattening and unflattening](https://mapperly.riok.app/docs/configuration/flattening/)
+
+
+## Set Default Mapping Provider
+
+When your project contains modules using both AutoMapper and Mapperly, you may need to explicitly set the default `IAutoObjectMappingProvider` to ensure consistent behavior across your application.
+
+If your application uses `AutoMapper`:
+
+```csharp
+public override void ConfigureServices(ServiceConfigurationContext context)
+{
+ context.Services.AddAutoMapperObjectMapper();
+}
+```
+
+If your application uses `Mapperly`:
+
+```csharp
+public override void ConfigureServices(ServiceConfigurationContext context)
+{
+ context.Services.AddMapperlyObjectMapper();
+}
+```
+
+### Why Set Default Mapping Provider?
+
+When your project contains modules using both AutoMapper and Mapperly, both `AbpAutoMapperModule` and `AbpMapperlyModule` will be loaded. Their dependency order may vary based on your project's module structure, and the last loaded module will override the `IAutoObjectMappingProvider` implementation. This could lead to unexpected behavior. Setting an explicit default ensures predictable mapping behavior throughout your application.
diff --git a/docs/en/release-info/migration-guides/abp-9-3.md b/docs/en/release-info/migration-guides/abp-9-3.md
index 3d085eba7d..0de650501e 100644
--- a/docs/en/release-info/migration-guides/abp-9-3.md
+++ b/docs/en/release-info/migration-guides/abp-9-3.md
@@ -43,4 +43,19 @@ The main changes include:
- Added support for standalone components in ABP Suite code generation
- Updated schematics to support both module-based and standalone templates
-For detailed migration steps and best practices, please refer to our upcoming documentation and/or blog post. The migration is optional, and you can continue using the module-based approach if you prefer.
\ No newline at end of file
+For detailed migration steps and best practices, please refer to our upcoming documentation and/or blog post. The migration is optional, and you can continue using the module-based approach if you prefer.
+
+## Angular UI: Migrating Version to v20
+
+In this version, we've updated our Angular version to v20. This update brings our Angular user interface to the latest and most powerful version
+
+Key Updates:
+- Updated Angular packages (core, common, forms, router, etc.) to ~20.0.0
+- Updated @angular/cli and @angular-devkit/* to ~20.0.0
+- Updated Typescript to ~5.8.0
+- Updated RxJS to ~7.8.0
+- Updated third-party libraries to their latest versions compatible with Angular v20
+
+Breaking Changes:
+- Minimum required Node.js version is now v20.19.0
+- @angular/platform-browser no longer includes deprecated APIs like DOCUMENT token globally; ensure you're importing from @angular/common
diff --git a/docs/en/release-info/release-notes.md b/docs/en/release-info/release-notes.md
index 685b1dcb72..284995d04d 100644
--- a/docs/en/release-info/release-notes.md
+++ b/docs/en/release-info/release-notes.md
@@ -16,6 +16,7 @@ This is currently a RC (release-candidate) and you can see the detailed **[blog
* Angular UI: Standalone Package Structure
* Upgraded to `Blazorise` **v1.7.7**
* Audit Logging Module: Excel Export
+* Angular UI: Version Upgrade to **v20**
## 9.2 (2025-06-02)
diff --git a/docs/en/studio/release-notes.md b/docs/en/studio/release-notes.md
index d2db328fbf..5601fe11d0 100644
--- a/docs/en/studio/release-notes.md
+++ b/docs/en/studio/release-notes.md
@@ -2,6 +2,33 @@
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.
+## 1.1.2 (2025-07-31)
+
+* Upgraded template dependencies for ABP Framework and LeptonX. (targeting ABP `9.2.3`)
+* Configured LeptonX Lite logos in the templates.
+* Added browser tab memory feature to remember previously selected tabs.
+* Enhanced tools section with default credentials display for first-time tool usage.
+* Improved module and package loading with better error handling.
+
+## 1.1.1 (2025-07-22)
+
+* Enhanced tools section with clear cookies option.
+* Fixed language management module name display for imported modules.
+* Improved update window messaging with "Skip this version" option.
+* Fixed Docker Compose file issues in microservice template.
+* Resolved RabbitMQ tool cookie problems.
+
+## 1.1.0 (2025-07-16)
+
+* Upgraded template dependencies for ABP Framework and LeptonX. (targeting ABP `9.2.2`)
+* Enhanced UI scaling for all windows and improved user experience.
+* Added tools section in solution runner main area with basic Grafana dashboard for microservice template.
+* Improved container management during application building.
+* Enhanced background task exception handling.
+* Added public account module package reference to Blazor WebApp client.
+* Fixed tenant database context updating errors.
+* Improved optional module selection UI with better documentation integration.
+
## 1.0.2 (2025-06-24)
* Enhanced the ABP NuGet package installation experience.
diff --git a/docs/en/studio/version-mapping.md b/docs/en/studio/version-mapping.md
index 51e0de5bbd..6fe3ba95be 100644
--- a/docs/en/studio/version-mapping.md
+++ b/docs/en/studio/version-mapping.md
@@ -4,6 +4,8 @@ This document provides a general overview of the relationship between various ve
| **ABP Studio Version** | **ABP Version of Startup Template** |
|------------------------|---------------------------|
+| 1.1.2 | 9.2.3 |
+| 1.1.0 - 1.1.1 | 9.2.2 |
| 1.0.2 | 9.2.1 |
| 1.0.1 | 9.2.0 |
| 1.0.0 | 9.2.0 |
diff --git a/docs/en/tutorials/modular-crm/part-05.md b/docs/en/tutorials/modular-crm/part-05.md
index 139c4a9a8b..d2082667aa 100644
--- a/docs/en/tutorials/modular-crm/part-05.md
+++ b/docs/en/tutorials/modular-crm/part-05.md
@@ -167,7 +167,7 @@ The `ReplaceDbContext` attribute allows the use of the `ModularCrmDbContext` cla
````csharp
public class ModularCrmDbContext :
AbpDbContext,
- IProductsDbContext,
+ ICatalogDbContext,
IOrderingDbContext //NEW: IMPLEMENT THE INTERFACE
{
public DbSet Products { get; set; }
diff --git a/docs/en/tutorials/todo/layered/index.md b/docs/en/tutorials/todo/layered/index.md
index 03c06f75c9..e2279e3d57 100644
--- a/docs/en/tutorials/todo/layered/index.md
+++ b/docs/en/tutorials/todo/layered/index.md
@@ -171,13 +171,13 @@ This application has a single [entity](../../../framework/architecture/domain-dr
using System;
using Volo.Abp.Domain.Entities;
-namespace TodoApp
+namespace TodoApp;
+
+public class TodoItem : BasicAggregateRoot
{
- public class TodoItem : BasicAggregateRoot
- {
- public string Text { get; set; } = string.Empty;
- }
+ public string Text { get; set; } = string.Empty;
}
+
````
`BasicAggregateRoot` is the simplest base class to create root entities, and `Guid` is the primary key (`Id`) of the entity here.
@@ -281,15 +281,15 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
-namespace TodoApp
+namespace TodoApp;
+
+public interface ITodoAppService : IApplicationService
{
- public interface ITodoAppService : IApplicationService
- {
- Task> GetListAsync();
- Task CreateAsync(string text);
- Task DeleteAsync(Guid id);
- }
+ Task> GetListAsync();
+ Task CreateAsync(string text);
+ Task DeleteAsync(Guid id);
}
+
````
### Data Transfer Object
@@ -299,14 +299,14 @@ namespace TodoApp
````csharp
using System;
-namespace TodoApp
+namespace TodoApp;
+
+public class TodoItemDto
{
- public class TodoItemDto
- {
- public Guid Id { get; set; }
- public string Text { get; set; } = string.Empty;
- }
+ public Guid Id { get; set; }
+ public string Text { get; set; } = string.Empty;
}
+
````
This is a very simple DTO class that matches our `TodoItem` entity. We are ready to implement the `ITodoAppService`.
@@ -323,19 +323,18 @@ using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
-namespace TodoApp
+namespace TodoApp;
+
+public class TodoAppService : ApplicationService, ITodoAppService
{
- public class TodoAppService : ApplicationService, ITodoAppService
- {
- private readonly IRepository _todoItemRepository;
+ private readonly IRepository _todoItemRepository;
- public TodoAppService(IRepository todoItemRepository)
- {
- _todoItemRepository = todoItemRepository;
- }
-
- // TODO: Implement the methods here...
+ public TodoAppService(IRepository todoItemRepository)
+ {
+ _todoItemRepository = todoItemRepository;
}
+
+ // TODO: Implement the methods here...
}
````
@@ -412,8 +411,8 @@ Open the `Index.cshtml.cs` file in the `Pages` folder of the *TodoApp.Web* proje
using System.Collections.Generic;
using System.Threading.Tasks;
-namespace TodoApp.Web.Pages
-{
+namespace TodoApp.Web.Pages;
+
public class IndexModel : TodoAppPageModel
{
public List TodoItems { get; set; }
@@ -430,7 +429,7 @@ namespace TodoApp.Web.Pages
TodoItems = await _todoAppService.GetListAsync();
}
}
-}
+
````
This class uses the `ITodoAppService` to get the list of todo items and assign the `TodoItems` property. We will use it to render the todo items on the razor page.
@@ -578,34 +577,39 @@ using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Threading.Tasks;
-namespace TodoApp.Blazor.Pages
+{{if UI=="Blazor" || UI=="BlazorWebApp"}}
+namespace TodoApp.Blazor.Client.Pages;
+{{else if UI=="BlazorServer"}}
+namespace TodoApp.Blazor.Pages;
+{{else if UI=="MAUIBlazor"}}
+namespace TodoApp.MauiBlazor.Pages;
+{{end}}
+
+public partial class Index
{
- public partial class Index
- {
- [Inject]
- private ITodoAppService TodoAppService { get; set; }
+ [Inject]
+ private ITodoAppService TodoAppService { get; set; }
- private List TodoItems { get; set; } = new List();
- private string NewTodoText { get; set; } = string.Empty;
+ private List TodoItems { get; set; } = new List();
+ private string NewTodoText { get; set; } = string.Empty;
- protected override async Task OnInitializedAsync()
- {
- TodoItems = await TodoAppService.GetListAsync();
- }
-
- private async Task Create()
- {
- var result = await TodoAppService.CreateAsync(NewTodoText);
- TodoItems.Add(result);
- NewTodoText = null;
- }
+ protected override async Task OnInitializedAsync()
+ {
+ TodoItems = await TodoAppService.GetListAsync();
+ }
+
+ private async Task Create()
+ {
+ var result = await TodoAppService.CreateAsync(NewTodoText);
+ TodoItems.Add(result);
+ NewTodoText = null;
+ }
- private async Task Delete(TodoItemDto todoItem)
- {
- await TodoAppService.DeleteAsync(todoItem.Id);
- await Notify.Info("Deleted the todo item.");
- TodoItems.Remove(todoItem);
- }
+ private async Task Delete(TodoItemDto todoItem)
+ {
+ await TodoAppService.DeleteAsync(todoItem.Id);
+ await Notify.Info("Deleted the todo item.");
+ TodoItems.Remove(todoItem);
}
}
```
diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln
index edf1d8051e..efe905c475 100644
--- a/framework/Volo.Abp.sln
+++ b/framework/Volo.Abp.sln
@@ -491,6 +491,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Bunny.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Timing.Tests", "test\Volo.Abp.Timing.Tests\Volo.Abp.Timing.Tests.csproj", "{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Mapperly", "src\Volo.Abp.Mapperly\Volo.Abp.Mapperly.csproj", "{AF556046-54CD-48BC-9740-3E926DB8B510}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Mapperly.Tests", "test\Volo.Abp.Mapperly.Tests\Volo.Abp.Mapperly.Tests.csproj", "{C38926D5-C1E7-47D6-BD0B-D36BE4C19AE7}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EntityFrameworkCore.MySQL.Pomelo", "src\Volo.Abp.EntityFrameworkCore.MySQL.Pomelo\Volo.Abp.EntityFrameworkCore.MySQL.Pomelo.csproj", "{5B49FE47-A4C5-45BE-A903-8215CF5E2FAF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Searching", "src\Volo.Abp.Searching\Volo.Abp.Searching.csproj", "{C8397D52-1D31-4962-AFA6-F815EF378757}"
@@ -1469,6 +1473,14 @@ Global
{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AF556046-54CD-48BC-9740-3E926DB8B510}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AF556046-54CD-48BC-9740-3E926DB8B510}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AF556046-54CD-48BC-9740-3E926DB8B510}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AF556046-54CD-48BC-9740-3E926DB8B510}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C38926D5-C1E7-47D6-BD0B-D36BE4C19AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C38926D5-C1E7-47D6-BD0B-D36BE4C19AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C38926D5-C1E7-47D6-BD0B-D36BE4C19AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C38926D5-C1E7-47D6-BD0B-D36BE4C19AE7}.Release|Any CPU.Build.0 = Release|Any CPU
{5B49FE47-A4C5-45BE-A903-8215CF5E2FAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B49FE47-A4C5-45BE-A903-8215CF5E2FAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B49FE47-A4C5-45BE-A903-8215CF5E2FAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -1724,6 +1736,8 @@ Global
{1BBCBA72-CDB6-4882-96EE-D4CD149433A2} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{BC4BB2D6-DFD8-4190-AAC3-32C0A7A8E915} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64} = {447C8A77-E5F0-4538-8687-7383196D04EA}
+ {AF556046-54CD-48BC-9740-3E926DB8B510} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
+ {C38926D5-C1E7-47D6-BD0B-D36BE4C19AE7} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{5B49FE47-A4C5-45BE-A903-8215CF5E2FAF} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{C8397D52-1D31-4962-AFA6-F815EF378757} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
EndGlobalSection
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj
index 2e22d5194f..ced3191585 100644
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj
@@ -27,7 +27,7 @@
-
+
diff --git a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorCache.cs b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorCache.cs
index 3a3b16131d..63c2d6d082 100644
--- a/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorCache.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorCache.cs
@@ -1,7 +1,7 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
-using IdentityModel.Client;
+using Duende.IdentityModel.Client;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs
index 9d303579da..0dd2c33cb8 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs
@@ -1,6 +1,6 @@
using System;
using System.Threading.Tasks;
-using IdentityModel.Client;
+using Duende.IdentityModel.Client;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj
index a5d4f97e59..b1b3b39f6f 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj
@@ -20,7 +20,7 @@
-
+
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo.Abp.AspNetCore.Components.WebAssembly.csproj b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo.Abp.AspNetCore.Components.WebAssembly.csproj
index 084c8aad97..cfa9732d2c 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo.Abp.AspNetCore.Components.WebAssembly.csproj
+++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo.Abp.AspNetCore.Components.WebAssembly.csproj
@@ -28,7 +28,7 @@
-
+
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyAuthenticationStateProvider.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyAuthenticationStateProvider.cs
index 0018571c20..c11f6ae9a9 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyAuthenticationStateProvider.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyAuthenticationStateProvider.cs
@@ -6,7 +6,7 @@ using System.Net.Http;
using System.Security.Claims;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
-using IdentityModel.Client;
+using Duende.IdentityModel.Client;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/Views/MultiTenancyMiddlewareErrorPage.Designer.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/Views/MultiTenancyMiddlewareErrorPage.Designer.cs
index 751eec21bb..e1c2947c97 100644
--- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/Views/MultiTenancyMiddlewareErrorPage.Designer.cs
+++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/Views/MultiTenancyMiddlewareErrorPage.Designer.cs
@@ -42,10 +42,10 @@ using Volo.Abp.AspNetCore.RazorViews;
#nullable disable
WriteLiteral("\n");
WriteLiteral("\n\n \n \n ");
#nullable restore
#line 22 "MultiTenancyMiddlewareErrorPage.cshtml"
- Write(HtmlEncoder.Encode(Model.Message));
+ Write(Model.Message);
#line default
#line hidden
@@ -62,7 +62,7 @@ WriteAttributeValue("", 460, HtmlEncoder.Encode(CultureInfo.CurrentCulture.Name)
WriteLiteral("\n \n \n