diff --git a/.github/workflows/auto-pr.yml b/.github/workflows/auto-pr.yml index f353a21e37..526cfc144b 100644 --- a/.github/workflows/auto-pr.yml +++ b/.github/workflows/auto-pr.yml @@ -1,13 +1,13 @@ -name: Merge branch rel-8.3 with rel-8.2 +name: Merge branch dev with rel-8.3 on: push: branches: - - rel-8.2 + - rel-8.3 permissions: contents: read jobs: - merge-rel-8-3-with-rel-8-2: + merge-dev-with-rel-8-3: permissions: contents: write # for peter-evans/create-pull-request to create branch pull-requests: write # for peter-evans/create-pull-request to create a PR @@ -15,22 +15,22 @@ jobs: steps: - uses: actions/checkout@v2 with: - ref: rel-8.3 + ref: dev - name: Reset promotion branch run: | - git fetch origin rel-8.2:rel-8.2 - git reset --hard rel-8.2 + git fetch origin rel-8.3:rel-8.3 + git reset --hard rel-8.3 - name: Create Pull Request uses: peter-evans/create-pull-request@v3 with: - branch: auto-merge/rel-8-2/${{github.run_number}} - title: Merge branch rel-8.3 with rel-8.2 - body: This PR generated automatically to merge rel-8.3 with rel-8.2. Please review the changed files before merging to prevent any errors that may occur. + branch: auto-merge/rel-8-3/${{github.run_number}} + title: Merge branch dev with rel-8.3 + body: This PR generated automatically to merge dev with rel-8.3. Please review the changed files before merging to prevent any errors that may occur. reviewers: maliming token: ${{ github.token }} - name: Merge Pull Request env: GH_TOKEN: ${{ secrets.BOT_SECRET }} run: | - gh pr review auto-merge/rel-8-2/${{github.run_number}} --approve - gh pr merge auto-merge/rel-8-2/${{github.run_number}} --merge --auto --delete-branch + gh pr review auto-merge/rel-8-3/${{github.run_number}} --approve + gh pr merge auto-merge/rel-8-3/${{github.run_number}} --merge --auto --delete-branch \ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props index 472fb034a5..93cbd3cfdf 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -49,7 +49,7 @@ - + @@ -61,7 +61,6 @@ - diff --git a/LICENSE.md b/LICENSE.md index 65c5ca88a6..5da3c16f4c 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,165 +1,89 @@ GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. +Copyright (C) 2007 Free Software Foundation, Inc. +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. +This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public. +The license is supplemented by the additional permissions listed below. - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - 0. Additional Definitions. - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. + **0. Additional Definitions.** + +As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. + +"The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. + +An "Application" is any work that makes use of an interface provided by the Library but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. + +A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". + +The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application and not on the Linked Version. + +The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. + + + + **1. Exception to Section 3 of the GNU GPL.** + +You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. + + + + **2. Conveying Modified Versions.** + +If you modify a copy of the Library and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: + + **a)** under this License, provided that you make a good-faith effort to ensure that, in the event an Application does not supply the + function or data, the facility still operates and performs whatever part of its purpose remains meaningful, or + + **b)** under the GNU GPL, with none of the additional permissions of this License is applicable to that copy. + + + + **3. Object Code Incorporating Material from Library Header Files.** + +The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such an object code under terms of your choice, provided that if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: + + **a)** Give prominent notice with each copy of the object code that the Library is used in it, and the Library and its use are covered by this License. + + **b)** Accompany the object code with a copy of the GNU GPL and this license document. + + + + **4. Combined Works.** + +You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: + + **a)** Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. + + **b)** Accompany the Combined Work with a copy of the GNU GPL and this license document. + + **c)** For a Combined Work that displays copyright notices during execution, including the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. + + **d)** Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this License and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. + 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. + + **e)** Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying the Corresponding Source.) + - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) 5. Combined Libraries. - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. +You may place library facilities that are work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License and convey such a combined library under the terms of your choice if you do both of the following: + + **a)** Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. + + **b)** Give prominent notice with the combined library that part of it is a work based on the Library and explains where to find the accompanying uncombined form of the same work. + + + + **6. Revised Versions of the GNU Lesser General Public License.** + +The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received, it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. diff --git a/README.md b/README.md index ccc31da4b5..dd953a6431 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,18 @@ # ABP Framework -![build and test](https://img.shields.io/github/actions/workflow/status/abpframework/abp/build-and-test.yml?branch=dev&style=flat-square) -[![codecov](https://codecov.io/gh/abpframework/abp/branch/dev/graph/badge.svg?token=jUKLCxa6HF)](https://codecov.io/gh/abpframework/abp) -[![NuGet](https://img.shields.io/nuget/v/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) -[![NuGet (with prereleases)](https://img.shields.io/nuget/vpre/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) -[![MyGet (nightly builds)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds) -[![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) -[![Code of Conduct](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](https://github.com/abpframework/abp/blob/dev/CODE_OF_CONDUCT.md) -[![CLA Signed](https://cla-assistant.io/readme/badge/abpframework/abp)](https://cla-assistant.io/abpframework/abp) -[![ABP Discord server](https://img.shields.io/discord/951497912645476422?label=Discord)](https://discord.gg/abp) - -ABP Framework is a complete **infrastructure** based on **ASP.NET Core** to create **modern web applications** and **APIs** by following the software development **best practices** and the **latest technologies**. Check out https://abp.io +![build and test](https://img.shields.io/github/actions/workflow/status/abpframework/abp/build-and-test.yml?branch=dev&style=flat-square) 🔹 [![codecov](https://codecov.io/gh/abpframework/abp/branch/dev/graph/badge.svg?token=jUKLCxa6HF)](https://codecov.io/gh/abpframework/abp) 🔹 [![NuGet](https://img.shields.io/nuget/v/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) 🔹 [![NuGet (with prereleases)](https://img.shields.io/nuget/vpre/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) 🔹 [![MyGet (nightly builds)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds) 🔹 +[![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) 🔹 [![Code of Conduct](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](https://github.com/abpframework/abp/blob/dev/CODE_OF_CONDUCT.md) 🔹 [![CLA Signed](https://cla-assistant.io/readme/badge/abpframework/abp)](https://cla-assistant.io/abpframework/abp) 🔹 [![Discord Shield](https://discord.com/api/guilds/951497912645476422/widget.png?style=shield)](https://discord.gg/abp) + +ABP Framework is a complete **infrastructure** based on **ASP.NET Core** that creates **modern web applications** and **APIs** by following the software development **best practices** and the **latest technologies**. + +[![ABP Platform](https://github.com/abpframework/abp/assets/9526587/47531496-4088-406d-9c69-63cb0ffec2ba)](https://abp.io) + ## Getting Started -- [Quick Start](https://docs.abp.io/en/abp/latest/Tutorials/Todo/Index) is a single-part, quick-start tutorial to build a simple application with the ABP Framework. Start with this tutorial if you want to quickly understand how ABP works. -- [Getting Started guide](https://docs.abp.io/en/abp/latest/Getting-Started) can be used to create and run ABP based solutions with different options and details. -- [Web Application Development Tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1) is a complete tutorial to develop a full stack web application with all aspects of a real-life solution. +- [Quick Start](https://docs.abp.io/en/abp/latest/Tutorials/Todo/Index) is a single-part, quick-start tutorial to build a simple application with the ABP Framework. Start with this tutorial if you want to understand how ABP works quickly. +- [Getting Started guide](https://docs.abp.io/en/abp/latest/Getting-Started) can be used to create and run ABP-based solutions with different options and details. +- [Web Application Development Tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1) is a complete tutorial on developing a full-stack web application with all aspects of a real-life solution. ### Quick Start @@ -34,28 +30,26 @@ Create a new solution: > See the [CLI documentation](https://docs.abp.io/en/abp/latest/CLI) for all available options. + + ### UI Framework Options + + ### Database Provider Options -## The Book: Mastering ABP Framework -Written by the creator of ABP Framework, this book will help you to gain a complete understanding of the ABP Framework and modern web application development techniques. - -* [Buy on Amazon](https://www.amazon.com/gp/product/B097Z2DM8Q) -* [Buy on Packt Publishing](https://www.packtpub.com/product/mastering-abp-framework/9781801079242) -* [More details about the book](https://abp.io/books/mastering-abp-framework) - -![book-mastering-abp-framework](docs/en/images/book-mastering-abp-framework.png) ## What ABP Provides? ABP provides a **full stack developer experience**. + + ### Architecture @@ -64,30 +58,48 @@ ABP offers a complete, **modular** and **layered** software architecture based o ABP Framework is suitable for **[microservice solutions](https://docs.abp.io/en/abp/latest/Microservice-Architecture)** as well as monolithic applications. + + ### Infrastructure -There are a lot of features provided by the ABP Framework to achieve real world scenarios easier, like [Event Bus](https://docs.abp.io/en/abp/latest/Event-Bus), [Background Job System](https://docs.abp.io/en/abp/latest/Background-Jobs), [Audit Logging](https://docs.abp.io/en/abp/latest/Audit-Logging), [BLOB Storing](https://docs.abp.io/en/abp/latest/Blob-Storing), [Data Seeding](https://docs.abp.io/en/abp/latest/Data-Seeding), [Data Filtering](https://docs.abp.io/en/abp/latest/Data-Filtering), etc. +There are a lot of features provided by the ABP Framework to achieve real-world scenarios easier, like [Event Bus](https://docs.abp.io/en/abp/latest/Event-Bus), [Background Job System](https://docs.abp.io/en/abp/latest/Background-Jobs), [Audit Logging](https://docs.abp.io/en/abp/latest/Audit-Logging), [BLOB Storing](https://docs.abp.io/en/abp/latest/Blob-Storing), [Data Seeding](https://docs.abp.io/en/abp/latest/Data-Seeding), [Data Filtering](https://docs.abp.io/en/abp/latest/Data-Filtering), etc. + + + +### Cross-Cutting Concerns + +ABP also simplifies (and even automates wherever possible) cross-cutting concerns and common non-functional requirements like [Exception Handling](https://docs.abp.io/en/abp/latest/Exception-Handling), [Validation](https://docs.abp.io/en/abp/latest/Validation), [Authorization](https://docs.abp.io/en/abp/latest/Authorization), [Localization](https://docs.abp.io/en/abp/latest/Localization), [Caching](https://docs.abp.io/en/abp/latest/Caching), [Dependency Injection](https://docs.abp.io/en/abp/latest/Dependency-Injection), [Setting Management](https://docs.abp.io/en/abp/latest/Settings), etc. -### Cross Cutting Concerns -ABP also simplifies (and even automates wherever possible) cross cutting concerns and common non-functional requirements like [Exception Handling](https://docs.abp.io/en/abp/latest/Exception-Handling), [Validation](https://docs.abp.io/en/abp/latest/Validation), [Authorization](https://docs.abp.io/en/abp/latest/Authorization), [Localization](https://docs.abp.io/en/abp/latest/Localization), [Caching](https://docs.abp.io/en/abp/latest/Caching), [Dependency Injection](https://docs.abp.io/en/abp/latest/Dependency-Injection), [Setting Management](https://docs.abp.io/en/abp/latest/Settings), etc. ### Application Modules ABP is a modular framework and the Application Modules provide **pre-built application functionalities**; - [**Account**](https://docs.abp.io/en/abp/latest/Modules/Account): Provides UI for the account management and allows user to login/register to the application. -- **[Identity](https://docs.abp.io/en/abp/latest/Modules/Identity)**: Manages organization units, roles, users and their permissions, based on the Microsoft Identity library. +- **[Identity](https://docs.abp.io/en/abp/latest/Modules/Identity)**: Manages organization units, roles, users and their permissions based on the Microsoft Identity library. - [**OpenIddict**](https://docs.abp.io/en/abp/latest/Modules/OpenIddict): Integrates to OpenIddict. - [**Tenant Management**](https://docs.abp.io/en/abp/latest/Modules/Tenant-Management): Manages tenants for a [multi-tenant](https://docs.abp.io/en/abp/latest/Multi-Tenancy) (SaaS) application. See the [Application Modules](https://docs.abp.io/en/abp/latest/Modules/Index) document for all pre-built modules. + + ### Startup Templates The [Startup templates](https://docs.abp.io/en/abp/latest/Startup-Templates/Index) are pre-built Visual Studio solution templates. You can create your own solution based on these templates to **immediately start your development**. -## ABP Community + + +## Mastering ABP Framework Book + +This book will help you to gain a complete understanding of the ABP Framework and modern web application development techniques. It is written by the creator and team lead of the ABP Framework. You can buy from [Amazon](https://www.amazon.com/gp/product/B097Z2DM8Q) or [Packt Publishing](https://www.packtpub.com/product/mastering-abp-framework/9781801079242). Find further info about the book at [abp.io/books/mastering-abp-framework](https://abp.io/books/mastering-abp-framework). + +![book-mastering-abp-framework](docs/en/images/book-mastering-abp-framework.png) + + + +## The Community ### ABP Community Web Site @@ -103,28 +115,31 @@ See the [sample projects](https://docs.abp.io/en/abp/latest/Samples/Index) built ### Want to Contribute? -ABP is a community-driven open source project. See [the contribution guide](https://docs.abp.io/en/abp/latest/Contribution/Index) if you want to be a part of this project. +ABP is a community-driven open-source project. See [the contribution guide](https://docs.abp.io/en/abp/latest/Contribution/Index) if you want to participate in this project. + + ## Official Links -* Main Web Site - * Get Started - * Features -* Documentation -* Samples -* Blog -* Community -* Stack overflow -* Twitter +* [Home Website](https://abp.io) + * [Get Started](https://abp.io/get-started) + * [Features](https://abp.io/features) +* [Documents](https://docs.abp.io/) +* [Samples](https://docs.abp.io/en/abp/latest/Samples/Index) +* [Blog](https://blog.abp.io/) +* [Community](https://community.abp.io/) +* [Stackoverflow](https://stackoverflow.com/questions/tagged/abp) +* [Twitter](https://twitter.com/abpframework) + + + +## Support ABP -## Support the ABP Framework +GitHub repository stars are an important indicator of popularity and the size of the community. If you like ABP Framework, support us by clicking the star :star: on the repository. -Love ABP Framework? **Please give a star** to this repository :star: -## Discord Channel -You can use this link to join the ABP Community Discord Server: https://discord.gg/abp +## Discord Server -## ABP Commercial +We have a Discord server where you can chat with other ABP users. Share your ideas, report technical issues, showcase your creations, share the tips that worked for you and catch up with the latest news and announcements about ABP Framework. Join 👉 https://discord.gg/abp. -See also [ABP Commercial](https://commercial.abp.io/) if you are looking for pre-built application modules, professional themes, code generation tooling and premium support for the ABP Framework. diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/en.json index 8470709c99..44ab5b3e31 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/en.json @@ -12,6 +12,7 @@ "CommunityWebSite": "ABP community website", "ManageAccount": "My Account | ABP.IO", "ManageYourProfile": "Manage your profile", - "ReturnToApplication": "Return to application" + "ReturnToApplication": "Return to application", + "IdentityUserNotAvailable:Deleted": "This email address is not available. Reason: Already deleted." } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json index 5be67a44b1..b8a92f19a4 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json @@ -816,6 +816,7 @@ "ErrorExceptionMessage": "حدث خطأ أثناء معالجة طلبك", "WatchTakeCodeGeneration": "شاهد فيديو \"استكشاف إمكانات إنشاء الأكواد البرمجية: ABP Suite\"!", "ExtendNow": "تمديد / تجديد", - "RegisterDemo": "يسجل" + "RegisterDemo": "يسجل", + "AbpStudio_ComingSoon": "إذا كنت ترغب في اختبار ABP Studio قبل أي شخص آخر، يمكنك أن تصبح أحد مختبري النسخة التجريبية" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/cs.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/cs.json index c047dd7b65..e94c4108aa 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/cs.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/cs.json @@ -431,6 +431,7 @@ "ErrorExceptionMessage": "Při zpracování vašeho požadavku nastala chyba", "WatchTakeCodeGeneration": "Podívejte se na video „Prozkoumejte potenciál generování kódu: ABP Suite“!", "ExtendNow": "Prodloužit / Obnovit", - "RegisterDemo": "Registrovat" + "RegisterDemo": "Registrovat", + "AbpStudio_ComingSoon": "Pokud chcete ABP Studio otestovat dříve než kdokoli jiný, staňte se BETA testerem" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/de.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/de.json index 1663811cef..5d944a25c7 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/de.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/de.json @@ -411,6 +411,7 @@ "SendUsEmail": "Senden Sie uns eine E-Mail", "ErrorExceptionMessage": "Während Ihrer Anfrage ist ein Fehler aufgetreten", "WatchTakeCodeGeneration": "Sehen Sie sich das Video „Entdecken Sie das Potenzial der Codegenerierung: ABP Suite“ an!", - "ExtendNow": "Verlängern / Erneuern" + "ExtendNow": "Verlängern / Erneuern", + "AbpStudio_ComingSoon": "Wenn Sie ABP Studio vor allen anderen testen möchten, werden Sie BETA-Tester" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json index 3fc2d697ee..071f025a81 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -916,7 +916,7 @@ "AbpStudio_Description": "ABP Studio is still under development. You can fill out the form below to be one of the first users.", "AbpStudio_Description1": "ABP Studio is a cross-platform desktop application for ABP developers.", "AbpStudio_Description2": "It is well integrated to the ABP Framework and aims to provide a comfortable development environment for you by automating things, providing insights about your solution, making develop, run and deploy your solutions much easier.", - "AbpStudio_ComingSoon": "Coming Soon Planned beta release date: Q4 of 2023.", + "AbpStudio_ComingSoon": "If you want to test ABP Studio before anyone else, become a BETA tester", "AbpStudio_PlannedPreviewDate": "Planned preview release date: Q4 of 2023.", "BetaRequest": "Beta Request", "CreateNewSolutions": "Create New Solutions", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/es.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/es.json index 3f54749131..67fa883440 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/es.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/es.json @@ -411,6 +411,7 @@ "SendUsEmail": "Envíanos un correo electrónico", "ErrorExceptionMessage": "Se produjo un error al procesar su solicitud.", "WatchTakeCodeGeneration": "¡Mire el vídeo \"Explore el potencial de la generación de código: ABP Suite\"!", - "ExtendNow": "Ampliar / Renovar" + "ExtendNow": "Ampliar / Renovar", + "AbpStudio_ComingSoon": "Si quieres probar ABP Studio antes que nadie, conviértete en tester BETA" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json index f367f63c30..57d76027b2 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json @@ -852,6 +852,7 @@ "ErrorExceptionMessage": "Virhe pyynnön käsittelyn yhteydessä", "WatchTakeCodeGeneration": "Katso \"Tutki koodin luomisen potentiaalia: ABP Suite\" -video!", "ExtendNow": "Laajenna / Uusi", - "RegisterDemo": "Rekisteröidy" + "RegisterDemo": "Rekisteröidy", + "AbpStudio_ComingSoon": "Jos haluat testata ABP Studiota ennen muita, ryhdy BETA-testaajaksi" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json index b044837aac..7bc6e12e95 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json @@ -431,6 +431,7 @@ "ErrorExceptionMessage": "Une erreur s'est produite lors du traitement de votre demande", "WatchTakeCodeGeneration": "Regardez la vidéo « Explorez le potentiel de la génération de code : ABP Suite » !", "ExtendNow": "Prolonger / Renouveler", - "RegisterDemo": "Registre" + "RegisterDemo": "Registre", + "AbpStudio_ComingSoon": "Si vous souhaitez tester ABP Studio avant tout le monde, devenez BETA testeur" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json index 958e3d533f..9d202f3d5d 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json @@ -430,6 +430,7 @@ "ErrorExceptionMessage": "आपका अनुरोध संसाधित करते समय एक त्रुटि पाई गई", "WatchTakeCodeGeneration": "\"कोड जनरेशन की क्षमता का अन्वेषण करें: एबीपी सुइट\" वीडियो देखें!", "ExtendNow": "विस्तार/नवीनीकरण", - "RegisterDemo": "पंजीकरण करवाना" + "RegisterDemo": "पंजीकरण करवाना", + "AbpStudio_ComingSoon": "यदि आप किसी और से पहले एबीपी स्टूडियो का परीक्षण करना चाहते हैं, तो बीटा परीक्षक बनें" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hr.json index 6f8c1930cf..b51e3b94ee 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hr.json @@ -915,7 +915,6 @@ "AbpStudio_Description": "ABP Studio je još uvijek u razvoju. Možete ispuniti obrazac ispod i biti jedan od prvih korisnika.", "AbpStudio_Description1": "ABP Studio je stolna aplikacija za više platformi za ABP programere.", "AbpStudio_Description2": "Dobro je integriran u ABP Framework i ima za cilj pružiti vam ugodno razvojno okruženje automatiziranjem stvari, pružanjem uvida u vaše rješenje, čineći razvoj, pokretanje i implementaciju vaših rješenja puno lakšim.", - "AbpStudio_ComingSoon": "Uskoro. Planirani datum izdavanja beta verzije: 4. tromjesečje 2023.", "AbpStudio_PlannedPreviewDate": "Planirani datum izdavanja pregleda: 4. kvartal 2023.", "BetaRequest": "Zahtjev za beta verziju", "CreateNewSolutions": "Stvorite nova rješenja", @@ -1107,6 +1106,7 @@ "SendUsEmail": "Pošaljite nam e-mail", "ErrorExceptionMessage": "Pojavila se greška prilikom obrade Vašeg zahtjeva", "WatchTakeCodeGeneration": "Pogledajte video \"Istražite potencijal generiranja koda: ABP Suite\"!", - "ExtendNow": "Produži / obnovi" + "ExtendNow": "Produži / obnovi", + "AbpStudio_ComingSoon": "Ako želite testirati ABP Studio prije svih ostalih, postanite BETA tester" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json index 79889c0d1b..ac1f74eafc 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hu.json @@ -777,6 +777,7 @@ "SendUsEmail": "Küldjön nekünk e-mailt", "ErrorExceptionMessage": "Hiba történt a kérése feldolgozása során", "WatchTakeCodeGeneration": "Nézze meg a \"Fedezze fel a kódgenerálás lehetőségét: ABP Suite\" videót!", - "ExtendNow": "Bővítés / Megújítás" + "ExtendNow": "Bővítés / Megújítás", + "AbpStudio_ComingSoon": "Ha bárki más előtt szeretné tesztelni az ABP Studio-t, legyen BÉTA tesztelő" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/is.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/is.json index d6744a9603..475ef5f98f 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/is.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/is.json @@ -408,6 +408,7 @@ "SendUsEmail": "Sendu okkur tölvupóst", "ErrorExceptionMessage": "Villa kom upp við úrvinnslu beiðni þinnar", "WatchTakeCodeGeneration": "Horfðu á \"Kannaðu möguleika kóðaframleiðslu: ABP Suite\" myndbandið!", - "ExtendNow": "Framlengja / endurnýja" + "ExtendNow": "Framlengja / endurnýja", + "AbpStudio_ComingSoon": "Ef þú vilt prófa ABP Studio á undan öllum öðrum skaltu gerast BETA prófari" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json index addb4b54e1..c668db7414 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json @@ -430,6 +430,7 @@ "ErrorExceptionMessage": "Si è verificato un errore durante l'elaborazione della richiesta", "WatchTakeCodeGeneration": "Guarda il video \"Esplora il potenziale della generazione di codice: ABP Suite\"!", "ExtendNow": "Estendi/Rinnova", - "RegisterDemo": "Registrati" + "RegisterDemo": "Registrati", + "AbpStudio_ComingSoon": "Se vuoi provare ABP Studio prima di chiunque altro, diventa un BETA tester" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/nl.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/nl.json index 298e59d573..d99901743e 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/nl.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/nl.json @@ -408,6 +408,7 @@ "SendUsEmail": "Stuur ons een e-mail", "ErrorExceptionMessage": "Er is een fout opgetreden bij het verwerken van uw verzoek", "WatchTakeCodeGeneration": "Bekijk de video 'Ontdek het potentieel van codegeneratie: ABP Suite'!", - "ExtendNow": "Verlengen / Verlengen" + "ExtendNow": "Verlengen / Verlengen", + "AbpStudio_ComingSoon": "Als u ABP Studio als eerste wilt testen, wordt dan BETA-tester" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pl-PL.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pl-PL.json index 757fc93ec1..1b6f200b66 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pl-PL.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pl-PL.json @@ -409,6 +409,7 @@ "ErrorExceptionMessage": "Podczas przetwarzania żądania wystąpił błąd", "WatchTakeCodeGeneration": "Obejrzyj film „Odkryj potencjał generowania kodu: pakiet ABP”!", "ExtendNow": "Przedłuż/Odnów", - "RegisterDemo": "Rejestr" + "RegisterDemo": "Rejestr", + "AbpStudio_ComingSoon": "Jeśli chcesz przetestować ABP Studio zanim ktokolwiek inny, zostań testerem BETA" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json index fe72c04d15..43d57e4184 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/pt-BR.json @@ -431,6 +431,7 @@ "SendUsEmail": "Envie-nos um e-mail", "ErrorExceptionMessage": "Um erro ocorreu durante o processamento do seu pedido", "WatchTakeCodeGeneration": "Assista ao vídeo \"Explore o potencial de geração de código: ABP Suite\"!", - "ExtendNow": "Estender/Renovar" + "ExtendNow": "Estender/Renovar", + "AbpStudio_ComingSoon": "Se você quiser testar o ABP Studio antes de todo mundo, torne-se um testador BETA" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json index 6bb638c703..3e66a513d6 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json @@ -408,6 +408,7 @@ "SendUsEmail": "Trimite-ne e-mail", "ErrorExceptionMessage": "A apărut o eroare în timpul procesării cererii dumneavoastră", "WatchTakeCodeGeneration": "Urmărește videoclipul „Explorați potențialul generării codului: ABP Suite”!", - "ExtendNow": "Extinde/Reînnoiește" + "ExtendNow": "Extinde/Reînnoiește", + "AbpStudio_ComingSoon": "Dacă doriți să testați ABP Studio înaintea oricui, deveniți un tester BETA" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json index 26f1c79704..6abcbcf1bf 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json @@ -427,6 +427,7 @@ "SendUsEmail": "Pošlite nám e-mail", "ErrorExceptionMessage": "Nastala chyba pri spracovaní vašej žiadosti", "WatchTakeCodeGeneration": "Pozrite si video „Preskúmajte potenciál generovania kódu: ABP Suite“!", - "ExtendNow": "Predĺžiť / obnoviť" + "ExtendNow": "Predĺžiť / obnoviť", + "AbpStudio_ComingSoon": "Ak chcete otestovať ABP Studio skôr ako ktokoľvek iný, staňte sa BETA testerom" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sl.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sl.json index 0d25e94113..880006579c 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sl.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sl.json @@ -409,6 +409,7 @@ "ErrorExceptionMessage": "Pri obdelavi vaše zahteve je prišlo do napake", "WatchTakeCodeGeneration": "Oglejte si video »Raziščite potencial generiranja kode: zbirka ABP«!", "ExtendNow": "Podaljšaj / obnovi", - "RegisterDemo": "Registrirajte se" + "RegisterDemo": "Registrirajte se", + "AbpStudio_ComingSoon": "Če želite preizkusiti ABP Studio pred vsemi drugimi, postanite BETA tester" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json index 9282239bee..22ef2ddc0f 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json @@ -1058,7 +1058,6 @@ "AbpStudio_Description": "ABP Studio hala geliştirme aşamasında. İlk kullanıcılardan biri olmak için aşağıdaki formu doldurabilirsiniz.", "AbpStudio_Description1": "ABP Studio, ABP geliştiricileri için çok platformlu masaüstü uygulamasıdır.", "AbpStudio_Description2": "ABP Studio, ABP Framework'e iyi entegre edilmiştir ve sizin için işleri otomatikleştirerek, projeniz hakkında bilgi sağlayarak, projelerinizi geliştirmeyi, çalıştırmayı ve dağıtımını çok daha kolay hale getirmeyi amaçlamaktadır.", - "AbpStudio_ComingSoon": "Yakında Planlanan beta sürüm tarihi: 2023'ün 4. çeyreği.", "AbpStudio_PlannedPreviewDate": "Planlanan beta sürüm tarihi: 2023'ün 4. çeyreği.", "BetaRequest": "Beta Talebi", "CreateNewSolutions": "Yeni Projeler Oluştur", @@ -1140,6 +1139,7 @@ "RemoveBasket": "Sepetten kaldır", "TrainingPack": "Eğitim paketi", "TrainingPackDiscount": "Eğitim paketi indirimi", - "LinkExpiredMessage": "Ödeme bağlantısının süresi doldu! Bağlantıyı güncellemek için sales@volosoft.com adresinden bizimle iletişime geçin veya iletişim sayfasına gitmek için buraya tıklayın." + "LinkExpiredMessage": "Ödeme bağlantısının süresi doldu! Bağlantıyı güncellemek için sales@volosoft.com adresinden bizimle iletişime geçin veya iletişim sayfasına gitmek için buraya tıklayın.", + "AbpStudio_ComingSoon": "ABP Studio'yu herkesten önce test etmek istiyorsanız BETA test kullanıcısı olun" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/vi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/vi.json index 6834f26f24..a944e8e193 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/vi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/vi.json @@ -408,6 +408,7 @@ "SendUsEmail": "Gửi email cho chúng tôi", "ErrorExceptionMessage": "Đã xảy ra lỗi trong khi xử lý yêu cầu của bạn", "WatchTakeCodeGeneration": "Xem video \"Khám phá tiềm năng tạo mã: ABP Suite\"!", - "ExtendNow": "Gia hạn/Gia hạn" + "ExtendNow": "Gia hạn/Gia hạn", + "AbpStudio_ComingSoon": "Nếu bạn muốn thử nghiệm ABP Studio trước bất kỳ ai khác, hãy trở thành người thử nghiệm BETA" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json index 57caf8322d..a6af2260cb 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json @@ -915,7 +915,6 @@ "AbpStudio_Description": "ABP Studio 仍在开发中。您可以填写下面的表单,成为首批用户之一。", "AbpStudio_Description1": "ABP Studio 是专为 ABP 开发人员设计的跨平台桌面应用程序。", "AbpStudio_Description2": "它与 ABP 框架集成得很好,旨在通过自动化、提供有关解决方案的见解,为您提供舒适的开发环境,使开发、运行部署解决方案变得更加容易。", - "AbpStudio_ComingSoon": "即将发布 计划测试版发布日期:计划测试版发布日期:2023年第四季度。", "AbpStudio_PlannedPreviewDate": "计划预览版发布日期:2023 年第四季度。", "BetaRequest": "测试版请求", "CreateNewSolutions": "创建新的解决方案", @@ -1110,6 +1109,7 @@ "ErrorExceptionMessage": "处理您的请求时发生错误", "WatchTakeCodeGeneration": "观看“探索代码生成的潜力:ABP Suite”视频!", "PreBuiltApplicationModulesTitle": "预构建应用程序 模块", - "RegisterDemo": "登记" + "RegisterDemo": "登记", + "AbpStudio_ComingSoon": "如果您想先于其他人测试 ABP Studio,请成为 BETA 测试员" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json index e9ee4ef230..ae5ba6708c 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json @@ -897,7 +897,6 @@ "AbpStudio_Description": "ABP Studio 仍在開發中。您可以填寫下面的表单,成為第一批使用者之一。", "AbpStudio_Description1": "ABP Studio 是一款針對 ABP 開發人員的跨平台桌面應用程式。", "AbpStudio_Description2": "它與 ABP 框架很好地集成,旨在透過自動化為您提供一個舒適的開發環境,提供有關您的解決方案的見解,使開發、運行部署您的解決方案變得更加容易。", - "AbpStudio_ComingSoon": "即將推出計劃測試版發布日期:2023 年第四季。", "AbpStudio_PlannedPreviewDate": "計畫預覽版發布日期:2023 年第四季。", "BetaRequest": "測試版請求", "CreateNewSolutions": "建立新的解決方案", @@ -1100,6 +1099,7 @@ "WatchTakeCodeGeneration": "观看“探索代码生成的潜力:ABP Suite”视频!", "ExtendNow": "延长 / 续订", "PreBuiltApplicationModulesTitle": "预构建应用程序 模块", - "RegisterDemo": "登记" + "RegisterDemo": "登记", + "AbpStudio_ComingSoon": "如果您想先于其他人测试 ABP Studio,请成为 BETA 测试员" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json index 2b6f5db40c..fef40ce7c1 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json @@ -259,6 +259,9 @@ "MarkdownSupported": "Markdown أيد.", "Preview": "معاينة", "VisitVideoCourseDescription": "إذا كنت ترغب في تعلم أساسيات إطار عمل برنامج ABP، فاطلع على دورات الفيديو الخاصة ببرنامج ABP Essentials.", - "VisitPage": "زر الصفحة" + "VisitPage": "زر الصفحة", + "ConfirmEmailForPost": "لتتمكن من النشر، تحتاج إلى تأكيد بريدك الإلكتروني. انتقل إلى account.abp.io/Account/Manage وتحقق من بريدك الإلكتروني في علامة التبويب \"المعلومات الشخصية\".", + "DailyPostCreateLimitation": "لقد وصلت إلى الحد الأقصى اليومي لإنشاء المنشورات. يمكنك إنشاء مشاركة جديدة في {0}.", + "YourAccountDisabled": "تم تعطيل حساب المستخدم الخاص بك!" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/cs.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/cs.json index 35119a1408..86910d5557 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/cs.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/cs.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown podporováno.", "Preview": "Náhled", "VisitPage": "Navštivte stránku", - "VisitVideoCourseDescription": "Pokud se chcete naučit základy rámce ABP, podívejte se na videokurzy ABP Essentials." + "VisitVideoCourseDescription": "Pokud se chcete naučit základy rámce ABP, podívejte se na videokurzy ABP Essentials.", + "ConfirmEmailForPost": "Abyste mohli přidávat příspěvky, musíte potvrdit svůj e-mail. Přejděte na stránku account.abp.io/Account/Manage a ověřte svůj e-mail na kartě Osobní údaje.", + "DailyPostCreateLimitation": "Dosáhli jste denního limitu pro vytváření příspěvků. Nový příspěvek můžete vytvořit v {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de.json index d26c081de5..99c60d5199 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/de.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown unterstützt.", "Preview": "Vorschau", "VisitPage": "Seite besuchen", - "VisitVideoCourseDescription": "Wenn Sie die Grundlagen des ABP Framework erlernen möchten, schauen Sie sich die ABP Essentials-Videokurse an." + "VisitVideoCourseDescription": "Wenn Sie die Grundlagen des ABP Framework erlernen möchten, schauen Sie sich die ABP Essentials-Videokurse an.", + "ConfirmEmailForPost": "Um Beiträge verfassen zu können, müssen Sie Ihre E-Mail-Adresse bestätigen. Gehen Sie zu account.abp.io/Account/Manage und bestätigen Sie Ihre E-Mail-Adresse auf der Registerkarte „Persönliche Daten“.", + "DailyPostCreateLimitation": "Sie haben das tägliche Limit für die Erstellung von Beiträgen erreicht. Sie können in {0} einen neuen Beitrag erstellen." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json index 347b18ce4b..dc59234777 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json @@ -59,7 +59,7 @@ "MilestoneErrorMessage": "Couldn't get the current milestone details from Github.", "QuestionItemErrorMessage": "Couldn't get the latest question details from Stackoverflow.", "Oops": "Oops!", - "CreatePostSuccessMessage": "The Post has been successfully submitted. It will be published once it has been reviewed by the site admin.", + "CreatePostSuccessMessage": "Your post has been successfully submitted. It will be published after review by the site administrator.", "ChooseCoverImage": "Choose a cover image...", "CoverImage": "Cover Image", "ShareYourExperiencesWithTheABPFramework": "Share your experiences with the ABP Framework!", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json index 80fbc8539b..78231bb1af 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json @@ -16,7 +16,7 @@ "Title": "Title", "CreationTime": "Creation time", "Save": "Save", - "SameUrlAlreadyExist": "Same url already exists if you want to add this post, you should change the url!", + "SameUrlAlreadyExist": "Same URL already exists! You must change the URL!", "UrlIsNotValid": "Url is not valid.", "UrlNotFound": "Url not found.", "UrlContentNotFound": "Url content not found.", @@ -33,7 +33,7 @@ "FeatureRequest": "Feature Request", "CreatePostTitleInfo": "Title of the post to be shown on the post list.", "CreatePostSummaryInfo": "A short summary of the post to be shown on the post list. Maximum length: {0}", - "CreatePostCoverInfo": "For creating an effective post, add a cover photo. Upload 16:9 aspect ratio pictures for the best view.
Maximum file size: 1MB.", + "CreatePostCoverInfo": "To create an effective post, add a cover photo. Upload 16:9 aspect ratio pictures for the best view.
Maximum file size is 1MB.", "ThisExtensionIsNotAllowed": "This extension is not allowed.", "TheFileIsTooLarge": "The file is too large.", "GoToThePost": "Go to the Post", @@ -56,7 +56,7 @@ "MilestoneErrorMessage": "Could not get the current milestone details from Github.", "QuestionItemErrorMessage": "Could not get the latest question details from Stackoverflow.", "Oops": "Oops!", - "CreatePostSuccessMessage": "The Post has been successfully submitted. It will be published after a review from the site admin.", + "CreatePostSuccessMessage": "Your post has been successfully submitted. It will be published after review by the site administrator.", "Browse": "Browse", "CoverImage": "Cover Image", "ShareYourExperiencesWithTheABPFramework": "Share your experiences with the ABP Framework!", @@ -125,7 +125,7 @@ "YoutubeVideoSubmitStepTwo": "2. Submit the video URL using the form.", "YoutubeVideoSubmitStepThree": "3. Visitors will be able to watch your video content directly on this website.", "ExternalContent": "External Content", - "ExternalContentSubmitStepOne": "1. Create a content on any public platform (Medium, your own blog or anywhere you like).", + "ExternalContentSubmitStepOne": "1. Create content on any public platform (Medium, your own blog or anywhere you like).", "ExternalContentSubmitStepTwo": "2. Submit your content URL using the form.", "ExternalContentSubmitStepThree": "3. Visitors are redirected to the content on the original website.", "ChooseYourContentType": "Please choose the way you want to add your content.", @@ -135,12 +135,12 @@ "GitHubUserNameValidationMessage": "Your Github username can not include whitespace, please make sure your Github username is correct.", "PersonalSiteUrlValidationMessage": "Your personal site URL can not include whitespace, please make sure your personal site URL is correct.", "TwitterUserNameValidationMessage": "Your Twitter username can not include whitespace, please make sure your Twitter username is correct.", - "LinkedinUrlValidationMessage": "Your Linkedin URL can not include whitespace, please make sure your Linkedin URL is correct.", + "LinkedinUrlValidationMessage": "Your LinkedIn URL can not include whitespace, please make sure your LinkedIn URL is correct.", "NoPostsFound": "No posts found!", "SearchInPosts": "Search in posts...", "MinimumSearchContent": "You must enter at least 3 characters!", "Volo.AbpIo.Domain:060001": "Source URL(\"{PostUrl}\") is not Github URL", - "Volo.AbpIo.Domain:060002": "Post Content is not available from Github(\"{PostUrl}\") resource.", + "Volo.AbpIo.Domain:060002": "Post Content is not available from GitHub(\"{PostUrl}\") resource.", "Volo.AbpIo.Domain:060003": "No post content found!", "SeeMore": "See More", "JoinTheABPCommunity": "Join the ABP Community", @@ -171,14 +171,14 @@ "Discord_Page_Announce": "We are happy to announce ABP Community Discord Server!", "Discord_Page_Description_1": "ABP Community has been growing since day one. We wanted to take it to the next step by creating an official ABP Discord server so the ABP Community can interact with each other using the wonders of instant messaging.", "Discord_Page_Description_2": "ABP Community Discord Server is the place where you can showcase your creations using ABP Framework, share the tips that worked for you, catch up with the latest news and announcements about ABP Framework, just chat with community members to exchange ideas, and have fun!", - "Discord_Page_Description_3": "This ABP Community Discord Server is the official one with the ABP Core Team is present on the server to monitor.", + "Discord_Page_Description_3": "This ABP Community Discord Server is the official one with the ABP Core Team present on the server to monitor.", "Discord_Page_JoinToServer": "Join ABP Discord Server", "Events_Page_MetaTitle": "ABP Community Events", "Events_Page_MetaDescription": "The live shows, hosted by the ABP Team, are casual sessions full of community content, demos, Q&A, and discussions around what's happening in ABP.", "Events_Page_Title": "ABP Community Talks", "Members_Page_WritingFromUser": "Read writing from {0} on ABP Community.", "Post_Create_Page_MetaTitle": "New Post", - "Post_Create_Page_MetaDescription": "Create your post for sharing your experiences about ABP framework and contributing the ABP Community.", + "Post_Create_Page_MetaDescription": "Create your post for sharing your experiences about the ABP framework and contributing to the ABP Community.", "Post_Create_Page_CreateNewPost": "Create New Post", "Post_Index_Page_MetaDescription": "ABP Community's purpose is to create a contribution environment for developers who use the ABP framework.", "Layout_Title": "{0} | ABP Community", @@ -193,7 +193,7 @@ "AbpCommunityTitleContent": "ABP Community - Open Source ABP Framework", "CommunitySlogan": "A unique community platform for ABP Lovers", "RaffleIsNotActive": "Raffle is not active", - "YouAreAlreadyJoinedToThisRaffle": "You already joined to this raffle!", + "YouAreAlreadyJoinedToThisRaffle": "You already joined this raffle!", "InvalidSubscriptionCode": "Invalid subscription code", "Raffle:{0}": "Raffle: {0}", "Join": "Join", @@ -261,6 +261,9 @@ "Preview": "Preview", "VisitPage": "Visit Page", "VisitVideoCourseDescription": "If you want to learn the basics of the ABP Framework, check out the ABP Essentials Video courses.", - "EditProfile": "Edit Profile" + "EditProfile": "Edit Profile", + "ConfirmEmailForPost": "To be able to post, you need to confirm your email. Go to account.abp.io/Account/Manage and verify your email in the Personal Info tab.", + "DailyPostCreateLimitation": "You have reached the daily post creation limit. You can create a new post in {0}.", + "YourAccountDisabled": "Your user account is disabled!" } -} \ No newline at end of file +} diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json index bf045dea81..2403cb7681 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/es.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown soportado.", "Preview": "Avance", "VisitPage": "Visita la página", - "VisitVideoCourseDescription": "Si desea aprender los conceptos básicos del marco ABP, consulte los cursos en vídeo de ABP Essentials." + "VisitVideoCourseDescription": "Si desea aprender los conceptos básicos del marco ABP, consulte los cursos en vídeo de ABP Essentials.", + "ConfirmEmailForPost": "Para poder publicar, debe confirmar su correo electrónico. Vaya a account.abp.io/Account/Manage y verifique su correo electrónico en la pestaña Información personal.", + "DailyPostCreateLimitation": "Has alcanzado el límite diario de creación de publicaciones. Puedes crear una nueva publicación en {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json index acf70381ff..3f420b1822 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fi.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown tuettu.", "Preview": "Esikatselu", "VisitPage": "Vieraile sivulla", - "VisitVideoCourseDescription": "Jos haluat oppia ABP Frameworkin perusteet, katso ABP Essentials Video -kurssit." + "VisitVideoCourseDescription": "Jos haluat oppia ABP Frameworkin perusteet, katso ABP Essentials Video -kurssit.", + "ConfirmEmailForPost": "Jotta voit lähettää viestejä, sinun on vahvistettava sähköpostiosoitteesi. Siirry osoitteeseen account.abp.io/Account/Manage ja vahvista sähköpostiosoitteesi Henkilökohtaiset tiedot -välilehdessä.", + "DailyPostCreateLimitation": "Olet saavuttanut päivittäisen viestien luomisrajan. Voit luoda uuden viestin kohteessa {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json index 963bde3048..a7821015b4 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/fr.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown prise en charge.", "Preview": "Aperçu", "VisitPage": "Page de visite", - "VisitVideoCourseDescription": "Si vous souhaitez apprendre les bases du framework ABP, consultez les cours vidéo ABP Essentials." + "VisitVideoCourseDescription": "Si vous souhaitez apprendre les bases du framework ABP, consultez les cours vidéo ABP Essentials.", + "ConfirmEmailForPost": "Pour pouvoir publier, vous devez confirmer votre e-mail. Accédez à account.abp.io/Account/Manage et vérifiez votre e-mail dans l'onglet Informations personnelles.", + "DailyPostCreateLimitation": "Vous avez atteint la limite quotidienne de création de publications. Vous pouvez créer une nouvelle publication dans {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json index 940d92573f..87919eef8b 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hi.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown का समर्थन किया।", "Preview": "पूर्व दर्शन", "VisitPage": "यात्रा पेज", - "VisitVideoCourseDescription": "यदि आप एबीपी फ्रेमवर्क की मूल बातें सीखना चाहते हैं, तो एबीपी एसेंशियल वीडियो पाठ्यक्रम देखें।" + "VisitVideoCourseDescription": "यदि आप एबीपी फ्रेमवर्क की मूल बातें सीखना चाहते हैं, तो एबीपी एसेंशियल वीडियो पाठ्यक्रम देखें।", + "ConfirmEmailForPost": "पोस्ट करने में सक्षम होने के लिए, आपको अपने ईमेल की पुष्टि करनी होगी। account.abp.io/Account/Manage पर जाएं और व्यक्तिगत जानकारी टैब में अपना ईमेल सत्यापित करें।", + "DailyPostCreateLimitation": "आप दैनिक पोस्ट निर्माण सीमा तक पहुंच गए हैं। आप {0} में एक नई पोस्ट बना सकते हैं।" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hr.json index f0b3a5941c..5cb7ff44a0 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hr.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown podržan.", "Preview": "Pregled", "VisitPage": "Posjetite stranicu", - "VisitVideoCourseDescription": "Ako želite naučiti osnove ABP okvira, pogledajte video tečajeve ABP Essentials." + "VisitVideoCourseDescription": "Ako želite naučiti osnove ABP okvira, pogledajte video tečajeve ABP Essentials.", + "ConfirmEmailForPost": "Da biste mogli objavljivati, morate potvrditi svoju e-poštu. Idite na account.abp.io/Account/Manage i potvrdite svoju e-poštu na kartici Osobni podaci.", + "DailyPostCreateLimitation": "Dosegli ste dnevno ograničenje za izradu postova. Možete stvoriti novi post u {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hu.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hu.json index 84117ededd..95433c6d92 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hu.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/hu.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown támogatott.", "Preview": "Előnézet", "VisitPage": "Látogassa meg az oldalt", - "VisitVideoCourseDescription": "Ha meg szeretné tanulni az ABP Framework alapjait, nézze meg az ABP Essentials Video tanfolyamokat." + "VisitVideoCourseDescription": "Ha meg szeretné tanulni az ABP Framework alapjait, nézze meg az ABP Essentials Video tanfolyamokat.", + "ConfirmEmailForPost": "A bejegyzések közzétételéhez meg kell erősítenie e-mail-címét. Nyissa meg az account.abp.io/Account/Manage oldalt, és ellenőrizze e-mail-címét a Személyes adatok lapon.", + "DailyPostCreateLimitation": "Elérte a napi bejegyzéslétrehozási korlátot. Új bejegyzést itt hozhat létre: {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json index 953186b239..8f2a733a2d 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/is.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown stutt.", "Preview": "Forskoðun", "VisitPage": "Heimsæktu síðu", - "VisitVideoCourseDescription": "Ef þú vilt læra grunnatriði ABP Framework skaltu skoða ABP Essentials Video námskeiðin." + "VisitVideoCourseDescription": "Ef þú vilt læra grunnatriði ABP Framework skaltu skoða ABP Essentials Video námskeiðin.", + "ConfirmEmailForPost": "Til að geta sent færslur þarftu að staðfesta netfangið þitt. Farðu á account.abp.io/Account/Manage og staðfestu tölvupóstinn þinn á Persónulegum upplýsingum flipanum.", + "DailyPostCreateLimitation": "Þú hefur náð daglegu takmörkunum fyrir færslu færslu. Þú getur búið til nýja færslu í {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json index 88bf43fc0e..45021c315d 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/it.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown supportato.", "Preview": "Anteprima", "VisitPage": "Visita la pagina", - "VisitVideoCourseDescription": "Se vuoi apprendere le nozioni di base del Framework ABP, dai un'occhiata ai corsi video ABP Essentials." + "VisitVideoCourseDescription": "Se vuoi apprendere le nozioni di base del Framework ABP, dai un'occhiata ai corsi video ABP Essentials.", + "ConfirmEmailForPost": "Per poter pubblicare, devi confermare la tua email. Vai su account.abp.io/Account/Manage e verifica la tua email nella scheda Informazioni personali.", + "DailyPostCreateLimitation": "Hai raggiunto il limite giornaliero di creazione di post. Puoi creare un nuovo post in {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/nl.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/nl.json index 5d18bde830..958c68263d 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/nl.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/nl.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown ondersteund.", "Preview": "Voorbeeld", "VisitPage": "Bezoek pagina", - "VisitVideoCourseDescription": "Als je de basis van het ABP Framework wilt leren, bekijk dan de ABP Essentials Videocursussen." + "VisitVideoCourseDescription": "Als je de basis van het ABP Framework wilt leren, bekijk dan de ABP Essentials Videocursussen.", + "ConfirmEmailForPost": "Om te kunnen posten, moet u uw e-mailadres bevestigen. Ga naar account.abp.io/Account/Manage en verifieer uw e-mailadres op het tabblad Persoonlijke informatie.", + "DailyPostCreateLimitation": "Je hebt de dagelijkse limiet voor het maken van berichten bereikt. Je kunt een nieuw bericht maken in {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pl-PL.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pl-PL.json index a86b93515c..16af07e6e4 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pl-PL.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pl-PL.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown utrzymany.", "Preview": "Zapowiedź", "VisitPage": "Odwiedź stronę", - "VisitVideoCourseDescription": "Jeśli chcesz poznać podstawy ABP Framework, sprawdź kursy wideo ABP Essentials." + "VisitVideoCourseDescription": "Jeśli chcesz poznać podstawy ABP Framework, sprawdź kursy wideo ABP Essentials.", + "ConfirmEmailForPost": "Aby móc publikować, musisz potwierdzić swój adres e-mail. Przejdź do account.abp.io/Account/Manage i zweryfikuj swój adres e-mail w zakładce Dane osobowe.", + "DailyPostCreateLimitation": "Osiągnąłeś dzienny limit tworzenia postów. Możesz utworzyć nowy post w {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pt-BR.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pt-BR.json index af28a46228..249e758a53 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pt-BR.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/pt-BR.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown suportado.", "Preview": "Visualização", "VisitPage": "Visite a página", - "VisitVideoCourseDescription": "Se você quiser aprender o básico do ABP Framework, confira os cursos em vídeo ABP Essentials." + "VisitVideoCourseDescription": "Se você quiser aprender o básico do ABP Framework, confira os cursos em vídeo ABP Essentials.", + "ConfirmEmailForPost": "Para poder postar, você precisa confirmar seu e-mail. Acesse account.abp.io/Account/Manage e verifique seu e-mail na guia Informações pessoais.", + "DailyPostCreateLimitation": "Você atingiu o limite diário de criação de postagens. Você pode criar uma nova postagem em {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json index e9d89b398b..7d33ecdb90 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown sprijinit.", "Preview": "previzualizare", "VisitPage": "Vizitați pagina", - "VisitVideoCourseDescription": "Dacă doriți să aflați elementele de bază ale cadrului ABP, consultați cursurile video ABP Essentials." + "VisitVideoCourseDescription": "Dacă doriți să aflați elementele de bază ale cadrului ABP, consultați cursurile video ABP Essentials.", + "ConfirmEmailForPost": "Pentru a putea posta, trebuie să vă confirmați adresa de e-mail. Accesați account.abp.io/Account/Manage și verificați e-mailul în fila Informații personale.", + "DailyPostCreateLimitation": "Ați atins limita zilnică de creare a postărilor. Puteți crea o postare nouă în {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json index dcfbc84bf9..6c842ef388 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sk.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown podporované.", "Preview": "Náhľad", "VisitPage": "Navštívte stránku", - "VisitVideoCourseDescription": "Ak sa chcete naučiť základy rámca ABP, pozrite si video kurzy ABP Essentials." + "VisitVideoCourseDescription": "Ak sa chcete naučiť základy rámca ABP, pozrite si video kurzy ABP Essentials.", + "ConfirmEmailForPost": "Aby ste mohli uverejňovať príspevky, musíte potvrdiť svoj e-mail. Prejdite na stránku account.abp.io/Account/Manage a overte svoj e-mail na karte Osobné informácie.", + "DailyPostCreateLimitation": "Dosiahli ste denný limit na vytváranie príspevkov. Nový príspevok môžete vytvoriť v {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sl.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sl.json index 8ed4d53271..eb6a616017 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sl.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/sl.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown podprt.", "Preview": "Predogled", "VisitPage": "Obiščite stran", - "VisitVideoCourseDescription": "Če se želite naučiti osnov ogrodja ABP, si oglejte video tečaje ABP Essentials." + "VisitVideoCourseDescription": "Če se želite naučiti osnov ogrodja ABP, si oglejte video tečaje ABP Essentials.", + "ConfirmEmailForPost": "Če želite objavljati, morate potrditi svoj e-poštni naslov. Pojdite na account.abp.io/Account/Manage in potrdite svoj e-poštni naslov na zavihku Osebni podatki.", + "DailyPostCreateLimitation": "Dosegli ste dnevno omejitev za ustvarjanje objav. Novo objavo lahko ustvarite v {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json index 711d068087..8d42d61eb0 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json @@ -244,6 +244,9 @@ "BuyTicket": "Bilet al", "SeeEvent": "Etkinliği Gör", "Cancel": "Vazgeç", - "Continue": "Devam" + "Continue": "Devam", + "ConfirmEmailForPost": "Gönderi paylaşabilmek için e-posta adresinizi onaylamanız gerekir. account.abp.io/Account/Manage adresine gidin ve Kişisel Bilgiler sekmesinden e-posta adresinizi doğrulayın.", + "DailyPostCreateLimitation": "Günlük gönderi paylaşma sınırına ulaştınız. {0}'da yeni bir gönderi paylaşabilirsiniz.", + "YourAccountDisabled": "Kullanıcı hesabınız devre dışı bırakıldı!" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/vi.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/vi.json index bd6baa67bb..4ca0c8ca49 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/vi.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/vi.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown được hỗ trợ.", "Preview": "Xem trước", "VisitPage": "Ghé thăm trang", - "VisitVideoCourseDescription": "Nếu bạn muốn tìm hiểu những kiến ​​thức cơ bản về Khung ABP, hãy xem các khóa học Video Cơ bản về ABP." + "VisitVideoCourseDescription": "Nếu bạn muốn tìm hiểu những kiến ​​thức cơ bản về Khung ABP, hãy xem các khóa học Video Cơ bản về ABP.", + "ConfirmEmailForPost": "Để có thể đăng bài, bạn cần xác nhận email của mình. Hãy truy cập account.abp.io/Account/Quản lý và xác minh email của bạn trong tab Thông tin cá nhân.", + "DailyPostCreateLimitation": "Bạn đã đạt đến giới hạn tạo bài đăng hàng ngày. Bạn có thể tạo bài đăng mới trong {0}." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json index 2bf0e9fb50..c6ef5a2c3d 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown 支持的。", "Preview": "预览", "VisitPage": "访问页面", - "VisitVideoCourseDescription": "如果您想学习 ABP 框架的基础知识,请查看 ABP Essentials 视频课程。" + "VisitVideoCourseDescription": "如果您想学习 ABP 框架的基础知识,请查看 ABP Essentials 视频课程。", + "ConfirmEmailForPost": "为了能够发帖,您需要确认您的电子邮件。转到 account.abp.io/Account/Manage 并在“个人信息”选项卡中验证您的电子邮件。", + "DailyPostCreateLimitation": "您已达到每日帖子创建限制。您可以在 {0} 中创建新帖子。" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hant.json index 61bb0aa8a0..b72c927296 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hant.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hant.json @@ -259,6 +259,8 @@ "MarkdownSupported": "Markdown 支持的。", "Preview": "预览", "VisitPage": "访问页面", - "VisitVideoCourseDescription": "如果您想学习 ABP 框架的基础知识,请查看 ABP Essentials 视频课程。" + "VisitVideoCourseDescription": "如果您想学习 ABP 框架的基础知识,请查看 ABP Essentials 视频课程。", + "ConfirmEmailForPost": "为了能够发帖,您需要确认您的电子邮件。转到 account.abp.io/Account/Manage 并在“个人信息”选项卡中验证您的电子邮件。", + "DailyPostCreateLimitation": "您已达到每日帖子创建限制。您可以在 {0} 中创建新帖子。" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json index 7f440cf205..984a3d28a7 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json @@ -158,7 +158,7 @@ "IndexPageHeroSection": "open sourceWeb Application
Framework
for asp.net core", "UiFramework": "UI框架", "EmailAddress": "电子邮件地址", - "Mobile": "移动电话", + "Mobile": "选择移动应用程序框架", "ReactNative": "React Native", "Strong": "强大", "Complete": "完整", @@ -476,4 +476,4 @@ "ABPVideoCoursesPageDescription": "通过ABP团队创建的视频课程学习ABP框架的基础知识。在本视频系列中,您将学习ABP框架的基本主题。每个视频上的数字都是根据学习流程编写的。", "ABPVideoCoursesTitle": "ABP 基本视频" } -} \ No newline at end of file +} diff --git a/common.props b/common.props index 75170b8152..2b87badaf8 100644 --- a/common.props +++ b/common.props @@ -1,8 +1,8 @@ latest - 8.2.1 - 3.2.1 + 8.3.0-preview + 3.3.0-preview $(NoWarn);CS1591;CS0436 https://abp.io/assets/abp_nupkg.png https://abp.io/ diff --git a/docs/cs/AspNetCore/Widgets.md b/docs/cs/AspNetCore/Widgets.md deleted file mode 100644 index f0ee218804..0000000000 --- a/docs/cs/AspNetCore/Widgets.md +++ /dev/null @@ -1,506 +0,0 @@ -# Widgety - -ABP poskytuje model a infastrukturu k vytváření **znovu použitelných widgetů**. Systém widgetů je rozšíření pro [ASP.NET Core pohledové komponenty](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components). Widgety jsou zvláště užitečné, když chcete; - -* Mít závislosti na **skriptech & stylech** ve vašem widgetu. -* Vytvářet **řídící panely** za použítí widgetů. -* Definovat widgety v znovu použitelných **[modulech](../Module-Development-Basics.md)**. -* Spolupráci widgetů s **[authorizačními](../Authorization.md)** a **[svazovacími](Bundling-Minification.md)** systémy. - -## Základní definice widgetu - -### Tvorba pohledové komponenty - -Jako první krok, vytvořte běžnou ASP.NET Core pohledovou komponentu: - -![widget-basic-files](../images/widget-basic-files.png) - -**MySimpleWidgetViewComponent.cs**: - -````csharp -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc; - -namespace DashboardDemo.Web.Pages.Components.MySimpleWidget -{ - public class MySimpleWidgetViewComponent : AbpViewComponent - { - public IViewComponentResult Invoke() - { - return View(); - } - } -} -```` - -Dědění z `AbpViewComponent` není vyžadováno. Můžete dědit ze standardního ASP.NET Core `ViewComponent`. `AbpViewComponent` pouze definuje pár základních a užitečných vlastnosti. - -Můžete vložit službu a pomocí metody `Invoke` z ní získat některá data. Možná budete muset provést metodu Invoke jako asynchronní `public async Task InvokeAsync()`. Podívejte se na dokument [ASP.NET Core ViewComponents](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components) pro všechna další použítí. - -**Default.cshtml**: - -```xml -
-

My Simple Widget

-

This is a simple widget!

-
-``` - -### Definice widgetu - -Přidejte atribut `Widget` k třídě `MySimpleWidgetViewComponent` pro označení této pohledové komponenty jako widgetu: - -````csharp -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc.UI.Widgets; - -namespace DashboardDemo.Web.Pages.Components.MySimpleWidget -{ - [Widget] - public class MySimpleWidgetViewComponent : AbpViewComponent - { - public IViewComponentResult Invoke() - { - return View(); - } - } -} -```` - -## Vykreslení widgetu - -Vykreslení widgetu je vcelku standardní. Použijte metodu `Component.InvokeAsync` v razor pohledu/stránce jako s kteroukoliv jinou pohledovou komponentou. Příklady: - -````xml -@await Component.InvokeAsync("MySimpleWidget") -@await Component.InvokeAsync(typeof(MySimpleWidgetViewComponent)) -```` - -První přístup používá název widgetu, zatímco druhý používá typ pohledové komponenty. - -### Widgety s argumenty - -Systém ASP.NET Core pohledových komponent umožňuje přijímat argumenty pro pohledové komponenty. Níže uvedená pohledová komponenta přijímá `startDate` a `endDate` a používá tyto argumenty k získání dat ze služby. - -````csharp -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc.UI.Widgets; - -namespace DashboardDemo.Web.Pages.Shared.Components.CountersWidget -{ - [Widget] - public class CountersWidgetViewComponent : AbpViewComponent - { - private readonly IDashboardAppService _dashboardAppService; - - public CountersWidgetViewComponent(IDashboardAppService dashboardAppService) - { - _dashboardAppService = dashboardAppService; - } - - public async Task InvokeAsync( - DateTime startDate, DateTime endDate) - { - var result = await _dashboardAppService.GetCountersWidgetAsync( - new CountersWidgetInputDto - { - StartDate = startDate, - EndDate = endDate - } - ); - - return View(result); - } - } -} -```` - -Nyní musíte předat anonymní objekt k předání argumentů tak jak je ukázáno níže: - -````xml -@await Component.InvokeAsync("CountersWidget", new -{ - startDate = DateTime.Now.Subtract(TimeSpan.FromDays(7)), - endDate = DateTime.Now -}) -```` - -## Název widgetu - -Výchozí název pohledových komponent je vypočítán na základě názvu typu pohledové komponenty. Pokud je typ pohledové komponenty `MySimpleWidgetViewComponent` potom název widgetu bude `MySimpleWidget` (odstraní se `ViewComponent` postfix). Takto ASP.NET Core vypočítává název pohledové komponenty. - -Chcete-li přizpůsobit název widgetu, stačí použít standardní atribut `ViewComponent` z ASP.NET Core: - -```csharp -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc.UI.Widgets; - -namespace DashboardDemo.Web.Pages.Components.MySimpleWidget -{ - [Widget] - [ViewComponent(Name = "MyCustomNamedWidget")] - public class MySimpleWidgetViewComponent : AbpViewComponent - { - public IViewComponentResult Invoke() - { - return View("~/Pages/Components/MySimpleWidget/Default.cshtml"); - } - } -} -``` - -ABP bude respektovat přizpůsobený název při zpracování widgetu. - -> Pokud jsou názvy pohledové komponenty a složky, která pohledovou komponentu obsahuje rozdílné, pravděpodobně budete muset ručně uvést cestu pohledu tak jako je to provedeno v tomto příkladu. - -### Zobrazovaný název - -Můžete také definovat čitelný & lokalizovatelný zobrazovaný název pro widget. Tento zobrazovaný název může být využít na uživatelském rozhraní kdykoliv je to potřeba. Zobrazovaný název je nepovinný a lze ho definovat pomocí vlastností atributu `Widget`: - -````csharp -using DashboardDemo.Localization; -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc.UI.Widgets; - -namespace DashboardDemo.Web.Pages.Components.MySimpleWidget -{ - [Widget( - DisplayName = "MySimpleWidgetDisplayName", // Lokalizační klíč - DisplayNameResource = typeof(DashboardDemoResource) // Lokalizační zdroj - )] - public class MySimpleWidgetViewComponent : AbpViewComponent - { - public IViewComponentResult Invoke() - { - return View(); - } - } -} -```` - -Podívejte se na [dokument lokalizace](../Localization.md) pro více informací o lokalizačních zdrojích a klíčích. - -## Závislosti na stylech & skriptech - -Problémy když má widget soubory skriptů a stylů; - -* Každý stránka, která používá widget musí také přidat soubory **skriptů & stylů** tohoto widgetu. -* Stránka se také musí postarat o **závislé knihovny/soubory** widgetu. - -ABP tyto problémy řeší, když správně propojíme zdroje s widgetem. O závislosti widgetu se při jeho používání nestaráme. - -### Definování jednoduchých cest souborů - -Níže uvedený příklad widgetu přidá stylové a skriptové soubory: - -````csharp -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc.UI.Widgets; - -namespace DashboardDemo.Web.Pages.Components.MySimpleWidget -{ - [Widget( - StyleFiles = new[] { "/Pages/Components/MySimpleWidget/Default.css" }, - ScriptFiles = new[] { "/Pages/Components/MySimpleWidget/Default.js" } - )] - public class MySimpleWidgetViewComponent : AbpViewComponent - { - public IViewComponentResult Invoke() - { - return View(); - } - } -} -```` - -ABP bere v úvahu tyto závislosti a správně je přidává do pohledu/stránky při použití widgetu. Stylové/skriptové soubory mohou být **fyzické nebo virtuální**. Plně integrováno do [virtuálního systému souborů](../Virtual-File-System.md). - -### Definování přispěvatelů balíku - -Všechny zdroje použité ve widgetech na stránce jsou přidány jako **svazek** (svázány & minifikovány v produkci pokud nenastavíte jinak). Kromě přidání jednoduchého souboru můžete využít plnou funkčnost přispěvatelů balíčků. - -Níže uvedený ukázkový kód provádí totéž co výše uvedený kód, ale definuje a používá přispěvatele balíků: - -````csharp -using System.Collections.Generic; -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc.UI.Bundling; -using Volo.Abp.AspNetCore.Mvc.UI.Widgets; - -namespace DashboardDemo.Web.Pages.Components.MySimpleWidget -{ - [Widget( - StyleTypes = new []{ typeof(MySimpleWidgetStyleBundleContributor) }, - ScriptTypes = new[]{ typeof(MySimpleWidgetScriptBundleContributor) } - )] - public class MySimpleWidgetViewComponent : AbpViewComponent - { - public IViewComponentResult Invoke() - { - return View(); - } - } - - public class MySimpleWidgetStyleBundleContributor : BundleContributor - { - public override void ConfigureBundle(BundleConfigurationContext context) - { - context.Files - .AddIfNotContains("/Pages/Components/MySimpleWidget/Default.css"); - } - } - - public class MySimpleWidgetScriptBundleContributor : BundleContributor - { - public override void ConfigureBundle(BundleConfigurationContext context) - { - context.Files - .AddIfNotContains("/Pages/Components/MySimpleWidget/Default.js"); - } - } -} - -```` - -Systém přispěvatelů balíků je velmi schopný. Pokud váš widget používá k vykreslení grafu JavaScript knihovnu, můžete ji deklarovat jako závislost, díky tomu se knihovna pokud nebyla dříve přidána automaticky přidá na stránku Tímto způsobem se stránka využívající váš widget nestará o závislosti. - -Podívejte se na dokumentaci [svazování & minifikace](Bundling-Minification.md) pro více informací o tomto systému. - -## RefreshUrl - -Widget může navrhnout `RefreshUrl`, který se používá vždy, když je potřeba widget aktualizovat. Je-li definován, widget se při každé aktualizaci znovu vykreslí na straně serveru (viz refresh `methoda` u `WidgetManager` níže). - -````csharp -[Widget(RefreshUrl = "Widgets/Counters")] -public class CountersWidgetViewComponent : AbpViewComponent -{ - -} -```` - -Jakmile pro svůj widget definujete `RefreshUrl`, musíte poskytnout koncový bod pro jeho vykreslení a vrátit ho: - -````csharp -[Route("Widgets")] -public class CountersWidgetController : AbpController -{ - [HttpGet] - [Route("Counters")] - public IActionResult Counters(DateTime startDate, DateTime endDate) - { - return ViewComponent("CountersWidget", new {startDate, endDate}); - } -} -```` - -Trasa `Widgets/Counters` předchozímu `RefreshUrl`. - -> Widget lze obnovit dvěma způsoby: Prvním způsobem je použití `RefreshUrl`, kdy se znovu vykreslí na serveru a nahradí HTML vrácené tím ze serveru. Druhým způsobem widget získá data (obvykle JSON objekt) ze serveru a obnoví se sám u klienta (viz refresh metoda v sekci Widget JavaScript API). - -## JavaScript API - -Možná bude potřeba vykreslit a obnovit widget na straně klienta. V takových případech můžete použít ABP `WidgetManager` a definovat API pro vaše widgety. - -### WidgetManager - -`WidgetManager` se používá k inicializaci a aktualizaci jednoho nebo více widgetů. Vytvořte nový `WidgetManager` jako je ukázáno níže: - -````js -$(function() { - var myWidgetManager = new abp.WidgetManager('#MyDashboardWidgetsArea'); -}) -```` - -`MyDashboardWidgetsArea` může obsahovat jeden nebo více widgetů. - -> Použíti `WidgetManager` uvnitř document.ready (jako nahoře) je dobrá praktika jelikož jeho funkce používají DOM a potřebují, aby byl DOM připraven. - -#### WidgetManager.init() - -`init` jednoduše inicializuje `WidgetManager` a volá metody `init` v souvisejících widgetech pokud je obsahují (podívejte se na sekci Widget JavaScript API section níže) - -```js -myWidgetManager.init(); -``` - -#### WidgetManager.refresh() - -`refresh` metoda obnoví všechny widgety související s tímto `WidgetManager`: - -```` -myWidgetManager.refresh(); -```` - -#### WidgetManager možnosti - -WidgetManager má několik dalších možností. - -##### Filtrační formulář - -Pokud vaše widgety vyžadují parametry/filtry pak budete obvykle mít formulář pro filtrování widgetů. V takových případech můžete vytvořit formulář, který obsahuje prvky formuláře a oblast řídicího panelu s nějakými widgety uvnitř. Příklad: - -````xml -
- ...prvky formuláře -
- -
- ...widgety -
-```` - -`data-widget-filter` atribut propojuje formulář s widgety. Kdykoli je formulář odeslán, všechny widgety jsou automaticky aktualizovány pomocí polí formuláře jako filtru. - -Místo atributu `data-widget-filter`, můžete použít parametr `filterForm` v konstruktoru `WidgetManager`. Příklad: - -````js -var myWidgetManager = new abp.WidgetManager({ - wrapper: '#MyDashboardWidgetsArea', - filterForm: '#MyDashboardFilterForm' -}); -```` - -##### Zpětné volání filtru - -Možná budete chtít mít lepší kontrolu nad poskytováním filtrů při inicializaci a aktualizaci widgetů. V tomto případě můžete použít volbu `filterCallback`: - -````js -var myWidgetManager = new abp.WidgetManager({ - wrapper: '#MyDashboardWidgetsArea', - filterCallback: function() { - return $('#MyDashboardFilterForm').serializeFormToObject(); - } -}); -```` - -Tento příklad ukazuje výchozí implementaci `filterCallback`. Pomocí polí můžete vrátit jakýkoli JavaScript objekt. Příklad: - -````js -filterCallback: function() { - return { - 'startDate': $('#StartDateInput').val(), - 'endDate': $('#EndDateInput').val() - }; -} -```` - -Vrácené filtry jsou předávány všem widgetům na `init` a` refresh`. - -### Widget JavaScript API - -Widget může definovat rozhraní API jazyka JavaScript, které je v případě potřeby vyvoláno přes `WidgetManager`. Ukázku kódu níže lze použít k definování API pro widget. - -````js -(function () { - abp.widgets.NewUserStatisticWidget = function ($wrapper) { - - var getFilters = function () { - return { - ... - }; - } - - var refresh = function (filters) { - ... - }; - - var init = function (filters) { - ... - }; - - return { - getFilters: getFilters, - init: init, - refresh: refresh - }; - }; -})(); -```` - -`NewUserStatisticWidget` je tady název widgetu. Měl by odpovídat názvu widgetu definovanému na straně serveru. Všechny funkce jsou volitelné. - -#### getFilters - -Pokud má widget vlastní interní filtry, měla by tato funkce vrátit objekt filtru. Příklad: - -````js -var getFilters = function() { - return { - frequency: $wrapper.find('.frequency-filter option:selected').val() - }; -} -```` - -Tuto metodu používá `WidgetManager` při vytváření filtrů. - -#### init - -Slouží k inicializaci widgetu kdykoli je potřeba. Má argument filtru, který lze použít při získávání dat ze serveru. Metoda `init` je použita když je volána funkce `WidgetManager.init()`. Použita je i v případě že váš widget vyžaduje úplné obnovení při aktualizaci. Viz `RefreshUrl` v možnostech widgetu. - -#### refresh - -Slouží k aktualizaci widgetu kdykoli je potřeba. Má argument filtru, který lze použít při získávání dat ze serveru. Metoda `refresh` se používá kdykoliv je volána funkce `WidgetManager.refresh()`. - -## Autorizace - -Některé widgety budou pravděpodobně muset být dostupné pouze pro ověřené nebo autorizované uživatele. V tomto případě použijte následující vlastnosti atributu `Widget`: - -* `RequiresAuthentication` (`bool`): Nastavte na true, aby byl tento widget použitelný pouze pro ověřené uživatele (uživatel je přihlášen do aplikace). -* `RequiredPolicies` (`List`): Seznam názvů zásad k autorizaci uživatele. Další informace o zásadách naleznete v [dokumentu autorizace](../Authorization.md). - -Příklad: - -````csharp -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc.UI.Widgets; - -namespace DashboardDemo.Web.Pages.Components.MySimpleWidget -{ - [Widget(RequiredPolicies = new[] { "MyPolicyName" })] - public class MySimpleWidgetViewComponent : AbpViewComponent - { - public IViewComponentResult Invoke() - { - return View(); - } - } -} -```` - -## WidgetOptions - -Jako alternativu k atributu `Widget` můžete ke konfiguraci widgetů použít `AbpWidgetOptions`: - -```csharp -Configure(options => -{ - options.Widgets.Add(); -}); -``` - -Toto vepište do metody `ConfigureServices` vašeho [modulu](../Module-Development-Basics.md). Veškerá konfigurace udělaná přes atribut `Widget` je dostupná i za pomoci `AbpWidgetOptions`. Příklad konfigurace, která přidává styl pro widget: - -````csharp -Configure(options => -{ - options.Widgets - .Add() - .WithStyles("/Pages/Components/MySimpleWidget/Default.css"); -}); -```` - -> Tip: `AbpWidgetOptions` lze také použít k získání existujícího widgetu a ke změně jeho konfigurace. To je obzvláště užitečné, pokud chcete změnit konfiguraci widgetu uvnitř modulu používaného vaší aplikací. Použíjte `options.Widgets.Find` k získání existujícího `WidgetDefinition`. - -## Podívejte se také na - -* [Příklad projektu (zdrojový kód)](https://github.com/abpframework/abp-samples/tree/master/DashboardDemo). - diff --git a/docs/cs/Autofac-Integration.md b/docs/cs/Autofac-Integration.md deleted file mode 100644 index 109dca6286..0000000000 --- a/docs/cs/Autofac-Integration.md +++ /dev/null @@ -1,84 +0,0 @@ -# Autofac integrace - -Autofac je jedním z nejpoužívanějších frameworků pro .Net pro vkládání závislostí (DI). Poskytuje pokročilejší funkce v porovnáním se standardní .Net Core DI knihovnou, jako dynamickou proxy a injekci vlastností. - -## Instalace Autofac integrace - -> Všechny startovací šablony a vzorky jsou s Autofac již integrovány. Takže většinou nemusíte tento balíček instalovat ručně. - -Nainstalujte do vašeho projektu balíček [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) (pro víceprojektovou aplikaci se doporučuje přidat do spustitelného/webového projektu.) - -```` -Install-Package Volo.Abp.Autofac -```` - -Poté přídejte k vašemu modulu závislost na `AbpAutofacModule`: - -```csharp -using Volo.Abp.Modularity; -using Volo.Abp.Autofac; - -namespace MyCompany.MyProject -{ - [DependsOn(typeof(AbpAutofacModule))] - public class MyModule : AbpModule - { - //... - } -} -``` - -Nakonec nastavte `AbpApplicationCreationOptions` aby nahradil výchozí služby pro vkládání závislostí na Autofac. Záleží na typu aplikace. - -### ASP.NET Core aplikace - -Volejte `UseAutofac()` v souboru **Startup.cs** jako je ukázáno níže: - -````csharp -public class Startup -{ - public IServiceProvider ConfigureServices(IServiceCollection services) - { - services.AddApplication(options => - { - //Integrace Autofac! - options.UseAutofac(); - }); - - return services.BuildServiceProviderFromFactory(); - } - - public void Configure(IApplicationBuilder app) - { - app.InitializeApplication(); - } -} -```` - -### Konzolová aplikace - -Volejte metodu `UseAutofac()` v možnostech `AbpApplicationFactory.Create` jako je ukázáno níže: - -````csharp -using System; -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp; - -namespace AbpConsoleDemo -{ - class Program - { - static void Main(string[] args) - { - using (var application = AbpApplicationFactory.Create(options => - { - options.UseAutofac(); //Autofac integrace - })) - { - //... - } - } - } -} -```` - diff --git a/docs/cs/Best-Practices/images/postgresql-delete-initial-migrations.png b/docs/cs/Best-Practices/images/postgresql-delete-initial-migrations.png deleted file mode 100644 index 14788c5fb8..0000000000 Binary files a/docs/cs/Best-Practices/images/postgresql-delete-initial-migrations.png and /dev/null differ diff --git a/docs/cs/Best-Practices/images/postgresql-update-database.png b/docs/cs/Best-Practices/images/postgresql-update-database.png deleted file mode 100644 index 30a5f3abe1..0000000000 Binary files a/docs/cs/Best-Practices/images/postgresql-update-database.png and /dev/null differ diff --git a/docs/cs/CLI.md b/docs/cs/CLI.md deleted file mode 100644 index f77c3ad969..0000000000 --- a/docs/cs/CLI.md +++ /dev/null @@ -1,167 +0,0 @@ -# ABP CLI - -ABP CLI (Command Line Interface) je nástroj v příkazovém řádku k provádění některých běžných úkonů v řešeních založených na ABP. - -## Instalace - -ABP CLI je [dotnet global tool](https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools). Nainstalujete jej pomocí okna příkazového řádku: - -````bash -dotnet tool install -g Volo.Abp.Cli -```` - -Aktualizace stávající instalace: - -````bash -dotnet tool update -g Volo.Abp.Cli -```` - -## Příkazy - -### new - -Vygeneruje nové řešení založené na ABP [startovací šabloně](Startup-Templates/Index.md). - -Základní použití: - -````bash -abp new [možnosti] -```` - -Příklad: - -````bash -abp new Acme.BookStore -```` - -* `Acme.BookStore` je tady název řešení. -* Běžná konvence je nazvat řešení stylem *VaseSpolecnost.VasProjekt*. Nicméně můžete použít i jiné pojmenování jako *VasProjekt* (jednostupňový jmenný prostor) nebo *VaseSpolecnost.VasProjekt.VasModul* (třístupňový jmenný prostor). - -#### Možnosti - -* `--template` nebo `-t`: Určuje název šablony. Výchozí šablona je `app`, která generuje webovou aplikaci. Dostupné šablony: - * `app` (výchozí): [Aplikační šablona](Startup-Templates/Application.md). Dodatečné možnosti: - * `--ui` nebo `-u`: Určuje UI framework. Výchozí framework je `mvc`. Dostupné frameworky: - * `mvc`: ASP.NET Core MVC. Pro tuto šablonu jsou dostupné dodatečné možnosti: - * `--tiered`: Vytvoří stupňovité řešení, kde jsou vrstvy Web a Http API fyzicky odděleny. Pokud není uvedeno, tak vytvoří vrstvené řešení, které je méně složité a vhodné pro většinu scénářů. - * `angular`: Angular. Pro tuto šablonu jsou dostupné dodatečné možnosti: - * `--separate-auth-server`: Oddělí Auth Server aplikaci od API host aplikace. Pokud není uvedeno, bude na straně serveru jediný koncový bod. - * `none`: Bez UI. Pro tuto šablonu jsou dostupné dodatečné možnosti: - * `--separate-auth-server`: Oddělí Auth Server aplikaci od API host aplikace. Pokud není uvedeno, bude na straně serveru jediný koncový bod. - * `--database-provider` nebo `-d`: Určuje poskytovatele databáze. Výchozí poskytovatel je `ef`. Dostupní poskytovatelé: - * `ef`: Entity Framework Core. - * `mongodb`: MongoDB. - * `module`: [Šablona modulu](Startup-Templates/Module.md). Dodatečné možnosti: - * `--no-ui`: Určuje nezahrnutí uživatelského rozhraní. Umožňuje vytvořit moduly pouze pro služby (a.k.a. mikroslužby - bez uživatelského rozhraní). -* `--output-folder` nebo `-o`: Určuje výstupní složku. Výchozí hodnota je aktuální adresář. -* `--version` nebo `-v`: Určuje verzi ABP & šablony. Může to být [štítek vydání](https://github.com/abpframework/abp/releases) nebo [název větve](https://github.com/abpframework/abp/branches). Pokud není uvedeno, používá nejnovější vydání. Většinou budete chtít použít nejnovější verzi. - - -### add-package - -Přidá ABP balíček do projektu, - -* Přidáním souvisejícícho nuget balíčku jako závislost do projektu. -* Přidáním `[DependsOn(...)]` atributu k modulové tříde v projektu (podívejte se na [dokument vývoje modulu](Module-Development-Basics.md)). - -> Všimněte si, že přidaný modul může vyžadovat další konfiguraci, která je obecně uvedena v dokumentaci příslušného balíčku. - -Základní použití: - -````bash -abp add-package [možnosti] -```` - -Příklad: - -```` -abp add-package Volo.Abp.MongoDB -```` - -* Tento příklad přidá do projektu balíček Volo.Abp.MongoDB. - -#### Možnosti - -* `--project` nebo `-p`: Určuje cestu k projektu (.csproj). Pokud není zadáno, CLI se pokusí najít soubor .csproj v aktuálním adresáři. - -### add-module - -Přidá [více-balíčkový aplikační modul](Modules/Index) k řešení tím, že najde všechny balíčky modulu, vyhledá související projekty v řešení a přidá každý balíček do odpovídajícího projektu v řešení. - -> Modul se obecně skládá z několika balíčků (z důvodu vrstvení, různých možností poskytovatele databáze nebo jiných důvodů). Použití příkazu `add-module` dramaticky zjednodušuje přidání modulu do řešení. Každý modul však může vyžadovat další konfiguraci, která je obecně uvedena v dokumentaci příslušného modulu. - -Základní použití: - -````bash -abp add-module [možnosti] -```` - -Příklad: - -```bash -abp add-module Volo.Blogging -``` - -* Tento příklad přidá do projektu modul Volo.Blogging. - -#### Možnosti - -* `--solution` nebo `-s`: Určuje cestu k řešení (.sln). Pokud není zadáno, CLI se pokusí najít soubor .sln v aktuálním adresáři. -* `--skip-db-migrations`: Pro poskytovatele databáze EF Core automaticky přidá nový kód první migrace (`Add-Migration`) a v případě potřeby aktualizuje databázi (`Update-Database`). Tuto možnost určete k vynechání této operace. -* `-sp` nebo `--startup-project`: Relativní cesta ke složce spouštěcího projektu. Výchozí hodnota je aktuální adresář. -* `--with-source-code`: Místo balíčků NuGet/NPM přidejte zdrojový kód modulu. - -### update - -Aktualizace všech balíčků souvisejících s ABP může být únavná, protože existuje mnoho balíčků frameworku a modulů. Tento příkaz automaticky aktualizuje na poslední verze všechny související ABP NuGet a NPM balíčky v řešení nebo projektu. - -Použití: - -````bash -abp update [možnosti] -```` - -* Pokud spouštíte v adresáři se souborem .sln, aktualizuje všechny balíčky všech projektů v řešení souvisejících s ABP na nejnovější verze. -* Pokud spouštíte v adresáři se souborem .csproj, aktualizuje všechny balíčky v projektu na nejnovější verze. - -#### Možnosti - -* `--include-previews` nebo `-p`: Zahrne náhledové, beta a rc balíčky při kontrole nových verzí. -* `--npm`: Aktualizuje pouze balíčky NPM. -* `--nuget`: Aktualizuje pouze balíčky NuGet. - -### login - -Některé funkce CLI vyžadují přihlášení k platformě abp.io. Chcete-li se přihlásit pomocí svého uživatelského jména, napište - -```bash -abp login -``` - -Všimněte si, že nové přihlášení s již aktivní relací ukončí předchozí relaci a vytvoří novou. - -### logout - -Odhlásí vás odebráním tokenu relace z počítače. - -``` -abp logout -``` - -### help - -Vypíše základní informace k používání CLI. - -Použítí: - -````bash -abp help [název-příkazu] -```` - -Příklady: - -````bash -abp help # Zobrazí obecnou nápovědu. -abp help new # Zobrazí nápovědu k příkazu "new". -```` - diff --git a/docs/cs/Contribution/Index.md b/docs/cs/Contribution/Index.md deleted file mode 100644 index ac1aaf00c1..0000000000 --- a/docs/cs/Contribution/Index.md +++ /dev/null @@ -1,64 +0,0 @@ -## Průvodce pro přispěvatele - -ABP je [open source](https://github.com/abpframework) a komunitně řízený projekt. Tento průvodce má za cíl pomoci každému kdo chce do projektu nějak přispět. - -### Příspěvek kódu - -Vždy můžete zaslat pull request do Github repositáře. - -- Naklonujte [ABP repozitář](https://github.com/abpframework/abp/) z Githubu. -- Učiňte potřebné změny. -- Zašlete pull request. - -Než budete dělat nějaké změny, diskutujte o nich prosím na [Github problémy](https://github.com/abpframework/abp/issues). Díky tomu nebude žádný jiný vývojář pracovat na stejném problému a Váš PR má lepší šanci na to být přijat. - -#### Opravy chyb a vylepšení - -Pokud chcete opravit známou chybu nebo pracovat na plánovaném vylepšení podívejte se na [seznam problémů](https://github.com/abpframework/abp/issues) na Githubu. - -#### Požadavky na funkce - -Pokud máte nápad na funkci pro framework nebo modul [vytvořte problém](https://github.com/abpframework/abp/issues/new) na Githubu nebo se připojte ke stávající diskuzi. V případě přijetí komunitou ho pak můžete implementovat. - -### Překlad dokumentů - -Pokud chcete přeložit celou [dokumentaci](https://abp.io/documents/) (včetně této stránky) do Vašeho rodného jazyka, následujte tyto kroky: - -* Naklonujte [ABP repozitář](https://github.com/abpframework/abp/) z Githubu. -* K přidání nového jazyka vytvořte novou složku v [docs](https://github.com/abpframework/abp/tree/master/docs). Název složky musí být "en", "es", "fr", "tr" atd. v závislosti na jazyku (navštivte [všechny jazykové kódy](https://msdn.microsoft.com/en-us/library/hh441729.aspx)). -* Pro referenci použijte ["en" složku](https://github.com/abpframework/abp/tree/master/docs/en) a její názvy souborů a strom složek. Při překladu této dokumentace zachovejte prosím tyto názvy stejné. -* Zašlete pull request (PR) po překladu jakéhokoliv dokumentu klidně i po jednom. Nečekejte až budete mít překlad všech dokumentů. - -Existuje několik základních dokumentů, které je třeba přeložit než bude jazyk uveřejněn na [stránkách ABP dokumentace](https://docs.abp.io) - -* Začínáme dokumenty -* Tutoriály -* CLI - -Nový jazyk je publikován jakmile jsou minimálně tyto překlady dokončeny. - -### Lokalizace zdrojů - -ABP framework má flexibilní [lokalizační systém](../Localization.md). Můžete tak vytvořit lokalizované uživatelské prostředí pro svou vlastní aplikaci. - -K tomu mají framework a vestavěné moduly již lokalizované texty. Například [lokalizační texty pro Volo.Abp.UI balík](https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json). - -Můžete vytvořit nový soubor ve [stejné složce](https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi) k přidání překladu. - -* Naklonujte [ABP repozitář](https://github.com/abpframework/abp/) z Githubu. -* Vytvořte nový soubor pro cílový jazyk pro lokalizační text v (json) souboru (u souboru en.json). -* Zkopírujte veškerý text ze souboru en.json. -* Přeložte texty. -* Zašlete pull request na Githubu. - -K překladu lokalizovaných textů můžete také použít příkaz `abp translate` of [ABP CLI](CLI.md). - -ABP je modulářní framework, proto je zde mnoho zdrojů lokalizačních textů, jeden pro každý modul. K najití všech .json souborů, vyhledejte po naklonování repozitáře soubory "en.json". Můžete se taky podívat na [tento seznam](Localization-Text-Files.md) souborů lokalizačních textů. - -### Příspevky do blogu a návody - -Pokud se rozhodnete pro ABP vytvořit nějaké návody nebo příspěvky do blogu, dejte nám vědět (prostřednictvím [Github problémy](https://github.com/abpframework/abp/issues)), ať můžeme přidat odkaz na Váš návod/příspěvek v oficiální dokumentaci a oznámit na našem [Twitter účtu](https://twitter.com/abpframework). - -### Zpráva o chybě - -Pokud najdete chybu, [vytvořte prosím problém v Github repozitáři](https://github.com/abpframework/abp/issues/new). diff --git a/docs/cs/Dapper.md b/docs/cs/Dapper.md deleted file mode 100644 index 94e40347f0..0000000000 --- a/docs/cs/Dapper.md +++ /dev/null @@ -1,61 +0,0 @@ -# Dapper integrace - -Jelikož myšlenka Dapper je taková, že sql příkaz má přednost, tak hlavně poskytuje metody rozšíření pro `IDbConnection` rozhraní. - -Abp nezapouzdřuje přílíš mnoho funkcí pro Dapper. Abp Dapper poskytuje základní třídu `DapperRepository` založenou na Abp EntityFrameworkCore, který poskytuje vlastnosti `IDbConnection` a `IDbTransaction` vyžadované v Dapper. - -Tyto dvě vlastnosti fungují dobře s [jednotkou práce](Unit-Of-Work.md). - -## Instalace - -Nainstalujte a nakonfigurujte EF Core podle [EF Core integrační dokumentace](Entity-Framework-Core.md). - -`Volo.Abp.Dapper` je hlavní NuGet balík pro Dapper integraci. Nainstalujte jej proto do vašeho projektu (pro strukturovanou aplikaci do datové/infrastrukturní vrstvy): - -```shell -Install-Package Volo.Abp.Dapper -``` - -Poté přidejte závislost na `AbpDapperModule` modulu (atribut `DependsOn`) do Vašeho [modulu](Module-Development-Basics.md): - -````C# -using Volo.Abp.Dapper; -using Volo.Abp.Modularity; - -namespace MyCompany.MyProject -{ - [DependsOn(typeof(AbpDapperModule))] - public class MyModule : AbpModule - { - //... - } -} -```` - -## Implementace Dapper repozitáře - -Následující kód implementuje repozitář `Person`, který vyžaduje `DbContext` z EF Core (MyAppDbContext). Můžete vložit `PersonDapperRepository` k volání jeho metod. - -`DbConnection` a `DbTransaction` jsou ze základní třídy `DapperRepository`. - -```C# -public class PersonDapperRepository : DapperRepository, ITransientDependency -{ - public PersonDapperRepository(IDbContextProvider dbContextProvider) - : base(dbContextProvider) - { - } - - public virtual async Task> GetAllPersonNames() - { - return (await DbConnection.QueryAsync("select Name from People", transaction: DbTransaction)) - .ToList(); - } - - public virtual async Task UpdatePersonNames(string name) - { - return await DbConnection.ExecuteAsync("update People set Name = @NewName", new { NewName = name }, - DbTransaction); - } -} -``` diff --git a/docs/cs/Domain-Driven-Design.md b/docs/cs/Domain-Driven-Design.md deleted file mode 100644 index 161e92c8a2..0000000000 --- a/docs/cs/Domain-Driven-Design.md +++ /dev/null @@ -1,33 +0,0 @@ -# Domain Driven Design - -## Co je DDD? - -ABP framework poskytuje **infrastrukturu**, která zjednodušuje implementaci vývoje založeného na **DDD**. DDD je [definován ve Wikipedii](https://en.wikipedia.org/wiki/Domain-driven_design) takto: - -> **Domain-driven design** (**DDD**) je přístup k vývoji softwaru pro komplexní potřeby propojením implementace s vyvíjejícím se modelem. Předpoklad DDD je následující: -> -> - Primární zaměření projektu je na jádře domény a doménové logice; -> - Zakládání komplexních návrhů na modelu domény; -> - Iniciování tvůrčí spolupráce mezi technickými a doménovými odborníky s cílem iterativně zdokonalit koncepční model, který řeší konkrétní problémy v doméně. - -### Vrstvy - -ABP dodržuje principy a vzorce DDD pro dosažení vrstveného aplikačního modelu, který se skládá ze čtyř základních vrstev: - -- **Prezentační vrstva**: Poskytuje uživateli rozhraní. Používá *Aplikační vrstvu* k dosažení uživatelských interakcí. -- **Aplikační vrstva**: Prostředník mezi prezentační a doménovou vrstvou. Instrumentuje business objekty k provádění specifických úloh aplikace. Implementuje případy použití jako logiku aplikace. -- **Doménová vrstva**: Zahrnuje business objekty a jejich business pravidla. Je jádrem aplikace. -- **Vrstva infrastruktury**: Poskytuje obecné technické možnosti, které podporují vyšší vrstvy většinou pomocí knihoven třetích stran. - -## Obsah - -* **Doménová vrstva** - * [Entity & agregované kořeny](Entities.md) - * Hodnotové objekty - * [Repozitáře](Repositories.md) - * Doménové služby - * Specifikace -* **Aplikační vrstva** - * [Aplikační služby](Application-Services.md) - * [Objekty přenosu dat (DTOs)](Data-Transfer-Objects.md) - * Jednotka práce \ No newline at end of file diff --git a/docs/cs/Entity-Framework-Core-PostgreSQL.md b/docs/cs/Entity-Framework-Core-PostgreSQL.md deleted file mode 100644 index dc50c8a742..0000000000 --- a/docs/cs/Entity-Framework-Core-PostgreSQL.md +++ /dev/null @@ -1,39 +0,0 @@ -# Přepnutí na EF Core PostgreSQL providera - -Tento dokument vysvětluje, jak přepnout na poskytovatele databáze **PostgreSQL** pro **[spouštěcí šablonu aplikace](Startup-Templates/Application.md)**, která je dodávána s předem nakonfigurovaným SQL poskytovatelem. - -## Výměna balíku Volo.Abp.EntityFrameworkCore.SqlServer - -Projekt `.EntityFrameworkCore` v řešení závisí na NuGet balíku [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer). Odstraňte tento balík a přidejte stejnou verzi balíku [Volo.Abp.EntityFrameworkCore.PostgreSql](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.PostgreSql). - -## Nahrazení závislosti modulu - -Najděte třídu ***YourProjectName*EntityFrameworkCoreModule** v projektu `.EntityFrameworkCore`, odstraňte `typeof(AbpEntityFrameworkCoreSqlServerModule)` z atributu `DependsOn`, přidejte `typeof(AbpEntityFrameworkCorePostgreSqlModule)` (také nahraďte `using Volo.Abp.EntityFrameworkCore.SqlServer;` za `using Volo.Abp.EntityFrameworkCore.PostgreSql;`). - -## UseNpgsql() - -Najděte volání `UseSqlServer()` v *YourProjectName*EntityFrameworkCoreModule.cs uvnitř projektu `.EntityFrameworkCore` a nahraďte za `UseNpgsql()`. - -Najděte volání `UseSqlServer()` v *YourProjectName*MigrationsDbContextFactory.cs uvnitř projektu `.EntityFrameworkCore.DbMigrations` a nahraďte za `UseNpgsql()`. - -> V závislosti na struktuře řešení můžete najít více volání `UseSqlServer()`, které je třeba změnit. - -## Změna connection stringů - -PostgreSql connection stringy se od těch pro SQL Server liší. Je proto potřeba zkontrolovat všechny soubory `appsettings.json` v řešení a connection stringy v nich nahradit. Podívejte se na [connectionstrings.com](https://www.connectionstrings.com/postgresql/) pro více detailů o možnostech PostgreSql connection stringů. - -Typicky je potřeba změnit `appsettings.json` v projektech `.DbMigrator` a `.Web` projects, ale to záleží na vaší struktuře řešení. - -## Regenerace migrací - -Startovací šablona používá [Entity Framework Core Code First migrace](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core migrace závisí na zvoleném DBMS poskytovateli. Tudíž změna DBMS poskytovatele způsobí selhání migrace. -* Smažte složku Migrations v projektu `.EntityFrameworkCore.DbMigrations` and znovu sestavte řešení. -* Spusťte `Add-Migration "Initial"` v Package Manager Console (je nutné zvolit `.DbMigrator` (nebo `.Web`) projekt jako startovací projekt v Solution Explorer a zvolit projekt `.EntityFrameworkCore.DbMigrations` jako výchozí v Package Manager Console). - -Tímto vytvoříte migraci databáze se všemi nakonfigurovanými databázovými objekty (tabulkami). - -Spusťte projekt `.DbMigrator` k vytvoření databáze a vložení počátečních dat. - -## Spuštění aplikace - -Vše je připraveno. Stačí už jen spustit aplikaci a užívat si kódování. diff --git a/docs/cs/Getting-Started-Angular-Template.md b/docs/cs/Getting-Started-Angular-Template.md deleted file mode 100644 index 076fb45671..0000000000 --- a/docs/cs/Getting-Started-Angular-Template.md +++ /dev/null @@ -1,126 +0,0 @@ -## Začínáme s Angular aplikační šablonou - -Tento tutoriál vysvětluje, jak vytvořit novou Angular aplikaci pomocí spouštěcí šablony, jak ji nakonfigurovat a spustit. - -### Tvorba nového projektu - -Tento tutorial používá k vytvoření nového projektu **ABP CLI**. Podívejte se na stránku [začínáme](https://abp.io/get-started) pro více možností. - -Pokud jste tak dosud neučinili, nainstalujte ABP CLI pomocí okna příkazového řádku: - -````bash -dotnet tool install -g Volo.Abp.Cli -```` - -Použíjte příkaz `abp new` v prázdné složce k vytvoření Vašeho projektu: - -````bash -abp new Acme.BookStore -u angular -```` - -> Můžete použít různé úrovně jmenných prostorů; např. BookStore, Acme.BookStore nebo Acme.Retail.BookStore. - -`-u angular` volba specifikuje Angular jako UI framework. Výchozí poskytovatel databáze je EF Core. Podívejte se na [CLI dokumentaci](CLI.md) pro všechny dostupné možnosti. - -#### Předběžné požadavky - -Vytvořené řešení vyžaduje; - -* [Visual Studio 2019 (v16.4.0+)](https://visualstudio.microsoft.com/vs/) -* [.NET Core 3.0+](https://www.microsoft.com/net/download/dotnet-core/) -* [Node v12+](https://nodejs.org) -* [Yarn v1.19+](https://classic.yarnpkg.com/) - -### Struktura řešení - -Otevřete řešení ve **Visual Studio**: - -![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-for-spa.png) - -Řešení má vrstvenou strukturu (založenou na [domain driven designu](Domain-Driven-Design.md)) a obsahuje projekty testů jednotek a integrace správně nakonfigurované pro práci s **EF Core** & **SQLite in-memory** databází. - -> Podívejte se na [dokument šablony aplikace](Startup-Templates/Application.md) k detailnímu pochopení struktury řešení. - -### Databázový connection string - -Zkontrolujte **connection string** v souboru `appsettings.json` u projektu `.HttpApi.Host`: - -````json -{ - "ConnectionStrings": { - "Default": "Server=localhost;Database=BookStore;Trusted_Connection=True" - } -} -```` - -Řešení je nakonfigurováno pro použití **Entity Framework Core** s **MS SQL Server**. EF Core podporuje [různé](https://docs.microsoft.com/en-us/ef/core/providers/) poskytovatele databáze, takže pokud chcete můžete použít jiný DBMS. V případě potřeby změňte connection string. - -### Tvorba databáze & aplikace migrací databáze - -K vytvoření databáze máte dvě možnosti. - -#### Použití aplikace DbMigrator - -Řešení obsahuje konzolovou aplikaci (v tomto příkladu nazvanou `Acme.BookStore.DbMigrator`), která dokáže vytvořit databázi, aplikovat migrace a vložit počáteční data. Ta je užitečná jak pro vývojové tak pro produkční prostředí. - -> `.DbMigrator` má vlastní `appsettings.json`. Pokud jste změnili connection string výše, měli byste změnit i tento. - -Klikněte pravým na projekt `.DbMigrator` zvolte **Set as StartUp Project**: - -![set-as-startup-project](images/set-as-startup-project.png) - -Zmáčkněte F5 (nebo Ctrl+F5) ke spuštění aplikace. Výstup by měl být podobný vyobrazení níže: - -![set-as-startup-project](images/db-migrator-app.png) - -#### Použití příkazu EF Core Update-Database - -Ef Core máš příkaz `Update-Database`, který v případě potřeby vytvoří databázi a aplikuje čekající migrace. Klikněte pravým na projekt `.HttpApi.Host` a zvolte **Set as StartUp Project**: - -![set-as-startup-project](images/set-as-startup-project.png) - -Otevřete **Package Manager Console**, zvolte `.EntityFrameworkCore.DbMigrations` jako **Default Project** a proveďte příkaz `Update-Database`: - -![pcm-update-database](images/pcm-update-database-v2.png) - -Tímto vytvoříte novou databáze podle nakonfigurovaného connection string. - -> Je doporučeno užití nástroje `.DbMigrator`, protože zároveň vloží i počáteční data ke správnému běhu webové aplikace. - -### Spuštění aplikace - -#### Spuštění API Host (na straně serveru) - -Ujistěte se že je projekt `.HttpApi.Host` nastaven jako startovací a spusťte aplikaci což otevře Swagger UI: - -![bookstore-homepage](images/bookstore-swagger-ui-host.png) - -Tady můžete vidět API aplikace a zároveň je i otestovat. Získejte [více informací](https://swagger.io/tools/swagger-ui/) o Swagger UI. - -##### Autorizace pro Swagger UI - -Vetšina API aplikace vyžaduje autentizaci & autorizaci. Pokud chcete otestovat autorizované API, manuálně přejděte na stránku `/Account/Login`, vložte `admin` jako uživatelské jméno a `1q2w3E*` jako heslo k příhlášení do aplikace. Poté budete moci provádět autorizované požadavky API. - -#### Spuštění Angular aplikace (na straně klienta) - -Přejděte do složky `angular`, otevřete terminál příkazového řádku, proveďte příkaz `yarn` (doporučujeme používat správce balíků [yarn](https://yarnpkg.com), npm install bude v mnoha případech také fungovat): - -````bash -yarn -```` - -Jakmile jsou načteny všechny node moduly, proveďte příkaz `yarn start` nebo `npm start`: - -````bash -yarn start -```` - -Otevřete Váš oblíbený prohlížeč a přejděte na adresu `localhost:4200`. Počáteční uživatelské jméno je `admin` a heslo `1q2w3E*`. - -Startovací šablona obsahuje moduly **správa identit** a **správa tenantů**. Jakmile se přihlásíte, zprístupní se administrační menu kde můžete spravovat **tenanty**, **role**, **uživatele** a jejich **oprávnění**. - -> Doporučujeme [Visual Studio Code](https://code.visualstudio.com/) jako editor pro Angular projekt, ale klidně použijte Váš oblíbený editor. - -### Co dále? - -* [Tutoriál vývoje aplikace](Tutorials/Angular/Part-I.md) diff --git a/docs/cs/Getting-Started-AspNetCore-Application.md b/docs/cs/Getting-Started-AspNetCore-Application.md deleted file mode 100644 index e269a08ba2..0000000000 --- a/docs/cs/Getting-Started-AspNetCore-Application.md +++ /dev/null @@ -1,157 +0,0 @@ -# Začínáme s ASP.NET Core MVC aplikací - -Tento tutoriál vysvětluje jak začít s ABP z ničeho s minimem závislostí. Obvykle chcete začít se **[startovací šablonou](https://abp.io/Templates)**. - -## Tvorba nového projektu - -1. Vytvořte novou AspNet Core Web aplikaci ve Visual Studio 2019 (16.4.0+): - -![](images/create-new-aspnet-core-application-v2.png) - -2. Nakonfigurujte váš nový projekt: - -![](images/select-empty-web-application-v2.png) - -3. Potvrďte kliknutím na tlačítko vytvořit - -![create-aspnet-core-application](images/create-aspnet-core-application.png) - -## Instalace Volo.Abp.AspNetCore.Mvc balíku - -Volo.Abp.AspNetCore.Mvc je AspNet Core MVC integrační balík pro ABP. Takže ho nainstalujeme do projektu: - -```` -Install-Package Volo.Abp.AspNetCore.Mvc -```` - -## Tvorba prvního ABP modulu - -ABP je modulární framework a proto vyžaduje **spouštěcí (kořenový) modul** což je třída dědící z ``AbpModule``: - -````C# -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Hosting; -using Volo.Abp; -using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.Modularity; - -namespace BasicAspNetCoreApplication -{ - [DependsOn(typeof(AbpAspNetCoreMvcModule))] - public class AppModule : AbpModule - { - public override void OnApplicationInitialization( - ApplicationInitializationContext context) - { - var app = context.GetApplicationBuilder(); - var env = context.GetEnvironment(); - - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Error"); - } - - app.UseStaticFiles(); - app.UseRouting(); - app.UseConfiguredEndpoints(); - } - } -} -```` - -``AppModule`` je dobrý název pro spouštěcí modul aplikace. - -ABP balíky definují modulové třídy a modul může mít závislost na jiném. V kódu výše, ``AppModule`` má závislost na ``AbpAspNetCoreMvcModule`` (definován v balíku [Volo.Abp.AspNetCore.Mvc](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Mvc)). Je běžné přidat ``DependsOn`` atribute po instalaci nového ABP NuGet balíku. - -Místo třídy Startup, konfigurujeme ASP.NET Core pipeline v této modulové třídě. - -## Třída Startup - -V dalším kroku upravíme Startup třídu k integraci ABP modulového systému: - -````C# -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; - -namespace BasicAspNetCoreApplication -{ - public class Startup - { - public void ConfigureServices(IServiceCollection services) - { - services.AddApplication(); - } - - public void Configure(IApplicationBuilder app) - { - app.InitializeApplication(); - } - } -} -```` - -``services.AddApplication()`` přidává všechny služby definované ve všech modulech počínaje od ``AppModule``. - -``app.InitializeApplication()`` v metodě ``Configure`` inicializuje a spustí aplikaci. - -## Spusťte aplikaci! - -To je vše! Spusťte aplikaci, bude fungovat podle očekávání. - -## Použití Autofac jako frameworku pro vkládání závislostí - -Ačkoliv je AspNet Core systém pro vkládání závíslostí (DI) dostatečný pro základní požadavky, [Autofac](https://autofac.org/) poskytuje pokročilé funkce jako injekce vlastností nebo záchyt metod, které jsou v ABP užity k provádění pokročilých funkcí frameworku. - -Nahrazení AspNet Core DI systému za Autofac a integrace s ABP je snadná. - -1. Nainstalujeme [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) balík - -```` -Install-Package Volo.Abp.Autofac -```` - -2. Přidáme ``AbpAutofacModule`` závislost - -````C# -[DependsOn(typeof(AbpAspNetCoreMvcModule))] -[DependsOn(typeof(AbpAutofacModule))] // Přidá závislost na AbpAutofacModule -public class AppModule : AbpModule -{ - ... -} -```` - -3. Upravíme `Program.cs` aby používal Autofac: - -````csharp -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; - -namespace BasicAspNetCoreApplication -{ - public class Program - { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }) - .UseAutofac(); // Přidejte tento řádek - } -} -```` - -## Zdrojový kód - -Získejte zdrojový kód vzorového projektu vytvořeného v tomto tutoriálů [z tohoto odkazu](https://github.com/abpframework/abp-samples/tree/master/BasicAspNetCoreApplication). - diff --git a/docs/cs/Getting-Started-AspNetCore-MVC-Template.md b/docs/cs/Getting-Started-AspNetCore-MVC-Template.md deleted file mode 100644 index c053e1d76a..0000000000 --- a/docs/cs/Getting-Started-AspNetCore-MVC-Template.md +++ /dev/null @@ -1,104 +0,0 @@ -## Začínáme s ASP.NET Core MVC šablonou - -Tento tutoriál vysvětluje, jak vytvořit novou ASP.NET Core MVC webovou aplikaci pomocí úvodní šablony, jak ji nakonfigurovat a spustit. - -### Tvorba nového projektu - -Tento tutoriál používá k tvorbě nového projektu **ABP CLI**. Podívejte se na stránku [Začínáme](https://abp.io/get-started) pro více možností. - -Pokud ještě nemáte ABP CLI nainstalováno, učiňte tak pomocí okna příkazového řádku: - -````bash -dotnet tool install -g Volo.Abp.Cli -```` - -K tvorbě vašeho projektu použijte příkaz `abp new` v prázdné složce: - -````bash -abp new Acme.BookStore -```` - -> Můžete použít různé úrovně jmenných prostorů; např. BookStore, Acme.BookStore nebo Acme.Retail.BookStore. - -Příkaz `new` vytvoří **vrstvenou MVC aplikaci** s **Entity Framework Core** jako databázovým poskytovatelem. Jsou zde však i jiné možnosti. Podívejte se na [CLI dokumnentaci](CLI.md) pro všechny další možností. - -#### Požadavky - -Vytvořené řešení vyžaduje; - -* [Visual Studio 2019 (v16.4.0+)](https://visualstudio.microsoft.com/vs/) -* [.NET Core 3.0+](https://www.microsoft.com/net/download/dotnet-core/) -* [Node v12+](https://nodejs.org) -* [Yarn v1.19+](https://classic.yarnpkg.com/) - -### Struktura řešení - -Otevřete řešení ve **Visual Studio**: - -![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v3.png) - -Řešení má vrstvenou strukturu (založenou na [Domain Driven Design](Domain-Driven-Design.md)) a obsahuje projekty jednotkovových a integračních testů předkonfigurované pro práci s **EF Core** & **SQLite in-memory** databází. - -> Podívejte se na [dokument šablony aplikace](Startup-Templates/Application.md) k detailnímu pochopení struktury řešení. - -### Connection string databáze - -Zkontrolujte **connection string** v souboru `appsettings.json` v projektu `.Web`: - -````json -{ - "ConnectionStrings": { - "Default": "Server=localhost;Database=BookStore;Trusted_Connection=True" - } -} -```` - -Řešení je nakonfigurováno k používání **Entity Framework Core** s **MS SQL Server**. EF Core podporuje [různé](https://docs.microsoft.com/en-us/ef/core/providers/) databázové poskytovatele, takže můžete použít i jiné DBMS. V případě potřeby změňte connection string. - -### Tvorba databáze & aplikace databázových migrací - -K vytvoření databáze máte dvě možnosti. - -#### Použití DbMigrator aplikace - -Řešení obsahuje konzolovou aplikaci (v tomto příkladu nazvanou `Acme.BookStore.DbMigrator`), která může vytvářet databáze, aplikovat migrace a vkládat seed data. Je užitečná jak pro vývojové, tak pro produkční prostředí. - -> Projekt `.DbMigrator` má vlastní `appsettings.json`. Takže pokud jste změnili connection string uvedený výše, musíte změnit také tento. - -Klikněte pravým na projekt `.DbMigrator` a vyberte **Set as StartUp Project**: - -![set-as-startup-project](images/set-as-startup-project.png) - -Zmáčkněte F5 (nebo Ctrl+F5) ke spuštění aplikace. Výstup bude vypadat následovně: - -![set-as-startup-project](images/db-migrator-app.png) - -#### Použití EF Core Update-Database příkazu - -Ef Core má `Update-Database` příkaz, který v případě potřeby vytvoří databázi a aplikuje čekající migrace. Klikněte pravým na projekt `.Web` a vyberte **Set as StartUp Project**: - -![set-as-startup-project](images/set-as-startup-project.png) - -Otevřete **Package Manager Console**, vyberte projekt `.EntityFrameworkCore.DbMigrations` jako **Default Project** and spusťte příkaz `Update-Database`: - -![pcm-update-database](images/pcm-update-database-v2.png) - -Dojde k vytvoření nové databáze na základě nakonfigurovaného connection stringu. - -> Použití nástroje `.Migrator` je doporučený způsob, jelikož zároveň vloží seed data nutné k správnému běhu webové aplikace. - -### Spuštění aplikace - -Ujistěte se že je projekt `.Web` nastaven jako startovací projekt. Spusťte aplikaci což následně otevře **úvodní** stránku ve vašem prohlížeči: - -![bookstore-homepage](images/bookstore-homepage.png) - -Klikněte na tlačítko **Přihlásit**, vložte `admin` jako uživatelské jméno a `1q2w3E*` jako heslo k přihlášení do aplikace. - -Startovací šabloná obsahuje **identity management** a **tenant management** moduly. Jakmile se přihlásite, budete mít přístup do nabídky Administrace, kde můžete spravovat **tenanty**, **role**, **uživatele** a jejich **oprávnění**. Správa uživatelů vypadá takto: - -![bookstore-user-management](images/bookstore-user-management-v2.png) - -### Co dále? - -* [Tutoriál vývoje aplikace](Tutorials/AspNetCore-Mvc/Part-I.md) diff --git a/docs/cs/Getting-Started-Console-Application.md b/docs/cs/Getting-Started-Console-Application.md deleted file mode 100644 index a6ee50dbe6..0000000000 --- a/docs/cs/Getting-Started-Console-Application.md +++ /dev/null @@ -1,181 +0,0 @@ -# Začínáme s konzolovou aplikací - -Tento tutoriál vysvětluje jak začít s ABP z ničeho s minimem závislostí. Obvykle chcete začít se **[startovací šablonou](https://abp.io/Templates)**. - -## Tvorba nového projektu - -Vytvořte regulérní .NET Core konzolovou aplikaci z Visual Studio: - -![](images/create-new-net-core-console-application.png) - -## Instalace Volo.Abp balíku - -Volo.Abp.Core je základní NuGet balík k tvorbě aplikací založených na ABP. Takže ho nainstalujeme do projektu: - -```` -Install-Package Volo.Abp.Core -```` - -## Tvorba prvního ABP modulu - -ABP je modulární framework a proto vyžaduje **spouštěcí (kořenový) modul** což je třída dědící z ``AbpModule``: - -````C# -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Modularity; - -namespace AbpConsoleDemo -{ - public class AppModule : AbpModule - { - - } -} -```` - -``AppModule`` je dobrý název pro spouštěcí modul aplikace. - -## Inicializace aplikace - -Dalším krokem je bootstrap aplikace pomocí spouštěcího modulu vytvořeného výše: - -````C# -using System; -using Volo.Abp; - -namespace AbpConsoleDemo -{ - class Program - { - static void Main(string[] args) - { - using (var application = AbpApplicationFactory.Create()) - { - application.Initialize(); - - Console.WriteLine("Press ENTER to stop application..."); - Console.ReadLine(); - } - } - } -} - -```` - -``AbpApplicationFactory`` se používá k vytvoření aplikace a načtení všech modulů, s využitím ``AppModule`` jako spouštěcím modulem. ``Initialize()`` metoda spouští aplikaci. - -## Ahoj světe! - -Aplikace výše zatím nic nedělá. Pojďme proto vytvořit službu která už něco dělá: - -````C# -using System; -using Volo.Abp.DependencyInjection; - -namespace AbpConsoleDemo -{ - public class HelloWorldService : ITransientDependency - { - public void SayHello() - { - Console.WriteLine("Hello World!"); - } - } -} - -```` - -``ITransientDependency`` je speciální rozhraní ABP, které automaticky registruje službu jako přechodnou (více v [dokumentu vkládání závislostí](Dependency-Injection.md)). - -Nyní můžeme vyřešit ``HelloWorldService`` a vypsat naše ahoj. Změníme Program.cs podle vyobrazení níže: - -````C# -using System; -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp; - -namespace AbpConsoleDemo -{ - class Program - { - static void Main(string[] args) - { - using (var application = AbpApplicationFactory.Create()) - { - application.Initialize(); - - // Vyřeší službu a použije ji - var helloWorldService = - application.ServiceProvider.GetService(); - helloWorldService.SayHello(); - - Console.WriteLine("Press ENTER to stop application..."); - Console.ReadLine(); - } - } - } -} -```` - -I když je to dostačující pro tento jednoduchý príklad kódu, je vždy lepší v případě přímého řešení závislostí z ``IServiceProvider`` vytvořit rámce (více v [dokumentu vkládání závislostí](Dependency-Injection.md)). - -## Využití Autofac jako frameworku pro vkládání závislostí - -Ačkoliv je AspNet Core systém pro vkládání závíslostí (DI) skvělý pro základní požadavky, Autofac poskytuje pokročilé funkce jako injekce vlastností nebo záchyt metod, které jsou v ABP užity k provádění pokročilých funkcí frameworku. - -Nahrazení AspNet Core DI systému za Autofac a integrace s ABP je snadná. - -1. Nainstalujeme [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) balík - -``` -Install-Package Volo.Abp.Autofac -``` - -1. Přidáme ``AbpAutofacModule`` závislost - -```c# -[DependsOn(typeof(AbpAutofacModule))] // Přidá závislost na AbpAutofacModule -public class AppModule : AbpModule -{ - -} -``` - -1. Změníme soubor ``Program.cs`` podle vyobrazení níže: - -```c# -using System; -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp; - -namespace AbpConsoleDemo -{ - class Program - { - static void Main(string[] args) - { - using (var application = AbpApplicationFactory.Create(options => - { - options.UseAutofac(); // Autofac integrace - })) - { - application.Initialize(); - - // Vyřeší službu a použije ji - var helloWorldService = - application.ServiceProvider.GetService(); - helloWorldService.SayHello(); - - Console.WriteLine("Press ENTER to stop application..."); - Console.ReadLine(); - } - } - } -} -``` - -Stačí volat metodu `options.UseAutofac()` v možnostech `AbpApplicationFactory.Create`. - -## Zdrojový kód - -Získejte zdrojový kód vzorového projektu vytvořeného v tomto tutoriálů [z tohoto odkazu](https://github.com/abpframework/abp-samples/tree/master/BasicConsoleApplication). diff --git a/docs/cs/Index.md b/docs/cs/Index.md deleted file mode 100644 index 875f4e066e..0000000000 --- a/docs/cs/Index.md +++ /dev/null @@ -1,25 +0,0 @@ -# ABP dokumentace - -ABP je **open source aplikační framework** se zaměřením na vývoj webových aplikací založených na ASP.NET Core, zároveň ho však lze využít i k vývoji jiných typů aplikací. - -K procházení dokumentace využijte navigační nabídky vlevo. - -## Začínáme - -Nejsnazší cestou jak začít nový projekt s ABP je užití startovací šablony: - -* [ASP.NET Core MVC (Razor Pages) UI Počáteční Šablona](Getting-Started-AspNetCore-MVC-Template.md) -* [Angular UI Počáteční Šablona](Getting-Started-Angular-Template.md) - -Pokud chcete začít od nuly (s prázdným projektem) tak manuálně nainstalujte ABP Framework s pomocí následujících tutoriálů: - -* [Konzolová Aplikace](Getting-Started-Console-Application.md) -* [ASP.NET Core Web Aplikace](Getting-Started-AspNetCore-Application.md) - -## Zdrojový kód - -ABP je hostovaný na GitHub. Zobrazit [zdrojový kód](https://github.com/abpframework/abp). - -## Chcete přispět? - -ABP je komunitně řízený open source projekt. Podívejte se na [průvodce pro přispěvatele](Contribution/Index.md) pokud chcete být součástí tohoto projektu. diff --git a/docs/cs/Nightly-Builds.md b/docs/cs/Nightly-Builds.md deleted file mode 100644 index e69588f5ff..0000000000 --- a/docs/cs/Nightly-Builds.md +++ /dev/null @@ -1,26 +0,0 @@ -# Noční sestavení - -Všechny balíky frameworku a modulů jsou každý večer nasazeny na MyGet. Takže můžete používat nebo testovat nejnovější kód bez čekání na další vydání. - -## Konfigurace Visual Studia - -> Vyžaduje Visual Studio 2017+ - -1. Přejděte do `Tools > Options > NuGet Package Manager > Package Source`. -2. Klikněte na zelenou ikonku `+`. -3. Nastavte `ABP Nightly` jako *Name* a `https://www.myget.org/F/abp-nightly/api/v3/index.json` jako *Source* podle vyobrazení níže: - ![night-build-add-nuget-source](images/night-build-add-nuget-source.png) -4. Klikněte na `Update`. -5. Klikněte na `OK` k uložení změn. - -## Instalace balíku - -Nyní můžete instalovat náhledové / noční balíky do Vašeho projektu z NuGet prohlížeče nebo Package Manager Console. - -![night-build-add-nuget-package](images/night-build-add-nuget-package.png) - -1. V nuget prohlížeči, vyberte "Include prereleases". -2. Změňte zdroj balíků na "All". -3. Vyhledejte balík. Uvidíte prerelease balík formátovaný jako `(VERZE)-preview(DATUM)` (např *v0.16.0-preview20190401* jako v tomto vzorku). -4. Můžete kliknout na `Install` k přídání balíku do projektu. - diff --git a/docs/cs/docs-nav.json b/docs/cs/docs-nav.json deleted file mode 100644 index 6c05d77dcf..0000000000 --- a/docs/cs/docs-nav.json +++ /dev/null @@ -1,376 +0,0 @@ -{ - "items": [ - { - "text": "Začínáme", - "items": [ - { - "text": "Ze startovacích šablon", - "items": [ - { - "text": "Aplikace s MVC (Razor Pages) UI", - "path": "Getting-Started-AspNetCore-MVC-Template.md" - }, - { - "text": "Aplikace s Angular UI", - "path": "Getting-Started-Angular-Template.md" - } - ] - }, - { - "text": "Z prázdných projektů", - "items": [ - { - "text": "S ASP.NET Core Web aplikací", - "path": "Getting-Started-AspNetCore-Application.md" - }, - { - "text": "S konzolovou aplikací", - "path": "Getting-Started-Console-Application.md" - } - ] - } - ] - }, - { - "text": "Tutoriály", - "items": [ - { - "text": "Vývoj aplikace", - "items": [ - { - "text": "S ASP.NET Core MVC UI", - "path": "Tutorials/AspNetCore-Mvc/Part-I.md" - }, - { - "text": "S Angular UI", - "path": "Tutorials/Angular/Part-I.md" - } - ] - } - ] - }, - { - "text": "CLI", - "path": "CLI.md" - }, - { - "text": "Základy", - "items": [ - { - "text": "Konfigurace", - "path": "Configuration.md" - }, - { - "text": "Možnosti", - "path": "Options.md" - }, - { - "text": "Vkládání závislostí", - "path": "Dependency-Injection.md", - "items": [ - { - "text": "AutoFac integrace", - "path": "Autofac-Integration.md" - } - ] - }, - { - "text": "Virtuální systém souborů", - "path": "Virtual-File-System.md" - }, - { - "text": "Lokalizace", - "path": "Localization.md" - }, - { - "text": "Zpracování výjimek", - "path": "Exception-Handling.md" - }, - { - "text": "Validace", - "path": "Validation.md", - "items": [ - { - "text": "FluentValidation integrace", - "path": "FluentValidation.md" - } - ] - }, - { - "text": "Autorizace", - "path": "Authorization.md" - }, - { - "text": "Ukládání do mezipaměti", - "path": "Caching.md" - }, - { - "text": "Audit" - }, - { - "text": "Nastavení", - "path": "Settings.md" - } - ] - }, - { - "text": "Události", - "items": [ - { - "text": "Event bus (místní)" - }, - { - "text": "Distribuovaný event bus", - "items": [ - { - "text": "RabbitMQ integrace" - } - ] - } - ] - }, - { - "text": "Služby", - "items": [ - { - "text": "Současný uživatel", - "path": "CurrentUser.md" - }, - { - "text": "Mapování objekt na objekt", - "path": "Object-To-Object-Mapping.md" - }, - { - "text": "Serializace objektu" - }, - { - "text": "Serializace JSON" - }, - { - "text": "Emailování" - }, - { - "text": "GUIDy" - }, - { - "text": "Vláknování" - }, - { - "text": "Časování" - } - ] - }, - { - "text": "Multitenance", - "path": "Multi-Tenancy.md" - }, - { - "text": "Vývoj modulů", - "items": [ - { - "text": "Základy", - "path": "Module-Development-Basics.md" - }, - { - "text": "Zásuvné moduly" - }, - { - "text": "Nejlepší praktiky", - "path": "Best-Practices/Index.md" - } - ] - }, - { - "text": "Domain driven design", - "path": "Domain-Driven-Design.md", - "items": [ - { - "text": "Doménová vrstva", - "items": [ - { - "text": "Entity & agregované kořeny", - "path": "Entities.md" - }, - { - "text": "Hodnotové objekty" - }, - { - "text": "Repozitáře", - "path": "Repositories.md" - }, - { - "text": "Doménové služby" - }, - { - "text": "Specifikace" - } - ] - }, - { - "text": "Aplikační vrstva", - "items": [ - { - "text": "Aplikační služby", - "path": "Application-Services.md" - }, - { - "text": "Objekty přenosu dat" - }, - { - "text": "Jednotka práce" - } - ] - } - ] - }, - { - "text": "ASP.NET Core", - "items": [ - { - "text": "API", - "items": [ - { - "text": "Automatické API řadiče", - "path": "AspNetCore/Auto-API-Controllers.md" - }, - { - "text": "Dynamičtí C# API klienti", - "path": "AspNetCore/Dynamic-CSharp-API-Clients.md" - } - ] - }, - { - "text": "Uživatelské rozhraní", - "items": [ - { - "text": "Správa klientských balíčků", - "path": "AspNetCore/Client-Side-Package-Management.md" - }, - { - "text": "Svazování & minifikace", - "path": "AspNetCore/Bundling-Minification.md" - }, - { - "text": "Tag pomocníci", - "path": "AspNetCore/Tag-Helpers/Index.md" - }, - { - "text": "Widgety", - "path": "AspNetCore/Widgets.md" - }, - { - "text": "Motivy", - "path": "AspNetCore/Theming.md" - } - ] - } - ] - }, - { - "text": "Přístup k datům", - "path": "Data-Access.md", - "items": [ - { - "text": "Connection stringy", - "path": "Connection-Strings.md" - }, - { - "text": "Poskytovatelé databází", - "items": [ - { - "text": "Entity Framework Core", - "path": "Entity-Framework-Core.md", - "items": [ - { - "text": "Přepnutí na MySQL", - "path": "Entity-Framework-Core-MySQL.md" - }, - { - "text": "Přepnutí na PostgreSQL", - "path": "Entity-Framework-Core-PostgreSQL.md" - }, - { - "text": "Přepnutí na SQLite", - "path": "Entity-Framework-Core-SQLite.md" - }, - { - "text": "Přepnutí na jiný DBMS", - "path": "Entity-Framework-Core-Other-DBMS.md" - } - ] - }, - { - "text": "MongoDB", - "path": "MongoDB.md" - }, - { - "text": "Dapper", - "path": "Dapper.md" - } - ] - } - ] - }, - { - "text": "Pozadí", - "items": [ - { - "text": "Úkony na pozadí", - "path": "Background-Jobs.md", - "items": [ - { - "text": "Hangfire integrace", - "path": "Background-Jobs-Hangfire.md" - }, - { - "text": "RabbitMQ integrace", - "path": "Background-Jobs-RabbitMq.md" - } - ] - } - ] - }, - { - "text": "Startovací šablony", - "path": "Startup-Templates/Index.md", - "items": [ - { - "text": "Aplikace", - "path": "Startup-Templates/Application.md" - }, - { - "text": "Modul", - "path": "Startup-Templates/Module.md" - } - ] - }, - { - "text": "Vzorky", - "items": [ - { - "text": "Mikroslužby demo", - "path": "Samples/Microservice-Demo.md" - } - ] - }, - { - "text": "Moduly aplikace", - "path": "Modules/Index.md" - }, - { - "text": "Architektura mikroslužby", - "path": "Microservice-Architecture.md" - }, - { - "text": "Testování" - }, - { - "text": "Noční sestavení", - "path": "Nightly-Builds.md" - }, - { - "text": "Průvodce pro přispěvatele", - "path": "Contribution/Index.md" - } - ] -} \ No newline at end of file diff --git a/docs/cs/images/MonthlyProfitWidgetFiles.png b/docs/cs/images/MonthlyProfitWidgetFiles.png deleted file mode 100644 index c3e4d6f1ab..0000000000 Binary files a/docs/cs/images/MonthlyProfitWidgetFiles.png and /dev/null differ diff --git a/docs/cs/images/authorization-new-permission-ui-hierarcy.png b/docs/cs/images/authorization-new-permission-ui-hierarcy.png deleted file mode 100644 index 07abfc7132..0000000000 Binary files a/docs/cs/images/authorization-new-permission-ui-hierarcy.png and /dev/null differ diff --git a/docs/cs/images/authorization-new-permission-ui-localized.png b/docs/cs/images/authorization-new-permission-ui-localized.png deleted file mode 100644 index 948fd618d9..0000000000 Binary files a/docs/cs/images/authorization-new-permission-ui-localized.png and /dev/null differ diff --git a/docs/cs/images/authorization-new-permission-ui.png b/docs/cs/images/authorization-new-permission-ui.png deleted file mode 100644 index 1190f04b70..0000000000 Binary files a/docs/cs/images/authorization-new-permission-ui.png and /dev/null differ diff --git a/docs/cs/images/bookstore-apis.png b/docs/cs/images/bookstore-apis.png deleted file mode 100644 index b7928c9637..0000000000 Binary files a/docs/cs/images/bookstore-apis.png and /dev/null differ diff --git a/docs/cs/images/bookstore-create-template.png b/docs/cs/images/bookstore-create-template.png deleted file mode 100644 index bae34a3b64..0000000000 Binary files a/docs/cs/images/bookstore-create-template.png and /dev/null differ diff --git a/docs/cs/images/bookstore-homepage.png b/docs/cs/images/bookstore-homepage.png deleted file mode 100644 index dc015aa67d..0000000000 Binary files a/docs/cs/images/bookstore-homepage.png and /dev/null differ diff --git a/docs/cs/images/bookstore-swagger-ui-host.png b/docs/cs/images/bookstore-swagger-ui-host.png deleted file mode 100644 index 7ebd8d8e37..0000000000 Binary files a/docs/cs/images/bookstore-swagger-ui-host.png and /dev/null differ diff --git a/docs/cs/images/bookstore-user-management-v2.png b/docs/cs/images/bookstore-user-management-v2.png deleted file mode 100644 index cd66010e05..0000000000 Binary files a/docs/cs/images/bookstore-user-management-v2.png and /dev/null differ diff --git a/docs/cs/images/bookstore-visual-studio-solution-for-spa.png b/docs/cs/images/bookstore-visual-studio-solution-for-spa.png deleted file mode 100644 index d114ed188c..0000000000 Binary files a/docs/cs/images/bookstore-visual-studio-solution-for-spa.png and /dev/null differ diff --git a/docs/cs/images/bookstore-visual-studio-solution-tiered.png b/docs/cs/images/bookstore-visual-studio-solution-tiered.png deleted file mode 100644 index 9affe841aa..0000000000 Binary files a/docs/cs/images/bookstore-visual-studio-solution-tiered.png and /dev/null differ diff --git a/docs/cs/images/bookstore-visual-studio-solution-v3.png b/docs/cs/images/bookstore-visual-studio-solution-v3.png deleted file mode 100644 index ce821eba72..0000000000 Binary files a/docs/cs/images/bookstore-visual-studio-solution-v3.png and /dev/null differ diff --git a/docs/cs/images/build-action-embedded-resource-sample.png b/docs/cs/images/build-action-embedded-resource-sample.png deleted file mode 100644 index 700e9921f4..0000000000 Binary files a/docs/cs/images/build-action-embedded-resource-sample.png and /dev/null differ diff --git a/docs/cs/images/create-aspnet-core-application.png b/docs/cs/images/create-aspnet-core-application.png deleted file mode 100644 index 03fde7e38a..0000000000 Binary files a/docs/cs/images/create-aspnet-core-application.png and /dev/null differ diff --git a/docs/cs/images/create-new-aspnet-core-application-v2.png b/docs/cs/images/create-new-aspnet-core-application-v2.png deleted file mode 100644 index d2bce84775..0000000000 Binary files a/docs/cs/images/create-new-aspnet-core-application-v2.png and /dev/null differ diff --git a/docs/cs/images/create-new-aspnet-core-application.png b/docs/cs/images/create-new-aspnet-core-application.png deleted file mode 100644 index 2c38289810..0000000000 Binary files a/docs/cs/images/create-new-aspnet-core-application.png and /dev/null differ diff --git a/docs/cs/images/create-new-net-core-console-application.png b/docs/cs/images/create-new-net-core-console-application.png deleted file mode 100644 index 0c2b3dbcb8..0000000000 Binary files a/docs/cs/images/create-new-net-core-console-application.png and /dev/null differ diff --git a/docs/cs/images/dashboard1.png b/docs/cs/images/dashboard1.png deleted file mode 100644 index 8c542b8786..0000000000 Binary files a/docs/cs/images/dashboard1.png and /dev/null differ diff --git a/docs/cs/images/db-migrator-app.png b/docs/cs/images/db-migrator-app.png deleted file mode 100644 index d2248d4588..0000000000 Binary files a/docs/cs/images/db-migrator-app.png and /dev/null differ diff --git a/docs/cs/images/docs-create-project.jpg b/docs/cs/images/docs-create-project.jpg deleted file mode 100644 index d2baa3242a..0000000000 Binary files a/docs/cs/images/docs-create-project.jpg and /dev/null differ diff --git a/docs/cs/images/docs-module_download-new-abp-project.png b/docs/cs/images/docs-module_download-new-abp-project.png deleted file mode 100644 index bc7aaacbd6..0000000000 Binary files a/docs/cs/images/docs-module_download-new-abp-project.png and /dev/null differ diff --git a/docs/cs/images/docs-module_download-sample-navigation-menu.png b/docs/cs/images/docs-module_download-sample-navigation-menu.png deleted file mode 100644 index 8d8eb42d52..0000000000 Binary files a/docs/cs/images/docs-module_download-sample-navigation-menu.png and /dev/null differ diff --git a/docs/cs/images/docs-module_solution-explorer.png b/docs/cs/images/docs-module_solution-explorer.png deleted file mode 100644 index 97bd3fc18e..0000000000 Binary files a/docs/cs/images/docs-module_solution-explorer.png and /dev/null differ diff --git a/docs/cs/images/docs-section-ui.png b/docs/cs/images/docs-section-ui.png deleted file mode 100644 index 1c63d1ad3a..0000000000 Binary files a/docs/cs/images/docs-section-ui.png and /dev/null differ diff --git a/docs/cs/images/github-access-token-private-repo.jpg b/docs/cs/images/github-access-token-private-repo.jpg deleted file mode 100644 index cb74f1eea3..0000000000 Binary files a/docs/cs/images/github-access-token-private-repo.jpg and /dev/null differ diff --git a/docs/cs/images/github-access-token-public-repo.jpg b/docs/cs/images/github-access-token-public-repo.jpg deleted file mode 100644 index d091a6d511..0000000000 Binary files a/docs/cs/images/github-access-token-public-repo.jpg and /dev/null differ diff --git a/docs/cs/images/github-myusername.jpg b/docs/cs/images/github-myusername.jpg deleted file mode 100644 index a723c17713..0000000000 Binary files a/docs/cs/images/github-myusername.jpg and /dev/null differ diff --git a/docs/cs/images/issuemanagement-module-solution.png b/docs/cs/images/issuemanagement-module-solution.png deleted file mode 100644 index d5f64b01d2..0000000000 Binary files a/docs/cs/images/issuemanagement-module-solution.png and /dev/null differ diff --git a/docs/cs/images/layered-project-dependencies-module.png b/docs/cs/images/layered-project-dependencies-module.png deleted file mode 100644 index de3b7a412f..0000000000 Binary files a/docs/cs/images/layered-project-dependencies-module.png and /dev/null differ diff --git a/docs/cs/images/layered-project-dependencies.png b/docs/cs/images/layered-project-dependencies.png deleted file mode 100644 index ed3e03fe4d..0000000000 Binary files a/docs/cs/images/layered-project-dependencies.png and /dev/null differ diff --git a/docs/cs/images/localization-resource-json-files.png b/docs/cs/images/localization-resource-json-files.png deleted file mode 100644 index 1a1d43403c..0000000000 Binary files a/docs/cs/images/localization-resource-json-files.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-authserver-home.png b/docs/cs/images/microservice-sample-authserver-home.png deleted file mode 100644 index 684fdb1a5a..0000000000 Binary files a/docs/cs/images/microservice-sample-authserver-home.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-authserver-login.png b/docs/cs/images/microservice-sample-authserver-login.png deleted file mode 100644 index 99d898ccd2..0000000000 Binary files a/docs/cs/images/microservice-sample-authserver-login.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-backend-ui-permissions.png b/docs/cs/images/microservice-sample-backend-ui-permissions.png deleted file mode 100644 index 3e1610294f..0000000000 Binary files a/docs/cs/images/microservice-sample-backend-ui-permissions.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-backend-ui.png b/docs/cs/images/microservice-sample-backend-ui.png deleted file mode 100644 index e649c8da59..0000000000 Binary files a/docs/cs/images/microservice-sample-backend-ui.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-blogservice-permission-in-database.png b/docs/cs/images/microservice-sample-blogservice-permission-in-database.png deleted file mode 100644 index 45d7f2b115..0000000000 Binary files a/docs/cs/images/microservice-sample-blogservice-permission-in-database.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-diagram-2.png b/docs/cs/images/microservice-sample-diagram-2.png deleted file mode 100644 index 414a942aca..0000000000 Binary files a/docs/cs/images/microservice-sample-diagram-2.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-diagram.png b/docs/cs/images/microservice-sample-diagram.png deleted file mode 100644 index 47e6443852..0000000000 Binary files a/docs/cs/images/microservice-sample-diagram.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-kibana-1.png b/docs/cs/images/microservice-sample-kibana-1.png deleted file mode 100644 index 51777f6bd7..0000000000 Binary files a/docs/cs/images/microservice-sample-kibana-1.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-kibana-2.png b/docs/cs/images/microservice-sample-kibana-2.png deleted file mode 100644 index cb1d0b748c..0000000000 Binary files a/docs/cs/images/microservice-sample-kibana-2.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-product-module-in-solution.png b/docs/cs/images/microservice-sample-product-module-in-solution.png deleted file mode 100644 index 2c07ad4b99..0000000000 Binary files a/docs/cs/images/microservice-sample-product-module-in-solution.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-public-product-list.png b/docs/cs/images/microservice-sample-public-product-list.png deleted file mode 100644 index 932b0b531c..0000000000 Binary files a/docs/cs/images/microservice-sample-public-product-list.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-solution.png b/docs/cs/images/microservice-sample-solution.png deleted file mode 100644 index d1497d9be2..0000000000 Binary files a/docs/cs/images/microservice-sample-solution.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-update-database-authserver.png b/docs/cs/images/microservice-sample-update-database-authserver.png deleted file mode 100644 index 094fd20fa6..0000000000 Binary files a/docs/cs/images/microservice-sample-update-database-authserver.png and /dev/null differ diff --git a/docs/cs/images/microservice-sample-update-database-products.png b/docs/cs/images/microservice-sample-update-database-products.png deleted file mode 100644 index 32a0927c1f..0000000000 Binary files a/docs/cs/images/microservice-sample-update-database-products.png and /dev/null differ diff --git a/docs/cs/images/module-layers-and-packages.jpg b/docs/cs/images/module-layers-and-packages.jpg deleted file mode 100644 index f71a91eb8d..0000000000 Binary files a/docs/cs/images/module-layers-and-packages.jpg and /dev/null differ diff --git a/docs/cs/images/night-build-add-nuget-package.png b/docs/cs/images/night-build-add-nuget-package.png deleted file mode 100644 index f475d3aaa0..0000000000 Binary files a/docs/cs/images/night-build-add-nuget-package.png and /dev/null differ diff --git a/docs/cs/images/night-build-add-nuget-source.png b/docs/cs/images/night-build-add-nuget-source.png deleted file mode 100644 index df3176aa12..0000000000 Binary files a/docs/cs/images/night-build-add-nuget-source.png and /dev/null differ diff --git a/docs/cs/images/pcm-update-database-v2.png b/docs/cs/images/pcm-update-database-v2.png deleted file mode 100644 index 72d02e9186..0000000000 Binary files a/docs/cs/images/pcm-update-database-v2.png and /dev/null differ diff --git a/docs/cs/images/pcm-update-database.png b/docs/cs/images/pcm-update-database.png deleted file mode 100644 index a9379d2571..0000000000 Binary files a/docs/cs/images/pcm-update-database.png and /dev/null differ diff --git a/docs/cs/images/select-empty-web-application-v2.png b/docs/cs/images/select-empty-web-application-v2.png deleted file mode 100644 index 9bfd2ec6a8..0000000000 Binary files a/docs/cs/images/select-empty-web-application-v2.png and /dev/null differ diff --git a/docs/cs/images/select-empty-web-application.png b/docs/cs/images/select-empty-web-application.png deleted file mode 100644 index f4b884140d..0000000000 Binary files a/docs/cs/images/select-empty-web-application.png and /dev/null differ diff --git a/docs/cs/images/set-as-startup-project.png b/docs/cs/images/set-as-startup-project.png deleted file mode 100644 index 8a5445bf38..0000000000 Binary files a/docs/cs/images/set-as-startup-project.png and /dev/null differ diff --git a/docs/cs/images/tiered-solution-applications.png b/docs/cs/images/tiered-solution-applications.png deleted file mode 100644 index df8d2b5f4a..0000000000 Binary files a/docs/cs/images/tiered-solution-applications.png and /dev/null differ diff --git a/docs/cs/images/tiered-solution-servers.png b/docs/cs/images/tiered-solution-servers.png deleted file mode 100644 index 68e72990d7..0000000000 Binary files a/docs/cs/images/tiered-solution-servers.png and /dev/null differ diff --git a/docs/cs/images/volodocs-iis-add-website.png b/docs/cs/images/volodocs-iis-add-website.png deleted file mode 100644 index aa7da8095b..0000000000 Binary files a/docs/cs/images/volodocs-iis-add-website.png and /dev/null differ diff --git a/docs/cs/images/volodocs-iis-application-pool.png b/docs/cs/images/volodocs-iis-application-pool.png deleted file mode 100644 index 28ccfa5c42..0000000000 Binary files a/docs/cs/images/volodocs-iis-application-pool.png and /dev/null differ diff --git a/docs/cs/images/widget-basic-files.png b/docs/cs/images/widget-basic-files.png deleted file mode 100644 index c692abd9e0..0000000000 Binary files a/docs/cs/images/widget-basic-files.png and /dev/null differ diff --git a/docs/docs-langs.json b/docs/docs-langs.json index 3986dc8618..b33b751207 100644 --- a/docs/docs-langs.json +++ b/docs/docs-langs.json @@ -4,16 +4,6 @@ "DisplayName" : "English", "Code" : "en", "IsDefault": true - }, - { - "DisplayName" : "Português", - "Code" : "pt-BR", - "IsDefault": false - }, - { - "DisplayName" : "简体中文", - "Code" : "zh-Hans", - "IsDefault": false } ] } diff --git a/docs/en/Blog-Posts/2024-05 ABP Unification/abp-studio-solution-runner.png b/docs/en/Blog-Posts/2024-05 ABP Unification/abp-studio-solution-runner.png new file mode 100644 index 0000000000..2b5bc20678 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05 ABP Unification/abp-studio-solution-runner.png differ diff --git a/docs/en/Blog-Posts/2024-05 ABP Unification/cover.png b/docs/en/Blog-Posts/2024-05 ABP Unification/cover.png new file mode 100644 index 0000000000..95e8363e67 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05 ABP Unification/cover.png differ diff --git a/docs/en/Blog-Posts/2024-05 ABP Unification/docs-new-navigation.png b/docs/en/Blog-Posts/2024-05 ABP Unification/docs-new-navigation.png new file mode 100644 index 0000000000..ba1f421339 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05 ABP Unification/docs-new-navigation.png differ diff --git a/docs/en/Blog-Posts/2024-05 ABP Unification/docs-project-selection.png b/docs/en/Blog-Posts/2024-05 ABP Unification/docs-project-selection.png new file mode 100644 index 0000000000..2e4dadafc6 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05 ABP Unification/docs-project-selection.png differ diff --git a/docs/en/Blog-Posts/2024-05 ABP Unification/new-get-started.png b/docs/en/Blog-Posts/2024-05 ABP Unification/new-get-started.png new file mode 100644 index 0000000000..ed1483f343 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05 ABP Unification/new-get-started.png differ diff --git a/docs/en/Blog-Posts/2024-05 ABP Unification/new-mega-menu.png b/docs/en/Blog-Posts/2024-05 ABP Unification/new-mega-menu.png new file mode 100644 index 0000000000..75c21a9693 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05 ABP Unification/new-mega-menu.png differ diff --git a/docs/en/Blog-Posts/2024-05 ABP Unification/new-pricing.png b/docs/en/Blog-Posts/2024-05 ABP Unification/new-pricing.png new file mode 100644 index 0000000000..4d299da6ee Binary files /dev/null and b/docs/en/Blog-Posts/2024-05 ABP Unification/new-pricing.png differ diff --git a/docs/en/Blog-Posts/2024-05 ABP Unification/post.md b/docs/en/Blog-Posts/2024-05 ABP Unification/post.md new file mode 100644 index 0000000000..9da50ac06b --- /dev/null +++ b/docs/en/Blog-Posts/2024-05 ABP Unification/post.md @@ -0,0 +1,111 @@ +# Unifying the ABP.IO Platform + +I am very excited to announce that some big changes and improvements are coming to the ABP.IO Platform soon. In this post, I will explain the changes we are currently working on. Here, a brief list of these changes: + +* We are merging the subdomains of the ABP.IO Platform websites: Community.abp.io, commercial.abp.io, blog.abp.io, docs.abp.io websites and their contents are being merged into the main domain, abp.io. +* ABP (open source) and ABP Commercial documents are being merged into a single documentation. +* Introducing ABP Studio Community Edition. + +These changes won't effect the license conditions. The open source part will remain the same and the commercial license contents will also be the same. The aim of the changes is to make the platform more consistent, holistic, understandable and easy to start. + +Let's dive deep... + +## Merging the ABP.IO Websites + +ABP.IO website has many subdomains currently: + +* **abp.io**: Home page of the open source ABP Framework project. +* **community.abp.io**: A website that community can share contents and we organize events. +* **commercial.abp.io**: A website to promote and sell commercial ABP licenses which have pre-built modules, themes, tooling and support on top of the ABP Framework. +* **docs.abp.io**: The technical documentation of the ABP Framework and ABP Commercial. +* **blog.abp.io**: A blog website to announce the news on the platform. +* **support.abp.io**: Premium support for the ABP Commercial customers. + +All these subdomains (except the support website for now) are being merged to the abp.io domain. All their contents and UI designs are being revised and enriched. + +Some fundamental purposes of that change are; + +* Making content more coherent and holistic, +* Making the design more harmonious, +* Making the contents of the old subdomains more visible and reachable, +* Allow you to navigate through the web pages much easier, +* Reducing duplications between different websites, + +I will highlight a few important changes in the next sections. + +### The New Mega Menu + +As I said above, the abp.io UI design is also being revised. One of the big revisions is the main menu. We are replacing the current main navigation by a mega menu as shown in the following figure: + +![new-mega-menu](new-mega-menu.png) + +We believe that new mega menu will allow you to navigate through the web pages much easier. + +### The New Get Started Page + +We are constantly working to improve ABP's onboarding experience. With the new platform changes, we now offer ABP Studio as the starting point for the ABP Platform. You can still use the [ABP CLI](https://docs.abp.io/en/abp/latest/CLI) to created new ABP solutions, but the new ABP Studio makes it much easier and understandable. It also provides features to easily run and monitor your applications, even in the Community edition. + +![new-get-started](new-get-started.png) + +You can easily download and install ABP Studio, login with your abp.io account and create your first ABP solution. + +### The New Pricing Page + +Since the [ABP Commercial website](https://commercial.abp.io/) has merged with the main website, you will see the *Pricing* page located on the main menu of the abp.io website. We have completely revised the design and content of this page to better reflect which features are open source and free, and what is included in the paid licenses. + +![new-pricing](new-pricing.png) + +As mentioned above, all the free & open source features are still free & open source. In addition, we included the ABP Studio Community edition (will be explained below) to the free license. + +## Merging the ABP Platform Documentation + +Currently, ABP Framework (open source) and ABP Commercial [documents](https://docs.abp.io/) are completely separated. You can switch between them on the left side: + +![docs-project-selection](docs-project-selection.png) + +Based on our and customers' experiences, there are some problems with that approach: + +* Getting started, development tutorials, release notes, road map and some other documents are duplicated (or very similar) among ABP Framework and ABP Commercial documents. +* For ABP Commercial users, it is not clear if they also need to read the ABP Framework (open source) documentation or not. Also, when they read the framework document, some parts are different for ABP Commercial users, and it is also not clear in some cases. + +We are currently working to completely merge the ABP Framework (open source) and ABP Commercial documentation, remove duplications and revisit the contents. We will clearly indicate if a part of a document requires a paid license. + +The left navigation panel tree is also completely revisited and simplified: + +![docs-new-navigation](docs-new-navigation.png) + +## The ABP Studio Community Edition + +[ABP Studio](https://docs.abp.io/en/commercial/latest/studio/index) is a cross-platform desktop application designed for ABP and .NET developers. It aims to provide a comfortable development environment by automating tasks, providing insights about your solution, and simplifying the processes of creation, development, execution, browsing, monitoring, tracing, and deploying your solutions. + +Here, a screenshot from the *Solution Runner* screen of ABP Studio: + +![abp-studio-solution-runner](abp-studio-solution-runner.png) + +ABP Studio has been started as a commercial product, as a part of [ABP Commercial](https://commercial.abp.io/). We are very excited to announce that the *Community Edition* will be available soon for free. It will have some missing features and limitations compared to the full edition, but will be enough to create, explore and run ABP solutions easily. + +We will be offering ABP Studio as a starting point to the ABP platform. The [Getting Started](https://docs.abp.io/en/abp/latest/Getting-Started-Overall) and other documents will use ABP Studio to create new solutions and perform ABP-related operations. + +## Other News + +We are also working on some other topics related to these changes. Some of them are; + +* Completely renewing the [startup templates](https://docs.abp.io/en/abp/latest/Startup-Templates/Index) (with ABP Studio), so they will be more flexible and will provide more options. +* Providing a tool to automatically convert ABP solutions created with open source startup templates into ABP commercial. + +## Questions + +I tried to explain all the important changes in this post. However, you may have some questions in your mind. + +### What should open source users expect? + +Since the [ABP Commercial](https://commercial.abp.io/) website content is merged with the main [abp.io](https://abp.io/) website, you will see paid features being introduced on the main website. The pricing page will also be available on the same website. This may lead you to wonder whether the ABP Platform is a fully paid product. The simple answer to this question is "No". Actually, nothing has changed on the open source side. Everything will be the same. Additionally, open source users will now have ABP Studio Community Edition for free. So open source has more for its users than before. + +### What should ABP Commercial customers expect? + +ABP Commercial license holders may wonder if any license change happens. The answer is "No". All the license types, rules, restrictions and features are the same. With the changes explained in this post, you will follow the documentation easier (since you won't need to go to another website for the framework documentation) and you will better understand what special features are available to you. + +## Last Words + +With this post, we wanted to announce the changes to be made on the ABP platform to the ABP community, so don't be surprised or curious about what happened. If you have any questions or suggestions, feel free to write a comment for this blog post or send an email to info@abp.io. + diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/POST.md b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/POST.md new file mode 100644 index 0000000000..23260950d4 --- /dev/null +++ b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/POST.md @@ -0,0 +1,269 @@ +# ABP.IO Platform 8.2 RC Has Been Released + +Today, we are happy to release the [ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) version **8.2 RC** (Release Candidate). This blog post introduces the new features and important changes in this new version. + +Try this version and provide feedback for a more stable version of ABP v8.2! Thanks to all of you. + +## Get Started with the 8.2 RC + +Follow the steps below to try version 8.2.0 RC today: + +1) **Upgrade** the ABP CLI to version `8.2.0-rc.3` using a command line terminal: + +````bash +dotnet tool update Volo.Abp.Cli -g --version 8.2.0-rc.3 +```` + +**or install** it if you haven't before: + +````bash +dotnet tool install Volo.Abp.Cli -g --version 8.2.0-rc.3 +```` + +2) Create a **new application** with the `--preview` option: + +````bash +abp new BookStore --preview +```` + +See the [ABP CLI documentation](https://docs.abp.io/en/abp/latest/CLI) for all the available options. + +> You can also use the [Get Started](https://abp.io/get-started) page to generate a CLI command to create a new application. + +You can use any IDE that supports .NET 8.x, like [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/). + +## Migration Guides + +There are a few breaking changes in this version that may affect your application. +Please see the following migration documents, if you are upgrading from v8.x or earlier: + +* [ABP Framework 8.x to 8.2 Migration Guide](https://docs.abp.io/en/abp/8.2/Migration-Guides/Abp-8_2) +* [ABP Commercial 8.x to 8.2 Migration Guide](https://docs.abp.io/en/commercial/8.2/migration-guides/v8_2) + +## What's New with ABP Framework 8.2? + +In this section, I will introduce some major features released in this version. +Here is a brief list of titles explained in the next sections: + +* Blazor Full-Stack Web App UI +* Introducing the `IBlockUiService` for Blazor UI +* Allowing Case-Insensitive Indexes for MongoDB +* Other News... + +### Blazor Full-Stack Web App UI + +ASP.NET Blazor in .NET 8 allows you to use a single powerful component model to handle all of your web UI needs, including server-side rendering, client-side rendering, streaming rendering, progressive enhancement, and much more! + +ABP v8.2.x supports the new Blazor Web App template, which you can directly create with the following command: + +```bash +abp new BookStore -t app -u blazor-webapp +``` + +When you create the project, you will typically see two main projects for Blazor UI, besides other projects: + +* **MyCompanyName.MyProjectName.Blazor.WebApp** (startup project of your application, and contains `App.razor` component, which is the root component of your application) +* **MyCompanyName.MyProjectName.Blazor.WebApp.Client** + +This new template overcomes the disadvantages of both Blazor WASM and Blazor Server applications and allows you to decide which approaches to use for a specific page or component. Therefore, you can imagine this new web UI as a combination of both Blazor Server and Blazor WASM. + +> This approach mainly overcomes the **large binary downloads of Blazor WASM**, and it resolves the Blazor Server's problem, which **always needs to be connected to the server via SignalR**. + +> If you are considering migrating your existing Blazor project to Blazor WebApp or want to learn more about this new template, please read the [Migrating to Blazor Web App](https://docs.abp.io/en/abp/8.2/Migration-Guides/Abp-8-2-Blazor-Web-App) guide. + +### Introducing the `IBlockUiService` for Blazor UI + +In this version, ABP Framework introduces the [`IBlockUiService`](https://docs.abp.io/en/abp/8.2/UI/Blazor/Block-Busy) for Blazor UI. This service uses UI Block API to disable/block the page or a part of the page. + +You just need to simply inject the `IBlockUiService` to your page or component and call the `Block` or `UnBlock` method to block/unblock the specified element: + +```csharp +namespace MyProject.Blazor.Pages +{ + public partial class Index + { + private readonly IBlockUiService _blockUiService; + + public Index(IBlockUiService _blockUiService) + { + _blockUiService = blockUiService; + } + + public async Task BlockForm() + { + /* + Parameters of Block method: + selectors: A string containing one or more selectors to match. https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector#selectors + busy : Set to true to show a progress indicator on the blocked area. + */ + await _blockUiService.Block(selectors: "#MySelectors", busy: true); + + //Unblocking the element + await _blockUiService.UnBlock(selectors: "#MySelectors"); + } + } +} + +``` + +Here is the resulting UI with all possible options (**block**, **block busy**, and **unblock**): + +![](block-ui-service-blazor.gif) + +### Allowing Case-Insensitive Indexes for MongoDB + +MongoDB allows case-insensitive string comparisons by using case-insensitive indexes. You can create a case-insensitive index by specifying a **collation**. + +To do that, you should override the `CreateModal` method, configure the `CreateCollectionOptions`, and specify the **collation** as below: + +```csharp +protected override void CreateModel(IMongoModelBuilder modelBuilder) +{ + base.CreateModel(modelBuilder); + + modelBuilder.Entity(b => + { + b.CreateCollectionOptions.Collation = new Collation(locale:"en_US", strength: CollationStrength.Secondary); + + b.ConfigureIndexes(indexes => + { + indexes.CreateOne( + new CreateIndexModel( + Builders.IndexKeys.Ascending("MyProperty"), + new CreateIndexOptions { Unique = true } + ) + ); + } + ); + }); +} +``` + +After this configuration, a unique index will be created for the `MyProperty` property and then you can perform case-insensitive string comparisons without the need to worry. See [#19073](https://github.com/abpframework/abp/pull/19073) for more information. + +### Other News + +* Angular package version has been updated to v17.3.0. See [#19915](https://github.com/abpframework/abp/pull/19915) for more info. +* OpenIddict [5.4.0 has been released on March 26](https://github.com/openiddict/openiddict-core/releases/tag/5.4.0). Therefore, we decided to upgrade the OpenIddict packages to v5.4.0. See [#19427](https://github.com/abpframework/abp/issues/19427). +* AutoMapper [13.0.1 was released on February 8](https://github.com/AutoMapper/AutoMapper/releases/tag/v13.0.1) and in this version, we upgraded AutoMapper packages to v13.0.1. See [#19564](https://github.com/abpframework/abp/pull/19564/). +* See other completed tasks in this version: [https://github.com/abpframework/abp/releases?q=8.2.0-rc](https://github.com/abpframework/abp/releases?q=8.2.0-rc&expanded=true) + +## What's New with ABP Commercial 8.2? + +We've also worked on ABP Commercial to align the features and changes made in the ABP Framework. The following sections introduce a few new features coming with ABP Commercial 8.2. + +### Session Management + +The [Session Management](https://docs.abp.io/en/commercial/8.2/modules/identity/session-management) feature allows you to prevent concurrent login and manage user sessions. You can allow concurrent login, allow only one session of the same device type, or logout from all other devices when a new session is created, by specifying in the settings page: + +![](concurrent-login-settings.png) + +Also, you can view and manage users sessions on the `Users` page of the [Identity Module](https://docs.abp.io/en/commercial/8.2/modules/identity): + +![](manage-user-sessions-1.png) +![](manage-user-sessions-2.png) + +### Suite: File/Image Property + +In this version, ABP Suite allows you to add a file/image property for an entity. You can select "File" as the property type for your properties as in the following figure: + +![](suite-file-property.png) + +Then, when you generate your entity and try to insert a record, you will see the file upload component on the create/update models: + +![](suite-file-property-create.png) + +You can upload a file with any supported extensions and under 10MB (this can be increased in the generated code, if you wish) and after that, you can download, delete and update the existing file any time you want: + +![](suite-file-upload-in-action.gif) + +> **Note:** This feature has already been implemented for MVC & Blazor UIs, but not implemented for Angular UI yet. We aim to implement it for Angular UI with v8.2.0. + +### Suite: DateOnly & TimeOnly Types + +In this version on, ABP Suite provides `DateOnly` and `TimeOnly` types as property types. You can select these types when you create an entity: + +![](suite-dateonly-timeonly-properties.png) + +Then, all related configurations (including db configurations) will be made by ABP Suite, and you will be able to see the fields in the UI: + +![](suite-dateonly-timeonly-ui.png) + +> **Note**: The `DateOnly` and `TimeOnly` types were introduced with .NET 6. Therefore, please make sure that all of your projects' target frameworks are .NET8+. With ABP v8.2, all startup templates target a single target framework, which is .NET8, so if you created your project with version 8.2+, you don't need to make any changes. + +### Periodic Log Deletion for Audit Logs + +In this version, the [Audit Logging Module](https://docs.abp.io/en/commercial/8.2/modules/audit-logging) provides a built-in periodic log deletion system. You can enable/disable the clean-up service system wide, in this way, you can turn off the clean up service for all tenants and their hosts: + +![](audit-logging-module-global-settings.png) + +> If the system wide clean up service is enabled, you can configure the global *Expired Item Deletion Period* for all tenants and hosts. + +When configuring the global settings for the audit log module from the host side in this manner, ensure that each tenant and host uses the global values. If you want to set tenant/host-specific values, you can do so under *Settings* -> *Audit Log* -> *General*. This way, you can disable the clean up service for specific tenants or host. It overrides the global settings: + +![](audit-logging-module-general-settings.png) + +> **Note**: To view the audit log settings, you need to enable the feature. For the host side, navigate to *Settings* -> *Feature Management* -> *Manage Host Features* -> *Audit Logging* -> *Enable audit log setting management*. + +## Community News + +### ABP Dotnet Conf 2024 Wrap Up + +![](abp-dotnet-conf-2024.png) + +We organized [ABP Dotnet Conference 2024](https://abp.io/conference/2024) on May 2024 and we are happy to share the success of the conference, which captivated overwhelmingly interested live viewers from all over the world. 29 great line up of speakers which includes .NET experts and Microsoft MVPs delivered captivating talks that resonated with the audiences. Each of the talks attracted a great amount of interest and a lot of questions, sparking curiosity in the attendees. + +Thanks to all speakers and attendees for joining our event. 🙏 + +> We shared our takeaways in a blog post, which you can read at [https://blog.abp.io/abp/ABP-Dotnet-Conference-2024-Wrap-Up](https://blog.abp.io/abp/ABP-Dotnet-Conference-2024-Wrap-Up). + +### DevDays Europe 2024 + +![](devdays-europe.jpg) + +Co-founder of [Volosoft](https://volosoft.com/), [Alper Ebiçoğlu](https://twitter.com/alperebicoglu) gave a speech about "How to Build a Multi-Tenant ASP.NET Core Application" at the [DevDays Europe 2024](https://devdays.lt/) on the 20th of May. + +### DevOps Pro Europe 2024 + +![](devops-pro-europe.jpg) + +We are thrilled to announce that the co-founder of [Volosoft](https://volosoft.com/) and Lead Developer of the [ABP Framework](https://abp.io/), [Halil Ibrahim Kalkan](https://x.com/hibrahimkalkan) gave a speech about "Building a Kubernetes Integrated Local Development Environment" in the [DevOps Pro Europe](https://devopspro.lt/) on the 24th of May. + +### Devnot Dotnet Conference 2024 + +We are happy to announce that core team members of the [ABP Framework](https://abp.io/), [Alper Ebiçoğlu](https://twitter.com/alperebicoglu) and [Enis Necipoğlu](https://twitter.com/EnisNecipoglu) will give speeches at the [Devnot Dotnet Conference 2024](https://dotnet.devnot.com/) on 25th of May. + +[Alper Ebiçoğlu](https://twitter.com/alperebicoglu) will talk about **"AspNet Core & Multitenancy"**: + +![](devnot-dotnet-conference-alper-ebicoglu.png) + +On the other hand, [Enis Necipoğlu](https://twitter.com/EnisNecipoglu) will talk about **"Reactive Programming with .NET MAUI"**: + +![](devnot-dotnet-conference-enis-necipoglu.png) + +### New ABP Community Articles + +There are exciting articles contributed by the ABP community as always. I will highlight some of them here: + +* [Ahmed Tarek](https://twitter.com/AhmedTarekHasa1) has created **four** new community articles: + * [🤔 When Implementations Affect Abstractions ⁉️](https://community.abp.io/posts/-when-implementations-affect-abstractions--ekx1o5xn) + * [👍 Design Best Practices In .NET C# 👀](https://community.abp.io/posts/design-best-practices-in-.net-c--eg8q8xh0) + * [👍 Chain of Responsibility Design Pattern In .NET C# 👀](https://community.abp.io/posts/chain-of-responsibility-design-pattern-in-.net-c--djmvkug1) + * [Flagged Enumerations: How To Represent Features Combinations Into One Field](https://community.abp.io/posts/flagged-enumerations-how-to-represent-features-combinations-into-one-field-9gj4l670) +* [Engincan Veske](https://github.com/EngincanV) has created **three** new community articles: + * [Performing Case-Insensitive Search in ABP Based-PostgreSQL Application: Using citext and Collation](https://community.abp.io/posts/caseinsensitive-search-in-abp-basedpostgresql-application-c9kb05dc) + * [Sentiment Analysis Within ABP-Based Application](https://community.abp.io/posts/sentiment-analysis-within-abpbased-application-lbsfkoxq) + * [Reusing and Optimizing Machine Learning Models in .NET](https://community.abp.io/posts/reusing-and-optimizing-machine-learning-models-in-.net-qj4ycnwu) +* [Unlocking Modularity in ABP.io A Closer Look at the Contributor Pattern](https://community.abp.io/posts/unlocking-modularity-in-abp.io-a-closer-look-at-the-contributor-pattern-ixf6wgbw) by [Qais Al khateeb](https://community.abp.io/members/qais.alkhateeb@devnas-jo.com) +* [Deploy Your ABP Framework MVC Project to Azure Container Apps](https://community.abp.io/posts/deploy-your-abp-framework-mvc-project-to-azure-container-apps-r93u9c6d) by [Selman Koç](https://community.abp.io/members/selmankoc) +* [How claim type works in ASP NET Core and ABP Framework](https://community.abp.io/posts/how-claim-type-works-in-asp-net-core-and-abp-framework-km5dw6g1) by [Liming Ma](https://github.com/maliming) +* [Using FluentValidation with ABP Framework](https://community.abp.io/posts/using-fluentvalidation-with-abp-framework-2cxuwl70) by [Enes Döner](https://community.abp.io/members/Enes) +* [Using Blob Storage with ABP](https://community.abp.io/posts/using-blob-storage-with-abp-framework-jygtmhn4) by [Emre Kendirli](https://community.abp.io/members/emrekenderli) + +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://community.abp.io/posts/submit) to the ABP Community. + +## Conclusion + +This version comes with some new features and a lot of enhancements to the existing features. You can see the [Road Map](https://docs.abp.io/en/abp/8.2/Road-Map) documentation to learn about the release schedule and planned features for the next releases. Please try ABP v8.2 RC and provide feedback to help us release a more stable version. + +Thanks for being a part of this community! \ No newline at end of file diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/abp-dotnet-conf-2024.png b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/abp-dotnet-conf-2024.png new file mode 100644 index 0000000000..4c20ced391 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/abp-dotnet-conf-2024.png differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/audit-logging-module-general-settings.png b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/audit-logging-module-general-settings.png new file mode 100644 index 0000000000..ed774fd4fd Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/audit-logging-module-general-settings.png differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/audit-logging-module-global-settings.png b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/audit-logging-module-global-settings.png new file mode 100644 index 0000000000..5a6373be10 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/audit-logging-module-global-settings.png differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/block-ui-service-blazor.gif b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/block-ui-service-blazor.gif new file mode 100644 index 0000000000..ecd9819d53 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/block-ui-service-blazor.gif differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/concurrent-login-settings.png b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/concurrent-login-settings.png new file mode 100644 index 0000000000..2b2aa17308 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/concurrent-login-settings.png differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/cover-image.png b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/cover-image.png new file mode 100644 index 0000000000..59689ba490 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/cover-image.png differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/devdays-europe.jpg b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/devdays-europe.jpg new file mode 100644 index 0000000000..48a71dc881 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/devdays-europe.jpg differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/devnot-dotnet-conference-alper-ebicoglu.png b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/devnot-dotnet-conference-alper-ebicoglu.png new file mode 100644 index 0000000000..f37435dc0e Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/devnot-dotnet-conference-alper-ebicoglu.png differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/devnot-dotnet-conference-enis-necipoglu.png b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/devnot-dotnet-conference-enis-necipoglu.png new file mode 100644 index 0000000000..a14a47a5a0 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/devnot-dotnet-conference-enis-necipoglu.png differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/devops-pro-europe.jpg b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/devops-pro-europe.jpg new file mode 100644 index 0000000000..639d49176a Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/devops-pro-europe.jpg differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/manage-user-sessions-1.png b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/manage-user-sessions-1.png new file mode 100644 index 0000000000..82856c45b2 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/manage-user-sessions-1.png differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/manage-user-sessions-2.png b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/manage-user-sessions-2.png new file mode 100644 index 0000000000..d2dcfddc5c Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/manage-user-sessions-2.png differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-dateonly-timeonly-properties.png b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-dateonly-timeonly-properties.png new file mode 100644 index 0000000000..5a6f8d1186 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-dateonly-timeonly-properties.png differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-dateonly-timeonly-ui.png b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-dateonly-timeonly-ui.png new file mode 100644 index 0000000000..5871984876 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-dateonly-timeonly-ui.png differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-file-property-create.png b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-file-property-create.png new file mode 100644 index 0000000000..2b6d2fdf95 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-file-property-create.png differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-file-property.png b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-file-property.png new file mode 100644 index 0000000000..a6b64ee986 Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-file-property.png differ diff --git a/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-file-upload-in-action.gif b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-file-upload-in-action.gif new file mode 100644 index 0000000000..0b51b1472e Binary files /dev/null and b/docs/en/Blog-Posts/2024-05-21 v8_2_Release/suite-file-upload-in-action.gif differ diff --git a/docs/en/Blog-Posts/2024-06-27 v8_2_Release_Stable/POST.md b/docs/en/Blog-Posts/2024-06-27 v8_2_Release_Stable/POST.md new file mode 100644 index 0000000000..67db40e98a --- /dev/null +++ b/docs/en/Blog-Posts/2024-06-27 v8_2_Release_Stable/POST.md @@ -0,0 +1,67 @@ +# ABP.IO Platform 8.2 Final Has Been Released! + +[ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) 8.2 versions have been released today. + +## What's New With Version 8.2? + +All the new features were explained in detail in the [8.2 RC Announcement Post](https://blog.abp.io/abp/announcing-abp-8-2-release-candidate), so there is no need to review them again. You can check it out for more details. + +## Getting Started with 8.2 + +### Creating New Solutions + +You can create a new solution with the ABP Framework version 8.2 by either using the `abp new` command or generating the CLI command on the [get started page](https://abp.io/get-started). + +> See the [getting started document](https://docs.abp.io/en/abp/latest/Getting-Started) for more. + +### How to Upgrade an Existing Solution + +#### Install/Update the ABP CLI + +First, install the ABP CLI or upgrade it to the latest version. + +If you haven't installed it yet: + +```bash +dotnet tool install -g Volo.Abp.Cli +``` + +To update the existing CLI: + +```bash +dotnet tool update -g Volo.Abp.Cli +``` + +#### Upgrading Existing Solutions with the ABP Update Command + +[ABP CLI](https://docs.abp.io/en/abp/latest/CLI) provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command: + +```bash +abp update +``` + +Run this command in the root folder of your solution. + +## Migration Guides + +There are a few breaking changes in this version that may affect your application. +Please see the following migration documents, if you are upgrading from v8.x or earlier: + +* [ABP Framework 8.x to 8.2 Migration Guide](https://docs.abp.io/en/abp/8.2/Migration-Guides/Abp-8_2) +* [ABP Commercial 8.x to 8.2 Migration Guide](https://docs.abp.io/en/commercial/8.2/migration-guides/v8_2) + +## Community News + +### New ABP Community Posts + +As always, exciting articles have been contributed by the ABP community. I will highlight some of them here: + +* [How to use Angular Material with Form Validation on ABP](https://community.abp.io/posts/how-to-use-angular-material-with-form-validation-on-abp-jtheajj3) by [Mahmut Gündoğdu](https://x.com/mahmutgundogdu) +* [Tunnel your local host address to a public URL with ngrok](https://community.abp.io/posts/tunnel-your-local-host-address-to-a-public-url-with-ngrok-4cywnocj) by [Bart Van Hoey](https://github.com/bartvanhoey) +* [Antiforgery Token Validation When Angular and HTTP API Runs on the Same Server](https://community.abp.io/posts/antiforgery-token-validation-when-angular-and-http-api-runs-on-the-same-server-mzf5ppdq) by [dignite](https://x.com/dignite_adu) + +Thanks to the ABP Community for all the content they have published. You can also [post your ABP-related (text or video) content](https://community.abp.io/articles/submit) to the ABP Community. + +## About the Next Version + +The next feature version will be 8.3. 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/2024-06-27 v8_2_Release_Stable/cover-image.png b/docs/en/Blog-Posts/2024-06-27 v8_2_Release_Stable/cover-image.png new file mode 100644 index 0000000000..59689ba490 Binary files /dev/null and b/docs/en/Blog-Posts/2024-06-27 v8_2_Release_Stable/cover-image.png differ diff --git a/docs/en/Community-Articles/2024-04-19-using-blob-storage-with-abp/images/blob-storage.png b/docs/en/Community-Articles/2024-04-19-using-blob-storage-with-abp/images/blob-storage.png new file mode 100644 index 0000000000..05aa32eaad Binary files /dev/null and b/docs/en/Community-Articles/2024-04-19-using-blob-storage-with-abp/images/blob-storage.png differ diff --git a/docs/en/Community-Articles/2024-04-19-using-blob-storage-with-abp/post.md b/docs/en/Community-Articles/2024-04-19-using-blob-storage-with-abp/post.md new file mode 100644 index 0000000000..e76f7f2728 --- /dev/null +++ b/docs/en/Community-Articles/2024-04-19-using-blob-storage-with-abp/post.md @@ -0,0 +1,114 @@ +# Using Blob Storage with ABP +ABP Framework provides a comprehensive solution to meet the needs of modern application development, while addressing the important requirement of BLOB Storing. ABP Framework [provides an easy integration for Blob Storing](https://docs.abp.io/en/abp/latest/Blob-Storing) and offers many storage services that you can easily integrate. In addition to efficiently storing large files, these services offer significant advantages such as scalability, security and backup. + +## What is Blob Storage ? + +Blob Storage is a service for storing unstructured data. It is becoming increasingly important to efficiently store and manage large data types (e.g. images, videos, documents). Blob Storage was developed to meet these needs and offers a secure solution with the advantages of scalability, durability and low cost. + + ![Blob Stroge](./images/blob-storage.png) + + +## How to use Blob Storage ? + +I would like to explain this to you with an example.For example, storing large files such as user profile pictures in the database negatively affects the performance and database.You can store this data using Blob storage. One of the advantages of storing user profile pictures in blob storage is that it improves database performance. Blob storage is a more efficient option than storing large size files in the database and allows database queries to run faster. Furthermore, blob storage provides scalability, so that the number of profile pictures can grow with the number of users, but without storage issues. This approach also maintains database normalization and makes the database design cleaner. + + How do we store user profile pictures with Blob Storage using ABP Framework? + +- #### Step 1: Configure the Blob Container + +Define a Blob Container named `profile-pictures` using the `[BlobContainerName("profile-pictures")]` attribute. + +````csharp +[BlobContainerName("profile-pictures")] +public class ProfilePictureContainer +{ + +} +```` +- #### Step 2: Create the ProfileAppService (Saving & Reading BLOBs) + +Create the `ProfileAppService` class and derive it from the `ApplicationService` class. This class will perform the necessary operations to store and retrieve profile pictures. + +````csharp +using Volo.Abp.Application.Services; + +public class ProfileAppService : ApplicationService +{ + // Code snippets will come here +} +```` + +- #### Step 3: Inject the `IBlobContainer` Service + +Inject the `IBlobContainer` service, in the constructor of the `ProfileAppService` class. The `IBlobContainer` is the main interface to store and read BLOB and is used to interact with the container. + +````csharp +private readonly IBlobContainer _blobContainer; + +public ProfileAppService(IBlobContainer blobContainer) +{ + _blobContainer = blobContainer; +} +```` + +- #### Step 4: Save Profile Picture + +The SaveProfilePictureAsync method is used to store the user's profile picture. A unique name is generated based on the user's credentials and the profile picture byte array with this name is saved in the Blob Container. + +````csharp +public async Task SaveProfilePictureAsync(byte[] bytes) +{ + var blobName = CurrentUser.GetId().ToString(); + await _blobContainer.SaveAsync(blobName, bytes); +} +```` + +- #### Step 5: Getting Profile Picture + +The GetProfilePictureAsync method is used to get the user's profile picture. A profile picture byte array is retrieved from the Blob Container with a specified name based on the user's credential. + +````csharp +public async Task GetProfilePictureAsync() +{ + var blobName = CurrentUser.GetId().ToString(); + return await _blobContainer.GetAllBytesOrNullAsync(blobName); +} +```` + + +Finally, add controls in the user interface that will allow users to upload and view their profile pictures. These controls will perform the operations by calling the corresponding methods in the ProfileAppService class. + +These steps cover the basic steps to store user profile pictures with Blob Storage using the ABP Framework. [Check out the documentation for more information.](https://docs.abp.io/en/abp/latest/Blob-Storing) + + +## What are the Advantages/Disadvantages of Keeping the BLOBs in a Database? + +#### Advantages: + +- Data Integrity and Relational Model: To ensure data integrity and preserve the relational model, it is important to store blob data in the database. This approach preserves the relationships between data and maintains the structural integrity of the database. + +- A Single Storage Location: Storing blob data in the database allows you to collect all data in a single storage location. This simplifies the management of data and increases data integrity. + +- Advanced Security Controls: Database systems often offer advanced security controls. Storing blob data in a database allows you to take advantage of these security features and ensures that data is accessed by authorized users. + +#### Disadvantages: + +- Performance Issues: Storing blob data in a database can negatively impact database performance. Oversized blob data can slow down query processing and reduce database performance. + +- Storage Space Issue: Storing blob data in the database can increase the size of the database and require more storage space. This can increase storage costs and complicate infrastructure requirements. + +- Backup and Recovery Challenges: Storing blob data in a database can make backup and recovery difficult. The large size of blob data can make backup and recovery time-consuming and data recovery difficult. + + +## Other Blob Storage Providers + +ABP Framework provides developers with a variety of options and flexibility by offering integration infrastructure for multiple cloud providers. This makes it easy for users to choose between different cloud platforms and select the most suitable solution for their business needs. + + +- Azure Blob Storage: A cloud storage service offered on the Microsoft Azure platform. It is used to store and access large amounts of data. It supports various data types such as files, images, videos and provides high scalability. ABP Framework provides integration with [Azure Blob Storage](https://docs.abp.io/en/abp/latest/Blob-Storing-Azure). + +- Aliyun Object Storage Service (OSS): OSS, Alibaba Cloud's cloud storage service, is an ideal solution for use cases such as big data storage, backup and media storage. It offers flexible storage options and provides a high level of security. ABP Framework interfaces with [Aliyun Blob Storage](https://docs.abp.io/en/abp/latest/Blob-Storing-Aliyun), making it easier for developers to manage data storage and access. + +- MinIO: MinIO is known as an open source object storage system and offers an Amazon S3 compatible cloud storage solution. It is a high-performance, scalable and fast storage service. ABP Framework integrates with [MinIO Blob Storage](https://docs.abp.io/en/abp/latest/Blob-Storing-Minio) to provide developers with cloud-based file and object storage. + +- Amazon Simple Storage Service (S3): Amazon S3 is a cloud storage service offered on the Amazon Web Services (AWS) platform. It can be used to store virtually unlimited amounts of data. It provides high durability, scalability and low cost.ABP Framework integrates with [Amazon S3 Blob Storage](https://docs.abp.io/en/abp/latest/Blob-Storing-Aws) to provide developers with cloud-based file and object storage. diff --git a/docs/en/Community-Articles/2024-05-01-How-ABP-get-current-user/POST.md b/docs/en/Community-Articles/2024-05-01-How-ABP-get-current-user/POST.md new file mode 100644 index 0000000000..5e32e184e1 --- /dev/null +++ b/docs/en/Community-Articles/2024-05-01-How-ABP-get-current-user/POST.md @@ -0,0 +1,201 @@ +# How claim type works in ASP NET Core and ABP Framework + +## The Claim Type + +A web application may use one or more authentication schemes to obtain the current user's information, such as `Cookies`, `JwtBearer`, `OpenID Connect`, `Google` etc. + +After authentication, we get a set of claims that can be issued using a trusted identity provider. A claim is a type/name-value pair representing the subject. The type property provides the semantic content of the claim, that is, it states what the claim is about. + +The [`ICurrentUser`](https://docs.abp.io/en/abp/latest/CurrentUser) service of the ABP Framework provides a convenient way to access the current user's information from the claims. + +The claim type is the key to getting the correct value of the current user, and we have a static `AbpClaimTypes` class that defines the names of the standard claims in the ABP Framework: + +```cs +public static class AbpClaimTypes +{ + public static string UserId { get; set; } = ClaimTypes.NameIdentifier; + public static string UserName { get; set; } = ClaimTypes.Name; + public static string Role { get; set; } = ClaimTypes.Role; + public static string Email { get; set; } = ClaimTypes.Email; + //... +} +``` + +As you can see, the default claim type of `AbpClaimTypes` comes from the [`System.Security.Claims.ClaimTypes`](https://learn.microsoft.com/en-us/dotnet/api/system.security.claims.claimtypes) class, which is the recommended practice in NET. + +## Claim type in different authentication schemes + +We usually see two types of claim types in our daily development. One of them is the [`System.Security.Claims.ClaimTypes`](https://learn.microsoft.com/en-us/dotnet/api/system.security.claims.claimtypes) and the other one is the `OpenId Connect` [standard claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). + +### ASP NET Core Identity + +There is a [`ClaimsIdentityOptions`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.claimsidentityoptions) property in the `IdentityOptions`, which can be used to configure the claim type: + +| Property | Description | +|----------------------|---------------------------------------------------------------------------------------------------------------| +| EmailClaimType | Gets or sets the ClaimType used for the user email claim. Defaults to Email. | +| RoleClaimType | Gets or sets the ClaimType used for a Role claim. Defaults to Role. | +| SecurityStampClaimType | Gets or sets the ClaimType used for the security stamp claim. Defaults to "AspNet.Identity.SecurityStamp". | +| UserIdClaimType | Gets or sets the ClaimType used for the user identifier claim. Defaults to NameIdentifier. | +| UserNameClaimType | Gets or sets the ClaimType used for the user name claim. Defaults to Name. | + +* The Identity creates a `ClaimsIdentity` object with the claim type that you have configured in the `ClaimsIdentityOptions` class. +* The ABP Framework configures it based on `AbpClaimTypes,` so usually you don't need to worry about it. + +### JwtBearer/OpenID Connect Client + +The `JwtBearer/OpenID Connect` gets claims from `id_token` or fetches user information from the `AuthServer`, and then maps/adds it to the current `ClaimsIdentity`. + +To map the [standard claim](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) type to the [`System.Security.Claims.ClaimTypes`](https://learn.microsoft.com/en-us/dotnet/api/system.security.claims.claimtypes) via [azure-activedirectory-identitymodel-extensions-for-dotnet](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) library by default, which is maintained by the Microsoft team: + +```cs +Dictionary ClaimTypeMapping = new Dictionary +{ + { "actort", ClaimTypes.Actor }, + { "birthdate", ClaimTypes.DateOfBirth }, + { "email", ClaimTypes.Email }, + { "family_name", ClaimTypes.Surname }, + { "gender", ClaimTypes.Gender }, + { "given_name", ClaimTypes.GivenName }, + { "nameid", ClaimTypes.NameIdentifier }, + { "sub", ClaimTypes.NameIdentifier }, + { "website", ClaimTypes.Webpage }, + { "unique_name", ClaimTypes.Name }, + { "oid", "http://schemas.microsoft.com/identity/claims/objectidentifier" }, + { "scp", "http://schemas.microsoft.com/identity/claims/scope" }, + { "tid", "http://schemas.microsoft.com/identity/claims/tenantid" }, + { "acr", "http://schemas.microsoft.com/claims/authnclassreference" }, + { "adfs1email", "http://schemas.xmlsoap.org/claims/EmailAddress" }, + { "adfs1upn", "http://schemas.xmlsoap.org/claims/UPN" }, + { "amr", "http://schemas.microsoft.com/claims/authnmethodsreferences" }, + { "authmethod", ClaimTypes.AuthenticationMethod }, + { "certapppolicy", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/applicationpolicy" }, + { "certauthoritykeyidentifier", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/authoritykeyidentifier" }, + { "certbasicconstraints", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/basicconstraints" }, + { "certeku", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/eku" }, + { "certissuer", "http://schemas.microsoft.com/2012/12/certificatecontext/field/issuer" }, + { "certissuername", "http://schemas.microsoft.com/2012/12/certificatecontext/field/issuername" }, + { "certkeyusage", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/keyusage" }, + { "certnotafter", "http://schemas.microsoft.com/2012/12/certificatecontext/field/notafter" }, + { "certnotbefore", "http://schemas.microsoft.com/2012/12/certificatecontext/field/notbefore" }, + { "certpolicy", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/certificatepolicy" }, + { "certpublickey", ClaimTypes.Rsa }, + { "certrawdata", "http://schemas.microsoft.com/2012/12/certificatecontext/field/rawdata" }, + { "certserialnumber", ClaimTypes.SerialNumber }, + { "certsignaturealgorithm", "http://schemas.microsoft.com/2012/12/certificatecontext/field/signaturealgorithm" }, + { "certsubject", "http://schemas.microsoft.com/2012/12/certificatecontext/field/subject" }, + { "certsubjectaltname", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/san" }, + { "certsubjectkeyidentifier", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/subjectkeyidentifier" }, + { "certsubjectname", "http://schemas.microsoft.com/2012/12/certificatecontext/field/subjectname" }, + { "certtemplateinformation", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/certificatetemplateinformation" }, + { "certtemplatename", "http://schemas.microsoft.com/2012/12/certificatecontext/extension/certificatetemplatename" }, + { "certthumbprint", ClaimTypes.Thumbprint }, + { "certx509version", "http://schemas.microsoft.com/2012/12/certificatecontext/field/x509version" }, + { "clientapplication", "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-client-application" }, + { "clientip", "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-client-ip" }, + { "clientuseragent", "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-client-user-agent" }, + { "commonname", "http://schemas.xmlsoap.org/claims/CommonName" }, + { "denyonlyprimarygroupsid", ClaimTypes.DenyOnlyPrimaryGroupSid }, + { "denyonlyprimarysid", ClaimTypes.DenyOnlyPrimarySid }, + { "denyonlysid", ClaimTypes.DenyOnlySid }, + { "devicedispname", "http://schemas.microsoft.com/2012/01/devicecontext/claims/displayname" }, + { "deviceid", "http://schemas.microsoft.com/2012/01/devicecontext/claims/identifier" }, + { "deviceismanaged", "http://schemas.microsoft.com/2012/01/devicecontext/claims/ismanaged" }, + { "deviceostype", "http://schemas.microsoft.com/2012/01/devicecontext/claims/ostype" }, + { "deviceosver", "http://schemas.microsoft.com/2012/01/devicecontext/claims/osversion" }, + { "deviceowner", "http://schemas.microsoft.com/2012/01/devicecontext/claims/userowner" }, + { "deviceregid", "http://schemas.microsoft.com/2012/01/devicecontext/claims/registrationid" }, + { "endpointpath", "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-endpoint-absolute-path" }, + { "forwardedclientip", "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-forwarded-client-ip" }, + { "group", "http://schemas.xmlsoap.org/claims/Group" }, + { "groupsid", ClaimTypes.GroupSid }, + { "idp", "http://schemas.microsoft.com/identity/claims/identityprovider" }, + { "insidecorporatenetwork", "http://schemas.microsoft.com/ws/2012/01/insidecorporatenetwork" }, + { "isregistereduser", "http://schemas.microsoft.com/2012/01/devicecontext/claims/isregistereduser" }, + { "ppid", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" }, + { "primarygroupsid", ClaimTypes.PrimaryGroupSid }, + { "primarysid", ClaimTypes.PrimarySid }, + { "proxy", "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-proxy" }, + { "pwdchgurl", "http://schemas.microsoft.com/ws/2012/01/passwordchangeurl" }, + { "pwdexpdays", "http://schemas.microsoft.com/ws/2012/01/passwordexpirationdays" }, + { "pwdexptime", "http://schemas.microsoft.com/ws/2012/01/passwordexpirationtime" }, + { "relyingpartytrustid", "http://schemas.microsoft.com/2012/01/requestcontext/claims/relyingpartytrustid" }, + { "role", ClaimTypes.Role }, + { "roles", ClaimTypes.Role }, + { "upn", ClaimTypes.Upn }, + { "winaccountname", ClaimTypes.WindowsAccountName }, +}; +``` + +#### Disable JwtBearer/OpenID Connect Client Claim Type Mapping + +To turn off the claim type mapping, you can set the `MapInboundClaims` property of `JwtBearerOptions` or `OpenIdConnectOptions` to `false`. Then, you can get the original claim types from the token(`access_token` or `id_token`): + +JWT Example: + +```json +{ + "iss": "https://localhost:44305/", + "exp": 1714466127, + "iat": 1714466127, + "aud": "MyProjectName", + "scope": "MyProjectName offline_access", + "sub": "ed7f5cfd-7311-0402-245c-3a123ff787f9", + "unique_name": "admin", + "preferred_username": "admin", + "given_name": "admin", + "role": "admin", + "email": "admin@abp.io", + "email_verified": "False", + "phone_number_verified": "False", +} +``` + +### OAuth2(Google, Facebook, Twitter, Microsoft) Extenal Login Client + +The `OAuth2 handler` fetchs a JSON containing user information from the `OAuth2` server. The third-party provider issues the claim type based on their standard server and then maps/adds it to the current `ClaimsIdentity`. The ASP NET Core provides some built-in claim-type mappings for different providers as can be seen below examples: + +**Example**: The `ClaimActions` property of the `GoogleOptions` maps the Google's claim types to [`System.Security.Claims.ClaimTypes`](https://learn.microsoft.com/en-us/dotnet/api/system.security.claims.claimtypes): + +```cs +ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id"); // v2 +ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub"); // v3 +ClaimActions.MapJsonKey(ClaimTypes.Name, "name"); +ClaimActions.MapJsonKey(ClaimTypes.GivenName, "given_name"); +ClaimActions.MapJsonKey(ClaimTypes.Surname, "family_name"); +ClaimActions.MapJsonKey("urn:google:profile", "link"); +ClaimActions.MapJsonKey(ClaimTypes.Email, "email"); +``` + +**Example**: The `ClaimActions` property of the `FacebookOptions` maps the Facebook's claim types to [`System.Security.Claims.ClaimTypes`](https://learn.microsoft.com/en-us/dotnet/api/system.security.claims.claimtypes): + +```cs +ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id"); +ClaimActions.MapJsonSubKey("urn:facebook:age_range_min", "age_range", "min"); +ClaimActions.MapJsonSubKey("urn:facebook:age_range_max", "age_range", "max"); +ClaimActions.MapJsonKey(ClaimTypes.DateOfBirth, "birthday"); +ClaimActions.MapJsonKey(ClaimTypes.Email, "email"); +ClaimActions.MapJsonKey(ClaimTypes.Name, "name"); +ClaimActions.MapJsonKey(ClaimTypes.GivenName, "first_name"); +ClaimActions.MapJsonKey("urn:facebook:middle_name", "middle_name"); +ClaimActions.MapJsonKey(ClaimTypes.Surname, "last_name"); +ClaimActions.MapJsonKey(ClaimTypes.Gender, "gender"); +ClaimActions.MapJsonKey("urn:facebook:link", "link"); +ClaimActions.MapJsonSubKey("urn:facebook:location", "location", "name"); +ClaimActions.MapJsonKey(ClaimTypes.Locality, "locale"); +ClaimActions.MapJsonKey("urn:facebook:timezone", "timezone"); +``` + +### OpenIddict AuthServer + +The `OpenIddict` uses the [standard claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) as the claim type of the `id_token` or `access_token` and `UserInfo` endpoint response, etc. + +* For JWT token, it also uses the [azure-activedirectory-identitymodel-extensions-for-dotnet](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) to get the claims from the `id_token` or `access_token`. +* For reference token, it gets the claims from the `database`. + +## Summary + +Once you find the claims you received do not meet your expectations, follow the instructions above to troubleshoot the problem. + +This article can help you understand the claim type in the ABP Framework and ASP NET Core. + diff --git a/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/POST.md b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/POST.md new file mode 100644 index 0000000000..4234062de6 --- /dev/null +++ b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/POST.md @@ -0,0 +1,86 @@ +# Deploy Your ABP Framework MVC Project to Azure Container Apps + +![](azure-container-abp.png) + +In this article, we will show the seamless deployment of an ABP Framework MVC project to Azure Container Apps. enabling you to deploy and run containerized applications without the hassle of managing the infrastructure underneath. It provides an uncomplicated and cost-effective method for deploying and scaling your applications. + +### Getting Started with ABP Framework MVC and Azure Container Apps + +To get started, you will need an ABP Framework MVC project that you want to deploy. If you don't have one, you can [create a new project using the ABP CLI](https://docs.abp.io/en/abp/latest/Startup-Templates/Application). You will also need [an Azure subscription](https://azure.microsoft.com) and [an Azure SQL database](https://azure.microsoft.com/en-gb/products/azure-sql). + +Before creating Azure container apps resources and deploying the ABP Framework MVC project, I show you how you can effortlessly create Docker images and push them to Docker Hub, leveraging the pre-configured Docker file and scripts that come with the ABP MVC framework. + +### Creating a Docker Image for ABP Framework MVC + +To create a Docker image for your ABP Framework MVC project, navigate to `etc/build/build-images-locally.ps1` and fix the script to match your Docker Hub username and image name. Then, run the script to build the Docker image locally. + +![Build Docker Image](build-docker-image.png) + +Next, check the Docker Hub repository to confirm that the image has been pushed successfully. + +![Docker Hub Repository](docker-hub-repository.png) + +### Deploying to Azure Container Apps + +Now that you have Docker images for your ABP Framework MVC project, you can proceed to deploy it to Azure Container Apps. To do this, navigate to the Azure portal and create a new Azure Container Apps resource. Ypu will not need just an Azure Container Apps resource, but also an Azure Container Apps Job resource to migrate the database schema and seed data for your ABP Framework MVC project. + +![Create Azure Container Apps](create-azure-container-apps.png) + +#### Step 1: Deploy the Docker Image + +Firstly, create a new Azure Container Apps resource without environment variables. You will need web url so that you can set it as an environment variable in the next step. Then, check the deployment status to confirm that the deployment was successful. + +![Deploy Docker Image](deploy-docker-image.png) + +#### Step 2: Migrate Database Schema and Seed Data + +Secondly, create a new Azure Container Apps Job resource to migrate the database schema and seed data. You can do this by creating a new job with the following environment variables: + +```text +ConnectionStrings__Default - Server=tcp:demoabpapp.database.windows.net,1433;Initial Catalog=mvcapppro;Persist Security Info=False;User ID=demoapppro;Password={your_password};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30; + +OpenIddict__Applications__mvcapppro_Web__RootUrl - https://mvcwebapp.victoriousgrass-8b06438d.northeurope.azurecontainerapps.io +``` + +To get ConnectionStrings of Sql Database and url of the web app, you can navigate to the Azure portal and check the properties of the Azure SQL database and Azure Container Apps resource. + + +![Azure SQL Database Connection Strings](azure-sql-database-connection-strings.png) + +![Create Azure Container Apps Job](create-azure-container-apps-job.png) + +Finally, check the job status to confirm that the database migration and seeding were successful. You can connect to the Azure SQL database to verify that the schema and seed data have been applied. + +![Check Job Status](check-job-status.png) + +#### Step 3: Edit the Azure Container Apps Resource + +After completing these steps, you have to edit the Azure Container Apps resource to add the required environment variables for your ABP Framework MVC project. You can do this by adding the following environment variables: + +```text +App__SelfUrl - https://mvcwebapp.victoriousgrass-8b06438d.northeurope.azurecontainerapps.io + +ASPNETCORE_URLS - http://+:80 + +AuthServer__Authority - https://mvcwebapp.victoriousgrass-8b06438d.northeurope.azurecontainerapps.io + +ConnectionStrings__Default - Server=tcp:demoabpapp.database.windows.net,1433;Initial Catalog=mvcapppro;Persist Security Info=False;User ID=demoapppro;Password={your_password};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30; +``` + +![Add Environment Variables](add-environment-variables.png) + +#### Step 4: Create a New Deployment + +Once you have added the environment variables, save and create a new deployment to apply the changes. You can now access your ABP Framework MVC project running on Azure Container Apps by navigating to the URL provided in the environment variables. + +![Access ABP Framework MVC Project](access-abp-framework-mvc-project.png) + +You can see the Azure resources created for the ABP Framework MVC project deployment that includes the Azure Container Apps resource, Azure Container Apps Job resource, and Azure SQL database. + +![Azure Resources](azure-resources.png) + +### Conclusion + +Azure Container Apps provides a simple and cost-effective way to deploy and scale your ABP Framework MVC projects without managing the underlying infrastructure. By following the steps outlined in this article, you can seamlessly deploy your ABP Framework MVC projects to Azure Container Apps and enjoy the benefits it offers. + +I hope you found this article helpful. If you have any questions or feedback, please feel free to leave a comment below. diff --git a/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/access-abp-framework-mvc-project.png b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/access-abp-framework-mvc-project.png new file mode 100644 index 0000000000..ff0aa2f811 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/access-abp-framework-mvc-project.png differ diff --git a/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/add-environment-variables.png b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/add-environment-variables.png new file mode 100644 index 0000000000..56f9df7fa4 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/add-environment-variables.png differ diff --git a/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/azure-container-abp.png b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/azure-container-abp.png new file mode 100644 index 0000000000..ec96dd0b2e Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/azure-container-abp.png differ diff --git a/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/azure-resources.png b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/azure-resources.png new file mode 100644 index 0000000000..3bab322580 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/azure-resources.png differ diff --git a/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/azure-sql-database-connection-strings.png b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/azure-sql-database-connection-strings.png new file mode 100644 index 0000000000..5ec51f6edb Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/azure-sql-database-connection-strings.png differ diff --git a/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/build-docker-image.png b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/build-docker-image.png new file mode 100644 index 0000000000..496dd637cd Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/build-docker-image.png differ diff --git a/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/check-job-status.png b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/check-job-status.png new file mode 100644 index 0000000000..e87ee2081f Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/check-job-status.png differ diff --git a/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/create-azure-container-apps-job.png b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/create-azure-container-apps-job.png new file mode 100644 index 0000000000..10229d5707 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/create-azure-container-apps-job.png differ diff --git a/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/create-azure-container-apps.png b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/create-azure-container-apps.png new file mode 100644 index 0000000000..3e8e899960 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/create-azure-container-apps.png differ diff --git a/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/deploy-docker-image.png b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/deploy-docker-image.png new file mode 100644 index 0000000000..df431b6c51 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/deploy-docker-image.png differ diff --git a/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/docker-hub-repository.png b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/docker-hub-repository.png new file mode 100644 index 0000000000..b25e01a629 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-Azure-Container-Apps-Deployment-with-ABP/docker-hub-repository.png differ diff --git a/docs/en/Community-Articles/2024-05-07-using-fluent-validation-with-abp/images/adding-incorrect-data.png b/docs/en/Community-Articles/2024-05-07-using-fluent-validation-with-abp/images/adding-incorrect-data.png new file mode 100644 index 0000000000..6c8a704093 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-using-fluent-validation-with-abp/images/adding-incorrect-data.png differ diff --git a/docs/en/Community-Articles/2024-05-07-using-fluent-validation-with-abp/images/error.png b/docs/en/Community-Articles/2024-05-07-using-fluent-validation-with-abp/images/error.png new file mode 100644 index 0000000000..7c611cdc49 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-using-fluent-validation-with-abp/images/error.png differ diff --git a/docs/en/Community-Articles/2024-05-07-using-fluent-validation-with-abp/images/validation.png b/docs/en/Community-Articles/2024-05-07-using-fluent-validation-with-abp/images/validation.png new file mode 100644 index 0000000000..6131739d68 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-07-using-fluent-validation-with-abp/images/validation.png differ diff --git a/docs/en/Community-Articles/2024-05-07-using-fluent-validation-with-abp/post.md b/docs/en/Community-Articles/2024-05-07-using-fluent-validation-with-abp/post.md new file mode 100644 index 0000000000..494f6a9a0a --- /dev/null +++ b/docs/en/Community-Articles/2024-05-07-using-fluent-validation-with-abp/post.md @@ -0,0 +1,115 @@ +# Using FluentValidation with ABP Framework + +## What is Validation? Why Do We Need to Validate? +Validation is checking whether data is valid or not. We can liken validations to the cell membrane of our application. Just as the cell does not want to let in harmful substances, we do not want to add erroneous data to the database, which is critical to our application. Validations allow data that follows the rules to reach the database. Data that does not comply with the rules will not access the database at all, and the operation will fail. + +![Validation](./images/validation.png) + +Validations make your application run more efficiently as they are not directly tied to the database. They should be implemented across various layers of the application, including the UI, backend, and database, to prevent malicious users from bypassing these checks. Fluent validation is frequently employed for creating backend validations. + +## What is Fluent Validation? +Fluent validation is a library for checking whether data is valid or not. Fluent validation can be applied to your code in a fluent and understandable way. + +## Why We Should Use Fluent Validation? +Fluent Validation allows you to define your validation rules in a clear and flexible way. This means you can comfortably handle complex validation scenarios in your code. This makes your development process much more manageable. The readability that Fluent Validation offers really makes things easier. Having a clear understanding of what your validation rules do is a huge advantage when working on your code. In short, your code is cleaner and clearer. Fluent Validation is also very functional in terms of testability. By defining your validation rules in separate classes, you can easily test and maintain these rules. Fluent Validation is a widely used validation library on the .NET platform. As such, it has become a common standard among .NET developers. This provides advantages in terms of community support and compatibility. So, using Fluent Validation simplifies your development process by making your code more understandable, manageable and testable. + +In this section, I will show you how to use FluentValidation library within an ABP-based application. Therefore, I assume that you have an ABP-based application that has already been created. If you haven't created an ABP-based application yet, please follow the [Getting Started documentation](https://docs.abp.io/en/abp/latest/Getting-Started-Create-Solution?UI=MVC&DB=EF&Tiered=No). + +Using Fluent validation with Abp is quite simple. Open a command line window in the folder of the project (.csproj file) and type the following command: + +```bash +abp add-package Volo.Abp.FluentValidation +``` + +If you have not created your abp project, review the [steps to create](https://docs.abp.io/en/abp/latest/Tutorials/Todo/Overall) it now. + +Create the `Product` entity as below: + +````csharp + public class Product: FullAuditedAggregateRoot + { + public string Name { get; set; } = string.Empty; + public decimal Price { get; set; } + public int Stock { get; set; } + public string? LicenseKey { get; set; } + } +```` + +You must have ProductCreateDto : + +````csharp + public class ProductCreateDto + { + public string Name { get; set; } + public decimal Price { get; set; } + public int Stock { get; set; } + public string? LicenseKey { get; set; } + } +```` +Create the `ProductCreateDtoValidator` class in the **Products** folder in the `Application.Contracts` project: + +````csharp + public class ProductCreateDtoValidator :AbstractValidator +{ + public ProductCreateDtoValidator() + { + RuleFor(p=>p.Name). + NotEmpty(). + WithMessage("Product name cannot be empty"); + + RuleFor(p=>p.Name). + MinimumLength(3). + MaximumLength(100). + WithMessage("Product name must be between 3 and 100 characters"); + + RuleFor(p => p.Stock). + GreaterThanOrEqualTo(0). + WithMessage("Product stock should not be negative"); + + RuleFor(p => p.Price). + GreaterThanOrEqualTo(0). + WithMessage("Product Price should not be negative"); + } +} +```` +The validator class you create should inherit from `AbstractValidator`. You should give `AbstractValidator` the class you want to validate generically. You have to create a constructor method. You must write the code in this constructor method. Fluent validation provides you with ready-made methods that you can use to write validations very easily. + +The **RuleFor** method allows you to write a validation rule. You must specify in the parameter for which property you want to write a validation rule. + +With the **NotEmpty** method you can specify that a property cannot be null. + +With **MinimumLength** and **MaximumLength** you can specify the minimum and maximum number of characters the property can take. + +With the **GreaterThanOrEqualTo** method you can specify that the value of the property must be greater than or equal to the value entered as a parameter. + +**WithMessage** method you can specify the message to be sent when the validation fails. + +You can add a method to write your own customized validation code. For example, let's write the code that requires the license key field to contain the word “key”. + +````csharp + private bool ContainsKey(string arg) + { + return arg.IndexOf("key", StringComparison.OrdinalIgnoreCase) >= 0; + } +```` + +Add the code to the constructor to use this method: + +````csharp +RuleFor(p => p.LicenseKey). + Must(ContainsKey). + WithMessage("Product license key must contain the word 'key'"); + +```` +Try to add data that does not meet the validation rules + +![Adding Incorrect Data](./images/adding-incorrect-data.png) + +If one of the validation rules does not meet the rules, then the following error will be received for the custom rule that we defined: + +![Error](./images/error.png) + +For more information on fluent validation with abp framework, see the [documentation](https://docs.abp.io/en/abp/latest/FluentValidation) + +For more information on fluent validation, see the [documentation](https://docs.fluentvalidation.net/en/latest/)  + diff --git a/docs/en/Community-Articles/2024-05-09-what-is-object-to-object-mapping/images/automapper.png b/docs/en/Community-Articles/2024-05-09-what-is-object-to-object-mapping/images/automapper.png new file mode 100644 index 0000000000..103e8f2261 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-09-what-is-object-to-object-mapping/images/automapper.png differ diff --git a/docs/en/Community-Articles/2024-05-09-what-is-object-to-object-mapping/images/swagger1.png b/docs/en/Community-Articles/2024-05-09-what-is-object-to-object-mapping/images/swagger1.png new file mode 100644 index 0000000000..d4e2cc10f8 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-09-what-is-object-to-object-mapping/images/swagger1.png differ diff --git a/docs/en/Community-Articles/2024-05-09-what-is-object-to-object-mapping/images/swagger2.png b/docs/en/Community-Articles/2024-05-09-what-is-object-to-object-mapping/images/swagger2.png new file mode 100644 index 0000000000..67a4b7ff3f Binary files /dev/null and b/docs/en/Community-Articles/2024-05-09-what-is-object-to-object-mapping/images/swagger2.png differ diff --git a/docs/en/Community-Articles/2024-05-09-what-is-object-to-object-mapping/post.md b/docs/en/Community-Articles/2024-05-09-what-is-object-to-object-mapping/post.md new file mode 100644 index 0000000000..283dd8e00d --- /dev/null +++ b/docs/en/Community-Articles/2024-05-09-what-is-object-to-object-mapping/post.md @@ -0,0 +1,134 @@ +# What is Object to Object Mapping? + +Mapping the properties of one object to the properties of another object is called **Object to Object Mapping**. Most of the time, you don't want to show the data you store in your database to end users as it is. Instead, you only return users the information they need for that operation and reduce the output size. + +For example, in database tables that contain relationships, we analyze the relationships and present meaningful data to users. Suppose we have a product and a category object, we keep a property called `categoryId` in the `Product` entity. However, it would be illogical to show the `categoryId ` property to users. Therefore, we can create a DTO (data transfer object) and show the **category name** to the end users, instead of the `categoryId` directly. + +DTOs are used to transfer data of objects from one object to another one. We often need to map our entities to DTOs and DTOs to entities. For example, consider the code below: + +````csharp + public virtual async Task CreateAsync(CustomerCreateDto input) + { + + var customer = await _customerManager.CreateAsync( + input.BirthDay, input.MembershipDate, input.FirstName, input.LastName + ); + CustomerDto customerDto = new CustomerDto + { + Id = customer.Id, + FirstName = input.FirstName, + LastName = input.LastName, + // ...other + }; + + return customerDto; + } + +```` +As can be seen here, it's repetitive and tedious to manually map an object to another similar object. Also, it violates the [DRY principle](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself), makes your code more complicated and reduces readability. Instead of manually mapping objects, you can use the [AutoMapper](https://automapper.org/) library to automatically map two objects' properties: + + +````csharp + public virtual async Task CreateAsync(CustomerCreateDto input) + { + + var customer = await _customerManager.CreateAsync( + input.BirthDay, input.MembershipDate, input.FirstName, input.LastName + ); + + return ObjectMapper.Map(customer); + } +```` +The **ObjectMapper.Map** method allows you to convert your `Customer` entity to `CustomerDto`. `IObjectMapper` interface is a service, that comes from the **AutoMapper** library, so let's learn more about **AutoMapper** in the next section. + +# What is AutoMapper? + +Automapper is a .NET library that automates object-to-object mapping. ABP provides abstractions for object-to-object mapping and has an integration package to use [AutoMapper](http://automapper.org/) as the object mapper. + +Automapper is a library that transforms similar objects into each other. We can imagine Automapper as a machine that transforms an apple with a hat into an apple without a hat: + +![AutoMapper](./images/automapper.png) + +In this chapter, I will show you how to use the AutoMapper library in an ABP-based application. For this reason, I assume that you already have an ABP-based application created. If you have not yet created an ABP-based application, please follow the [Getting Started documentation](https://docs.abp.io/en/abp/latest/Getting-Started-Create-Solution?UI=MVC&DB=EF&Tiered=No). + +Create a domain entity similar to this one: + +````csharp + public class Customer : FullAuditedAggregateRoot + { + public string? FirstName { get; set; } + public string? LastName { get; set; } + public DateTime BirthDay { get; set; } + public DateTime MembershipDate { get; set; } + } +```` +`Customer` entity contains some properties (such as `FirstName`, `LastName`, ... and other audited properties coming from the base class - `DeleterId`, `IsDeleted`, `CreationTime` etc. -). Typically, you would not want to show/return all of these properties to end users, at that point, you can create a DTO class and only define the properties that you want to return to the end users. + +Let's create the `CustomerGetDto` class in the `*.Application.Contracts` project as follows: + +````csharp + public class CustomerGetDto + { + public string? FirstName { get; set; } + public string? LastName { get; set; } + public DateTime BirthDay { get; set; } + } +```` + +After creating our entity and output DTO classes, now in the application service implementation, we can return the `CustomerGetDto` class, as a result of listing the customers. For that reason, we can write a code as follows: + +````csharp +public virtual async Task> GetListAsync(GetCustomersInput input) + { + var totalCount = await _customerRepository.GetCountAsync(input.FilterText, input.FirstName, input.LastName, input.BirthDayMin, input.BirthDayMax, input.MembershipDateMin, input.MembershipDateMax); + var items = await _customerRepository.GetListAsync(input.FilterText, input.FirstName, input.LastName, input.BirthDayMin, input.BirthDayMax, input.MembershipDateMin, input.MembershipDateMax, input.Sorting, input.MaxResultCount, input.SkipCount); + + return new PagedResultDto + { + TotalCount = totalCount, + Items = ObjectMapper.Map, List>(items) + }; + } +```` +In this code, we first get the total number of our customers and all customers according to the specified filters, then we map `List` to `List` using the `ObjectMapper.Map` method from the **ApplicationService** base class. This way we have full control over which properties are returned to the end users. + +After mapping the `Customer` entity to the `CustomerGetDto` class. Before running our application, we should define the mappings in the `*AutoMapperProfile` class in the `*.Application` project as follows: + +````csharp +public class YourApplicationAutoMapperProfile : Profile +{ + public YourApplicationAutoMapperProfile() + { + CreateMap(); + } +} +```` +Finally, we can run our application and navigate to the **/swagger** endpoint to try our endpoint. When we send a request, we should get the result as follows: + +![Swagger](./images/swagger1.png) + +## Advanced: Mapping Configurations + +In some scenarios, you may want to make some customizations when mapping two objects. For example, let's assume that you want to create the `CustomerGetDto` class as follows: + +````csharp + public class CustomerGetDto + { + public string? FullName { get; set; } + public int Age { get; set; } + } +```` +AutoMapper can't map these properties automatically, because they do not exist in the source object, which is the `Customer` entity. Therefore, you need to specify the exception and update your `YourApplicationAutoMapperProfile` class as follows: + +````csharp + +CreateMap().ForMember(c=>c.FullName,opt=> opt.MapFrom(src => src.FirstName + " " + src.LastName)) + .ForMember(c=>c.Age, opt=> opt.MapFrom(src=> DateTime.UtcNow.Year -src.BirthDay.Year)); + +```` +This configuration concatenates and matches **FirstName** and **LastName** properties into the **FullName** property and subtracts **BirthDate** from today's year and assigns it to the customer's **Age**. +After these configurations, if you make a request to the relevant endpoint, the output will look like: + +![Swagger](./images/swagger2.png) + +For more information on object-to-object mapping with [ABP Framework](https://abp.io/), see the [documentation](https://docs.abp.io/en/abp/latest/Object-To-Object-Mapping). diff --git a/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/POST.md b/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/POST.md new file mode 100644 index 0000000000..e6417b70ce --- /dev/null +++ b/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/POST.md @@ -0,0 +1,340 @@ +# Sentiment Analysis Within ABP-Based Application + +In this article, first I will briefly explain what sentiment analysis is and then show you how you can apply sentiment analysis in an ABP-Based application (or any kind of .NET application). + +We will use ML.NET Framework, which is an open-source machine learning framework created by the dotnet team and also we will create a layered ABP Solution by using the application template and finally we will use CMS Kit's Comment Feature and extend its behavior by adding spam detection while creating or updating a comment, at that point we will make sentiment analysis. + +## Sentiment Analysis + +[Sentiment Analysis (or opinion mining)](https://en.wikipedia.org/wiki/Sentiment_analysis) refers to determining the emotion from the given input. The primary goal of sentiment analysis is to identify, extract, and categorize (positive, negative, or neutral) the sentiments expressed in textual data. + +To understand it better, let's check the following figure and examine the comments: + +![](sentiment-analysis.png) + +* If you look at these comments, you will notice that comments have ratings and it's easy to understand the emotion or thoughts of the users who commented about the related product. +* But even if there was not any rating specified for the given comments we still can get the emotion of the users. Because, as you can see, the comments specified some obvious words that express emotions, for example, in the first comment, the user says **he/she liked the product**, **it's easy to use** and **its battery is good**, and therefore this is obviously a positive comment. +* On the other hand, if we look at the second comment, we will notice some negative statements such as **useless phone**, **cannot maintain any data connection** and the user suggests **do not buy this phone**. Actually, this is what sentiment analysis is all about, abstracting the emotion from a given input, it's comment in that case but it can be any kind of input or input-group. + +## Demo: Spam Detection (Applying Sentiment Analysis) + +> You can get the source code of the demo from [https://github.com/EngincanV/SentimentAnalysisDemo](https://github.com/EngincanV/SentimentAnalysisDemo). + +In this demo application, we will create an [ABP-based application](https://docs.abp.io/en/abp/8.1/Startup-Templates/Application) and integrate the [ABP's CMS Kit Module's Comment Feature](https://docs.abp.io/en/abp/latest/Modules/Cms-Kit/Comments), which provides a comment system to add a comment to any kind of resource, such as blog posts or products. + +By default, CMS Kit's Comment Feature does not provide spam detection and therefore in this sample application, we will add [spam detection](https://github.com/EngincanV/SentimentAnalysisDemo/blob/master/src/SentimentAnalysisDemo.Application/ML/SpamDetector.cs) while creating or updating a comment. Thus, whenever a comment is being added or updated, the spam detection service will validate the comment and reject it if it contains spam content otherwise it will make the other validations and save the comment: + +![](sentiment-analysis-steps.png) + +To get started, we will first create an application, and add the CMS Kit Module to the solution and then we will enable the Comment Feature of the CMS Kit Module, and finally, we will add the Comment Component to the homepage and add spam detection by extending the behavior. Let's start with creating the application! + +### Creating an ABP-Based Application + +You can use the following command to create a layered ABP solution (with MongoDB as the database option): + +```bash +abp new SentimentAnalysisDemo -t app -d mongodb --version 8.1.1 +``` + +### Installing the CMS Kit Module + +After creating the project, we can add the CMS Kit module to our project. [ABP CLI](https://docs.abp.io/en/abp/latest/CLI) provides the `add-module` command to install a specific module to a solution. + +You can use the following command to install the CMS Kit module into your application (run this command in the solution directory): + +```bash +abp add-module Volo.CmsKit --skip-db-migrations +``` + +After this command is executed, all related CMS Kit packages will be added to the correct layers and then you can enable any CMS Kit feature you want. + +### Enabling the Comment Feature + +By default, CMS Kit features are disabled. Therefore, you need to enable the features you want, before starting to use it. You can either enable all of them or enable them one by one. In our demo application, we only need the **Comment Feature**, therefore we can only enable it. + +To enable the Comment Feature, you can open the `SentimentAnalysisDemoGlobalFeatureConfigurator` class (under the `*.Domain.Shared` project) and update it as follows: + +```csharp +using Volo.Abp.GlobalFeatures; +using Volo.Abp.Threading; + +namespace SentimentAnalysisDemo; + +public static class SentimentAnalysisDemoGlobalFeatureConfigurator +{ + private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); + + public static void Configure() + { + OneTimeRunner.Run(() => + { + GlobalFeatureManager.Instance.Modules.CmsKit(cmsKit => + { + cmsKit.Comments.Enable(); + }); + }); + } +} +``` + +After enabling the feature, now we can make the final configurations and directly use it in our application. + +### Configurations for Comment Feature + +Open the `SentimentAnalysisDemoDomainModule` class and add the following code-block into the `ConfigureServices` method: + +```csharp + Configure(options => + { + options.EntityTypes.Add(new CommentEntityTypeDefinition("Comment")); + options.IsRecaptchaEnabled = true; + }); +``` + +Here, we simply defining what should be the entity-type name of our comment and also enable the reCaptcha for the comment system. After this configuration, now we can open the `Index.cshtml` file in the `*.Web` project and invoke the `CommentingViewComponent` as below: + +```html +@page +@using Microsoft.AspNetCore.Mvc.Localization +@using SentimentAnalysisDemo.Localization +@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Commenting +@model SentimentAnalysisDemo.Web.Pages.IndexModel + +
+
Comments:
+ + @await Component.InvokeAsync(typeof(CommentingViewComponent), new + { + entityType = "Comment", + entityId = "SentimentAnalysisDemo", + isReadOnly = false + }) +
+ +``` + +After adding the related component, now you can run the web project and see the comment component if you want. + +### Applying Sentiment Analysis (Creating the Spam Detection Service) + +By default, CMS Kit's Comment Feature does not provide a spam detection system. In this demo application, we will override the `CommentPublicAppService`'s `CreateAsync` and `UpdateAsync` methods and then will add the spam detection control whenever a new comment has been submitted or an existing one is being updated. + +To override the `CommentPublicAppService` and extend its use-case implementations, create a `MyCommentAppService` class and update its content as below: + +```csharp +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using SentimentAnalysisDemo.ML; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus.Distributed; +using Volo.CmsKit.Comments; +using Volo.CmsKit.Public.Comments; +using Volo.CmsKit.Users; + +namespace SentimentAnalysisDemo.Volo.CmsKit.Public.Comments; + +[Dependency(ReplaceServices = true)] +[ExposeServices(typeof(ICommentPublicAppService), typeof(CommentPublicAppService), typeof(MyCommentAppService))] +public class MyCommentAppService : CommentPublicAppService +{ + protected ISpamDetector SpamDetector { get; } + + public MyCommentAppService( + ICommentRepository commentRepository, + ICmsUserLookupService cmsUserLookupService, + IDistributedEventBus distributedEventBus, + CommentManager commentManager, + IOptionsSnapshot cmsCommentOptions, + ISpamDetector spamDetector + ) + : base(commentRepository, cmsUserLookupService, distributedEventBus, commentManager, cmsCommentOptions) + { + SpamDetector = spamDetector; + } + + public override async Task CreateAsync(string entityType, string entityId, CreateCommentInput input) + { + //Check message: spam or ham. + await SpamDetector.CheckAsync(input.Text); + + return await base.CreateAsync(entityType, entityId, input); + } + + public override async Task UpdateAsync(Guid id, UpdateCommentInput input) + { + //Check message: spam or ham. + await SpamDetector.CheckAsync(input.Text); + + return await base.UpdateAsync(id, input); + } +} +``` + +Here, we simply just inject the `ISpamDetector` service, which we will create in a minute, and use its `CheckAsync` method to make a spam check before the comment is created or updated. + +Now, we can create the `ISpamDetector` service in the `*.Application.Contracts` project as follows: + +```csharp +using System.Threading.Tasks; + +namespace SentimentAnalysisDemo.ML; + +public interface ISpamDetector +{ + Task CheckAsync(string text); +} +``` + +Then, we can create the `SpamDetector` and implement the `ISpamDetector` interface (in the `*.Application` project): + +```csharp +using System; +using System.IO; +using System.Threading.Tasks; +using Microsoft.ML; +using SentimentAnalysisDemo.ML.Model; +using Volo.Abp; +using Volo.Abp.DependencyInjection; + +namespace SentimentAnalysisDemo.ML; + +public class SpamDetector : ISpamDetector, ITransientDependency +{ + public async Task CheckAsync(string text) + { + //check if the text contains a spam content or not... + + } +} +``` + +The `CheckAsync` method is where we need to make the sentiment analysis and detect if the comment contains spam content or not. If it's spam, then we should throw a [UserFriendlyException](https://docs.abp.io/en/abp/latest/Exception-Handling#user-friendly-exception) and notify the user that the comment should be updated and should not contain any spam content. + +#### Spam Detection + +Before, making the spam check, we should have a dataset to train a machine-learning model and add `Microsoft.ML` package into our project. For that purpose, I searched in [Kaggle](https://www.kaggle.com/) for spam datasets, found the **Spam-Mail-Detection-Dataset** from Kaggle, and downloaded the csv file to use in my application. Therefore, [you should also download the dataset from the link and put it under the **/ML/Data/spam_data.csv** directory of the `*.Web` project](https://github.com/EngincanV/SentimentAnalysisDemo/blob/master/src/SentimentAnalysisDemo.Web/ML/Data/spam_data.csv). + +Here is what our dataset looks like (**0 -> not spam / 1 -> spam**): + +| Category | Message | +|----------|---------| +| 0 | Is that seriously how you spell his name? | +| 1 | Free entry in 2 a wkly comp to win FA Cup final tkts 21st May 2005. Text FA to 87121 to receive entry question(std txt rate)T&C's apply 08452810075over18's | +| . | . | +| . | . | +| . | . | + +> **Note:** This dataset is not ready-to use in a real-world solution. It's for mail spam detection but for the simplicity of the sample, it's not important and can be used for development purposes. + +After, downloading the dataset and putting it in the directory of **/ML/Data**, now we can add the `Microsoft.ML` package into our `*.Application` project: + +```bash +dotnet add package Microsoft.ML +``` + +Finally, we can implement the `CheckAsync` method and use sentiment analysis to make spam checks as follows: + +```csharp + + public async Task CheckAsync(string text) + { + var dataPath = Path.Combine(Environment.CurrentDirectory, "ML", "Data", "spam_data.csv"); + + var mlContext = new MLContext(); + + //Step 1: Load Data 👇 + IDataView dataView = mlContext.Data.LoadFromTextFile(dataPath, hasHeader: true, separatorChar: ','); + + //Step 2: Split data to train-test data 👇 + DataOperationsCatalog.TrainTestData trainTestSplit = mlContext.Data.TrainTestSplit(dataView, testFraction: 0.2); + IDataView trainingData = trainTestSplit.TrainSet; //80% of the data. + IDataView testData = trainTestSplit.TestSet; //20% of the data. + + //Step 3: Common data process configuration with pipeline data transformations + choose and set the training algorithm 👇 + var estimator = mlContext.Transforms.Text.FeaturizeText(outputColumnName: "Features", inputColumnName: nameof(SentimentAnalyzeInput.Message)) + .Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression(labelColumnName: "Label", featureColumnName: "Features")); + + //Step 4: Train the model 👇 + ITransformer model = estimator.Fit(trainingData); + + //Step 5: Predict 👇 + var sentimentAnalyzeInput = new SentimentAnalyzeInput + { + Message = text + }; + + var predictionEngine = mlContext.Model.CreatePredictionEngine(model); + var result = predictionEngine.Predict(sentimentAnalyzeInput); + if (IsSpam(result)) + { + throw new UserFriendlyException("Spam detected! Please update the message!"); + } + } + + private static bool IsSpam(SentimentAnalyzeResult result) + { + //1 -> spam / 0 -> ham (for 'Prediction' column) + return result is { Prediction: true, Probability: >= 0.5f }; + } + +``` + +Here, we have done the following things: + +1. **First, we loaded the data**: For that reason, we created a `MLContext` object, which is a main class for all ML.NET operations. Then, we used its `LoadFromTextFile` method and specified the dataset path in our application. Also, we mapped the dataset columns to the `SentimentAnalyzeInput` class, which we will create later on. +2. **For the second step, we split the data as training and testing data**: To be able to train a machine learning model and then evaluate its accuracy, we should not use all the data for training purposes, instead, we should split the data as training and testing data and after training the model, compare the training data accuracy with the testing data. +3. **For the third step, we should make data transformation, convert the text-based data into numeric vectors and then choose a training algorithm**: After splitting the data for training and testing purposes, now we can apply some data transformations for the *Message* column in our dataset. Because, as you would see, messages are text-based inputs and machine-learning algorithms work best with the numeric vectors. So, we are making data transformations and representing the data as numeric values. Then, we can apply `BinaryClassification` with the **SdcaLogicticRegression** algorithm to our training data. +4. **Train the model**: Since we make the data transformations and chose the correct algorithm for our model, now we can train the model. +5. **Predict the sample data**: Finally, we can pass a comment to this method and make spam check and either approve our reject the comment according to the predicted result. (To make predictions, we need to create a **PredictionEngine** and get the final results in the output class that we specified, `SentimentAnalyzeResult` in our example) + +Let's create the `SentimentAnalyzeInput` and `SentimentAnalyzeResult` classes as follows. + +**SentimentAnalyzeInput.cs:** + +```csharp +using Microsoft.ML.Data; + +namespace SentimentAnalysisDemo.ML.Model; + +public class SentimentAnalyzeInput +{ + [LoadColumn(0), ColumnName("Label")] + public bool Category { get; set; } + + [LoadColumn(1), ColumnName("Message")] + public string Message { get; set; } +} +``` + +**SentimentAnalyzeResult.cs:** + +```csharp +using Microsoft.ML.Data; + +namespace SentimentAnalysisDemo.ML.Model; + +public class SentimentAnalyzeResult +{ + [ColumnName("PredictedLabel")] + public bool Prediction { get; set; } + + public float Probability { get; set; } + + public float Score { get; set; } +} +``` + +Then, finally, we can run the application to see the final results: + +![](demo.gif) + +## Advanced: Reusing And Optimizing Machine Learning Models + +Once the model is trained and evaluated, we can save the trained model and use it directly for further use. In this way, you don’t have to retrain the model every time when you want to make predictions. It’s essential to save the trained model for future use and a must for the production-ready code. I created a separate article dedicated to that topic, and if you are interested, you can read it from [here](https://engincanv.github.io/machine-learning/sentiment-analysis/best-practises/2024/05/16/reusing-and-optimizing-machine-learning-models-in-dotnet.html). + +## Conclusion + +In this article, I briefly explain what sentiment analysis is, created a sample ABP-based application, integrated the CMS Kit Module and finally, applied sentiment analysis to make spam checks whenever a new comment has been submitted or updated. You can get the source code of the demo from [https://github.com/EngincanV/SentimentAnalysisDemo](https://github.com/EngincanV/SentimentAnalysisDemo) + +Thanks for reading :) diff --git a/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/cover-image.png b/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/cover-image.png new file mode 100644 index 0000000000..7091f1a6b5 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/cover-image.png differ diff --git a/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/demo.gif b/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/demo.gif new file mode 100644 index 0000000000..5a373ba110 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/demo.gif differ diff --git a/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/sentiment-analysis-steps.png b/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/sentiment-analysis-steps.png new file mode 100644 index 0000000000..4222b4c97c Binary files /dev/null and b/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/sentiment-analysis-steps.png differ diff --git a/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/sentiment-analysis.png b/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/sentiment-analysis.png new file mode 100644 index 0000000000..9597476dca Binary files /dev/null and b/docs/en/Community-Articles/2024-05-10-Sentiment-Analysis-within-ABP-Based-Application/sentiment-analysis.png differ diff --git a/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/POST.md b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/POST.md new file mode 100644 index 0000000000..f94e92a548 --- /dev/null +++ b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/POST.md @@ -0,0 +1,228 @@ +# Deploy Your ABP Framework Angular Project to Azure Kubernetes Service (AKS) + +![ABP Framework Angular Project](abp-angular-aks-helm.png) + +In my previous article on [Deploy Your ABP Framework MVC Project to Azure Container Apps](https://community.abp.io/posts/deploy-your-abp-framework-mvc-project-to-azure-container-apps-r93u9c6d), I talked about how ABP Mvc project can be easily deployed to Azure Container Apps. Now I will show how we can deploy to kubernetes environment, which looks a bit more complex but is more preferred for production, using a Helm chart. + +### Getting Started with ABP Framework Angular and Azure Kubernetes Service + +To get started, you will need an ABP Framework Angular project that you want to deploy. If you don't have one, you can [create a new project using the ABP CLI](https://docs.abp.io/en/abp/latest/Startup-Templates/Application). You will also need [an Azure subscription](https://azure.microsoft.com) and [an Azure Kubernetes Service](https://azure.microsoft.com/en-gb/services/kubernetes-service/). + +### Configuring Your ABP Framework Angular Project + +We have a sample ABP Framework Angular project that we will use for this deployment. Before creating the Docker image and Helm chart, you just need to configure `aspnet-core/src/***.HttpApi.Host/***.HttpApiHostModule.cs` file to allow CORS requests from your frontend application. You can do this by updating the following code to the `ConfigureServices` method: + +```csharp +public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + var hostingEnvironment = context.Services.GetHostingEnvironment(); + + if (!configuration.GetValue("App:DisablePII")) + { + Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true; + } + + if (!configuration.GetValue("AuthServer:RequireHttpsMetadata")) + { + Configure(options => + { + options.DisableTransportSecurityRequirement = true; + }); + } + context.Services.Configure(options => + { + options.ForwardedHeaders = ForwardedHeaders.XForw +``` + +![Configure CORS](configure-cors.png) + +If your ABP Framework Angular project and Azure kubernetes cluster ready, we can start to build the docker images and pushing them to any container registry. In this article, I will use DockerHub as the container registry. + +I will also show you how I automated the steps that I originally did manually to make it simpler in the beginning and then automated them in Azure Devops. + +### Creating a Docker Image for ABP Framework Angular + +To create a Docker image for your ABP Framework Angular project, navigate to `etc/build/build-images-locally.ps1` and fix the script to match your Docker Hub username and image name. Then, run the script to build the Docker image locally. + +![Build Docker Image](build-docker-image.png) + +At the end of this process, check your Docker Hub repository to confirm that the image has been pushed successfully. My Docker Hub repository looks like this. Also you can use these my public images to test the deployment. + +![Docker Hub Repository](docker-hub-repository.png) + +### Creating Helm Chart for ABP Framework Angular + +To deploy your ABP Framework Angular project to Azure Kubernetes Service, you need to create a Helm chart. Helm is a package manager for Kubernetes that allows you to define, install, and upgrade even the most complex Kubernetes applications. Helm uses a packaging format called charts, which are a collection of files that describe a related set of Kubernetes resources. + +These helm charts are prepared to create a deployment, configmap, service and ingress for your ABP Framework Angular project. It is prepared not only for migration, frontend and backend, but also to create the sqlserver and redis that the application needs as a kubernetes service. If you already have redis and sqlserver, you don't need to stand them up in kubernetes, of course. + +![Helm Chart](helm-chart.png) + +You can find the helm chart in the https://github.com/skoc10/k8s_works/tree/main/demo/helm/k8s/angular repository. You can configure the `values-azure.yaml` file according to your needs. + +### Deploying to Azure Kubernetes Service + +`Note:` You need to have nginx-ingress-controller and cert-manager installed for letsencrypt certificate in your kubernetes cluster. + +Now that you have Docker images for your ABP Framework Angular project and a Helm chart, you can proceed to deploy it to Azure Kubernetes Service. To do this, you need to create a new Azure Kubernetes Service resource and configure the `values-azure.yaml` file according to your needs. If you want, you can deploy a single Helm with `demo/helm/k8s/deploy-staging.ps1` script you can deploy each chart separately. + +![Create Azure Kubernetes Service](create-azure-kubernetes-service.png) + +After deploying the Helm chart, you can check the deployment status to confirm that the deployment was successful. You can also check the logs of the pods to see if there are any errors. + +![Deploy Helm Chart](deploy-helm-chart.png) + +Finally, you can navigate to the web url to see your ABP Framework Angular project running in Azure Kubernetes Service. + +![ABP Framework Angular Project](abp-angular-aks.png) + +### CI/CD with Azure DevOps + +I have automated the steps that I originally did manually to make it simpler in the beginning and then automated them in Azure Devops. You can find the `azure-pipelines.yml` file in the https://github.com/skoc10/k8s_works/blob/main/demo/azure/azure-pipelines.yml repository. You can configure the `azure-pipelines.yml` file according to your needs. + +```yaml +trigger: + tags: + include: + - "*.*.*" + +variables: + dockerRegistryServiceConnection: 'demo-reg' + buildContextBasePath: '$(Build.SourcesDirectory)' + tag: $(Build.BuildNumber) + DOCKER_BUILDKIT: 1 + +pool: + name: ubuntu + +stages: +- stage: Build + displayName: Build + jobs: + - job: CheckChanges + displayName: Check if Angular or ASP.NET Core has changed + pool: + name: ubuntu + steps: + - checkout: self + +# Migration + - task: Docker@2 + displayName: 'Build Migration Docker image' + inputs: + command: build + repository: demo-angular-apppro/migration + dockerfile: $(buildContextBasePath)/aspnet-core/src/Demo.AzureAppsAngular.DbMigrator/Dockerfile.azure + buildContext: $(buildContextBasePath)/aspnet-core + containerRegistry: $(dockerRegistryServiceConnection) + tags: | + $(tag) + + - task: Docker@2 + displayName: 'Push Migration Docker image' + inputs: + command: push + repository: demo-angular-apppro/migration + containerRegistry: $(dockerRegistryServiceConnection) + tags: | + $(tag) + + - task: HelmDeploy@0 + displayName: 'Delete Migrator' + inputs: + connectionType: Kubernetes Service Connection + kubernetesServiceConnection: 'aks-demoms' + namespace: 'angular' + command: delete + arguments: dbmigrator + continueOnError: true + + - task: HelmDeploy@0 + displayName: 'Deploy Migration to AKS' + inputs: + connectionType: Kubernetes Service Connection + kubernetesServiceConnection: 'aks-demoms' + namespace: 'angular' + command: 'upgrade' + chartType: 'FilePath' + chartPath: '$(buildContextBasePath)/aspnet-core/etc/k8s/angular/charts/dbmigrator' + releaseName: 'dbmigrator' + overrideValues: 'image.tag=$(tag)' + valueFile: '$(buildContextBasePath)/aspnet-core/etc/k8s/angular/charts/dbmigrator/values.yaml' + waitForExecution: false + +# Backend + - task: Docker@2 + displayName: 'Build Backend Docker image' + inputs: + command: build + repository: demo-angular-apppro/backend + dockerfile: $(buildContextBasePath)/aspnet-core/src/Demo.AzureAppsAngular.HttpApi.Host/Dockerfile.azure + buildContext: $(buildContextBasePath)/aspnet-core + containerRegistry: $(dockerRegistryServiceConnection) + tags: | + $(tag) + + - task: Docker@2 + displayName: 'Push Backend Docker image' + inputs: + command: push + repository: demo-angular-apppro/backend + containerRegistry: $(dockerRegistryServiceConnection) + tags: | + $(tag) + + - task: HelmDeploy@0 + displayName: 'Deploy Backend to AKS' + inputs: + connectionType: Kubernetes Service Connection + kubernetesServiceConnection: 'aks-demoms' + namespace: 'angular' + command: 'upgrade' + chartType: 'FilePath' + chartPath: '$(buildContextBasePath)/aspnet-core/etc/k8s/angular/charts/backend' + releaseName: 'backend' + overrideValues: 'image.tag=$(tag)' + valueFile: '$(buildContextBasePath)/aspnet-core/etc/k8s/angular/charts/backend/values.yaml' + waitForExecution: false + +# Frontend + - task: Docker@2 + displayName: 'Build Frontend Docker image' + inputs: + command: build + repository: demo-angular-apppro/frontend + dockerfile: $(buildContextBasePath)/angular/Dockerfile.azure + buildContext: $(buildContextBasePath)/angular + containerRegistry: $(dockerRegistryServiceConnection) + tags: | + $(tag) + + - task: Docker@2 + displayName: 'Push Frontend Docker image' + inputs: + command: push + repository: demo-angular-apppro/frontend + containerRegistry: $(dockerRegistryServiceConnection) + tags: | + $(tag) + + - task: HelmDeploy@0 + displayName: 'Deploy Frontend to AKS' + inputs: + connectionType: Kubernetes Service Connection + kubernetesServiceConnection: 'aks-demoms' + namespace: 'angular' + command: 'upgrade' + chartType: 'FilePath' + chartPath: '$(buildContextBasePath)/aspnet-core/etc/k8s/angular/charts/angular' + releaseName: 'frontend' + overrideValues: 'image.tag=$(tag)' + valueFile: '$(buildContextBasePath)/aspnet-core/etc/k8s/angular/charts/angular/values.yaml' + waitForExecution: false +``` + +### Conclusion + +In this article, I showed you how you can deploy your ABP Framework Angular project to Azure Kubernetes Service using Helm chart. I also showed you how you can automate the deployment process using Azure DevOps. I hope you found this article helpful. If you have any questions or feedback, please feel free to leave a comment below. \ No newline at end of file diff --git a/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/abp-angular-aks-helm.png b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/abp-angular-aks-helm.png new file mode 100644 index 0000000000..0e861b2a68 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/abp-angular-aks-helm.png differ diff --git a/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/abp-angular-aks.png b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/abp-angular-aks.png new file mode 100644 index 0000000000..1790b100e2 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/abp-angular-aks.png differ diff --git a/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/build-docker-image.png b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/build-docker-image.png new file mode 100644 index 0000000000..12baa30af4 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/build-docker-image.png differ diff --git a/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/configure-cors.png b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/configure-cors.png new file mode 100644 index 0000000000..def6e9b97e Binary files /dev/null and b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/configure-cors.png differ diff --git a/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/create-azure-kubernetes-service.png b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/create-azure-kubernetes-service.png new file mode 100644 index 0000000000..88c5c3b97e Binary files /dev/null and b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/create-azure-kubernetes-service.png differ diff --git a/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/deploy-helm-chart.png b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/deploy-helm-chart.png new file mode 100644 index 0000000000..b58be08115 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/deploy-helm-chart.png differ diff --git a/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/docker-hub-repository.png b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/docker-hub-repository.png new file mode 100644 index 0000000000..1a58455658 Binary files /dev/null and b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/docker-hub-repository.png differ diff --git a/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/helm-chart.png b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/helm-chart.png new file mode 100644 index 0000000000..398a724baf Binary files /dev/null and b/docs/en/Community-Articles/2024-05-28-AKS-Helm-deployment-ABP-Angular/helm-chart.png differ diff --git a/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/How to use Aspire with ABP framework.md b/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/How to use Aspire with ABP framework.md new file mode 100644 index 0000000000..7d78d476c5 --- /dev/null +++ b/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/How to use Aspire with ABP framework.md @@ -0,0 +1,302 @@ +# How to use .NET Aspire with ABP framework + +[.NET Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview) is an opinionated, cloud-ready stack designed for building observable, production-ready, and distributed applications. On the other hand, the [ABP framework](https://docs.abp.io/en/abp/latest) offers a complete, modular and layered software architecture based on Domain Driven Design principles and patterns. This guide explores how to combine .NET Aspire with ABP, enabling developers to create observable, and feature-rich applications. + +## When to Use .NET Aspire? + +Using .NET Aspire with the ABP framework can be beneficial in various scenarios where you need to combine the strengths of both technologies. Here are some situations when using .NET Aspire with ABP can be advantageous: + +- **Enterprise Web Applications:** ABP is well-suited for building enterprise web applications with its opinionated architecture and best practices. When combined with .NET Aspire, you can leverage ABP's features for rapid development of user interfaces, backend services, and business logic while benefiting from .NET Aspire's cloud-native capabilities and observability features. +- **Observability and Monitoring:** .NET Aspire's emphasis on observability, including logging, monitoring, and tracing, can enhance ABP applications by providing deeper insights into system behavior, performance metrics, and diagnostics, which is key for maintaining and optimizing enterprise-grade applications. + +## Creating a new ABP Solution + +To demonstrate the usage of .NET Aspire with the ABP framework, I've created an ABP solution. If you want to create the same solution from scratch, follow the steps below: + +Install the ABP CLI if you haven't installed it before: + +```bash +dotnet tool install -g Volo.Abp.Cli +``` + +Create a new solution with the ABP framework's Application Startup Template with Tiered MVC UI and EF Core database: + +```bash +abp new AspirationalAbp -u mvc --database-provider ef -dbms PostgreSQL --csf --tiered +``` + +> The startup template selection matters for this article. I chose these options so that the demo solution can cover complex scenarios. + +**Disclaimer-I:** This article is based on version `8.0.1` of .NET Aspire and version `8.2.0` of ABP Framework. + +**Disclaimer-II:** ABP and .NET Aspire may not be fully compatible in some respects. This article aims to explain how these two technologies can be used together in the simplest way possible, even if they are not fully compatible. +## Add .NET Aspire + +After creating the solution, run the following commands in the `src` folder of your solution to add .NET Aspire: + +```bash +// Adding AppHost +dotnet new aspire-apphost -n AspirationalAbp.AppHost +dotnet sln ../AspirationalAbp.sln add ./AspirationalAbp.AppHost/AspirationalAbp.AppHost.csproj + +// Adding ServiceDefaults +dotnet new aspire-servicedefaults -n AspirationalAbp.ServiceDefaults +dotnet sln ../AspirationalAbp.sln add ./AspirationalAbp.ServiceDefaults/AspirationalAbp.ServiceDefaults.csproj +``` + +These commands add two new projects to the solution: +- **AspirationalAbp.AppHost**: An orchestrator project designed to connect and configure the different projects and services of your app. +- **AspirationalAbp.ServiceDefaults**: A .NET Aspire shared project to manage configurations that are reused across the projects in your solution related to [resilience](https://learn.microsoft.com/en-us/dotnet/core/resilience/http-resilience), [service discovery](https://learn.microsoft.com/en-us/dotnet/aspire/service-discovery/overview), and [telemetry](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/telemetry). + +We have added .NET Aspire to our ABP based solution, but we have not registered our projects in the .NET Aspire orchestration. Now, let's enroll our projects, which implement the db migrator, web user interface, API, and auth, in .NET Aspire orchestration. + +## Registering projects to .NET Aspire orchestration + +First of all, we need to add the reference of related projects to the `AspirationalAbp.AppHost` project. For this, add the following `ItemGroups` to the `AspirationalAbp.AppHost/AspirationalAbp.AppHost.csproj` file: + +```csharp + + + + + + + + + + + +``` + +With the first `ItemGroup`, we added the references of `AuthServer`, `HttpApi.Host`, `Web`, and `DbMigrator` projects to the app host project. So, we can orchestrate them within the app model. + +With the second `ItemGroup`, to model the **PostgreSQL** server resource and **Redis** resource in the app host, installed the `Aspire.Hosting.PostgreSQL` and `Aspire.Hosting.Redis` + +Now let's update the `Program` class of the `AspirationalAbp.AppHost` project as follows: + +```csharp +using Microsoft.Extensions.Hosting; + +var builder = DistributedApplication.CreateBuilder(args); + +var postgres = builder + .AddPostgres("postgres") + .AddDatabase("AspirationalAbp"); + +var redis = builder.AddRedis("redis"); + +// DbMigrator +if (builder.Environment.IsDevelopment()) +{ + builder + .AddProject("dbMigrator") + .WithReference(postgres, "Default") + .WithReference(redis, "Redis") + .WithReplicas(1); +} + +// AuthServer +var authServerLaunchProfile = "AspirationalAbp.AuthServer"; +builder + .AddProject("authserver", launchProfileName: authServerLaunchProfile) + .WithExternalHttpEndpoints() + .WithReference(postgres, "Default") + .WithReference(redis); + +// HttpApi.Host +var httpApiHostLaunchProfile = "AspirationalAbp.HttpApi.Host"; +builder + .AddProject("httpapihost", launchProfileName: httpApiHostLaunchProfile) + .WithExternalHttpEndpoints() + .WithReference(postgres, "Default") + .WithReference(redis); + +// Web +builder + .AddProject("web", "AspirationalAbp.Web") + .WithReference(redis); + +builder.Build().Run(); +``` + +With the code above, the following operations were performed below: + +1. Creates an `IDistributedApplicationBuilder` instance by calling `DistributedApplication.CreateBuilder(args)`. +2. Adds PostgreSQL and the `AspirationalAbp` database. +3. Adds Redis. +4. Adds the `DbMigrator` project with references to PostgreSQL and Redis, ensuring one replica in development. +5. Adds the `AuthServer` project with external HTTP endpoints, referencing PostgreSQL and Redis. +6. Adds the `HttpApi.Host` project with external HTTP endpoints, referencing PostgreSQL and Redis. +7. Adds the `Web` project, referencing Redis. +8. Builds and runs the application. + +Now let's make the projects we added to the app host compatible with .NET Aspire. + +## Configuring Projects for Aspire + +To make the `AspirationalAbp.DbMigrator`, `AspirationalAbp.AuthServer`, `AspirationalAbp.HttpApi.Host`, and `AspirationalAbp.Web` projects compatible with .NET Aspire, we need to add and configure several packages. For that, we need to add the `Aspire.StackExchange.Redis` package to all these projects and the `Aspire.Npgsql.EntityFrameworkCore.PostgreSQL` package to the `AspirationalAbp.EntityFrameworkCore` project. Additionally, we will add the `AspirationalAbp.ServiceDefaults` reference to host projects except `AspirationalAbp.DbMigrator`. Also, we need to convert [Serilog](https://serilog.net/) events into [OpenTelemetry](https://opentelemetry.io/) `LogRecord`s, for that we will add a `Serilog.Sinks.OpenTelemetry` reference to host projects. Let's begin with configuring `AspirationalAbp.DbMigrator`. + +### AspirationalAbp.DbMigrator + +First, let's add the `Aspire.StackExchange.Redis`, and `Serilog.Sinks.OpenTelemetry` packages to the `AspirationalAbp.DbMigrator` project. For this, let's run the following .NET CLI command inside the `AspirationalAbp.DbMigrator` project: + +```bash +dotnet add package Aspire.StackExchange.Redis --version 8.0.1 +dotnet add package Serilog.Sinks.OpenTelemetry --version 4.0.0-dev-00313 +``` + +Then let's override the `PreConfigureServices` method in `AspirationalAbpDbMigratorModule` as below: + +```csharp +public override void PreConfigureServices(ServiceConfigurationContext context) +{ + var configuration = context.Services.GetConfiguration(); + configuration["Redis:Configuration"] = configuration["ConnectionStrings:Redis"]; +} +``` + +To use the **OpenTelemetry** sink we have installed the `Serilog.Sinks.OpenTelemetry` package and now let's enable the sink. For this, let's write the following code block just before calling the `CreateLogger` method in the logger configuration in `Program.cs`: + +```csharp +/// .WriteTo.Async(c => c.Console()) +.WriteTo.Async(c => c.OpenTelemetry()) +/// .CreateLogger(); +``` + +Now let's continue with `AspirationalAbp.EntityFrameworkCore`. + +### AspirationalAbp.EntityFrameworkCore + +Now let's add the `Aspire.Npgsql.EntityFrameworkCore.PostgreSQL` package to the `AspirationalAbp.EntityFrameworkCore` project. For this, you can run the following command in the `AspirationalAbp.EntityFrameworkCore` project: + +```bash +dotnet add package Aspire.Npgsql.EntityFrameworkCore.PostgreSQL --version 8.0.1 +``` + +Now let's continue with `AspirationalAbp.AuthServer`. + +### AspirationalAbp.AuthServer + +First, let's add the `Serilog.Sinks.OpenTelemetry`, `Aspire.StackExchange.Redis` and `AspirationalAbp.ServiceDefaults` packages to the `AspirationalAbp.AuthServer` project. For this, let's run the following .NET CLI command inside the `AspirationalAbp.AuthServer` project: + +```bash +dotnet add package Aspire.StackExchange.Redis --version 8.0.1 +dotnet add reference ../AspirationalAbp.ServiceDefaults/AspirationalAbp.ServiceDefaults.csproj +dotnet add package Serilog.Sinks.OpenTelemetry --version 4.0.0-dev-00313 +``` + +Then add the following code block after defining the builder variable in `Program.cs`: + +```csharp +builder.AddServiceDefaults(); +builder.AddRedisClient("redis"); +builder.AddNpgsqlDbContext("Default", + options => + { + options.DisableRetry = true; + }); +``` + +Then add the following code to the `PreConfigureServices` method in the `AspirationalAbpAuthServerModule` class: + +```csharp +configuration["Redis:Configuration"] = configuration["ConnectionStrings:Redis"]; +``` + +To use the **OpenTelemetry** sink we have installed the `Serilog.Sinks.OpenTelemetry` package and now let's enable the sink. For this, let's write the following code block just before calling the `CreateLogger` method in logger configuration in `Program.cs`: + +```csharp +/// .WriteTo.Async(c => c.Console()) +.WriteTo.Async(c => c.OpenTelemetry()) +/// .CreateLogger(); +``` + +So far we have made `AspirationalAbp.DbMigrator`, `AspirationalAbp.EntityFrameworkCore`, and `AspirationalAbp.AuthServer` compatible with .NET Aspire. Now let's continue with `AspirationalAbp.HttpApi.Host`. + +### AspirationalAbp.HttpApi.Host + +First, let's add the `Serilog.Sinks.OpenTelemetry`, `Aspire.StackExchange.Redis` and `AspirationalAbp.ServiceDefaults` packages to the `AspirationalAbp.HttpApi.Host` project. For this, let's run the following .NET CLI command inside the `AspirationalAbp.HttpApi.Host` project: + +```bash +dotnet add package Aspire.StackExchange.Redis --version 8.0.1 +dotnet add reference ../AspirationalAbp.ServiceDefaults/AspirationalAbp.ServiceDefaults.csproj +dotnet add package Serilog.Sinks.OpenTelemetry --version 4.0.0-dev-00313 +``` + +Then add the following code block after defining the builder variable in `Program.cs`: + +```csharp +builder.AddServiceDefaults(); +builder.AddRedisClient("redis"); +builder.AddNpgsqlDbContext("Default", + options => + { + options.DisableRetry = true; + }); +``` + +Then let's override the `PreConfigureServices` method in `AspirationalAbpHttpApiHostModule` as below: + +```csharp +public override void PreConfigureServices(ServiceConfigurationContext context) +{ + var configuration = context.Services.GetConfiguration(); + configuration["Redis:Configuration"] = configuration["ConnectionStrings:Redis"]; +} +``` + +To use the **OpenTelemetry** sink we have installed the `Serilog.Sinks.OpenTelemetry` package and now let's enable the sink. For this, let's write the following code block just before calling the `CreateLogger` method in the logger configuration in `Program.cs`: + +```csharp +/// .WriteTo.Async(c => c.Console()) +.WriteTo.Async(c => c.OpenTelemetry()) +/// .CreateLogger(); +``` + +Finally, let's make `AspirationalAbp.Web` compatible with .NET Aspire. + +### AspirationalAbp.Web + +First, let's add the `Serilog.Sinks.OpenTelemetry`, `Aspire.StackExchange.Redis` and `AspirationalAbp.ServiceDefaults` packages to the `AspirationalAbp.Web` project. For this, let's run the following .NET CLI command inside the `AspirationalAbp.Web` project: + +```bash +dotnet add package Aspire.StackExchange.Redis --version 8.0.1 +dotnet add reference ../AspirationalAbp.ServiceDefaults/AspirationalAbp.ServiceDefaults.csproj +dotnet add package Serilog.Sinks.OpenTelemetry --version 4.0.0-dev-00313 +``` + +Then add the following code block after defining the builder variable in `Program.cs`: + +```csharp +builder.AddServiceDefaults(); +builder.AddRedisClient("redis"); +``` + +Then add the following code to the `PreConfigureServices` method in the `AspirationalAbpWebModule` class: + +```bash +var configuration = context.Services.GetConfiguration(); +configuration["Redis:Configuration"] = configuration["ConnectionStrings:Redis"]; +``` + +To use the **OpenTelemetry** sink we have installed the `Serilog.Sinks.OpenTelemetry` package and now let's enable the sink. For this, let's write the following code block just before calling the `CreateLogger` method in logger configuration in `Program.cs`: + +```csharp +/// .WriteTo.Async(c => c.Console()) +.WriteTo.Async(c => c.OpenTelemetry()) +/// .CreateLogger(); +``` + +After making all our changes, we can run the `AspirationalAbp.AppHost` project. + +![aspire-dashboard](aspire-dashboard.png) + +![aspire-structured-logs](aspire-structured-logs.png) + +![aspire-traces](aspire-traces.png) + +![aspire-metrics](aspire-metrics.png) + +## Conclusion + +Combining .NET Aspire with the ABP framework creates a powerful setup for building robust, observable, and feature-rich applications. By integrating Aspire's observability and cloud capabilities with ABP's approach of focusing on your business without repeating yourself, you can develop feature-rich, scalable applications with enhanced monitoring and seamless cloud integration. This guide provides a clear path to set up and configure these technologies, ensuring your applications are well-structured, maintainable, and ready for modern cloud environments. diff --git a/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/aspire-dashboard.png b/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/aspire-dashboard.png new file mode 100644 index 0000000000..b1141c4644 Binary files /dev/null and b/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/aspire-dashboard.png differ diff --git a/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/aspire-metrics.png b/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/aspire-metrics.png new file mode 100644 index 0000000000..ec2c9abda7 Binary files /dev/null and b/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/aspire-metrics.png differ diff --git a/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/aspire-structured-logs.png b/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/aspire-structured-logs.png new file mode 100644 index 0000000000..af0b685000 Binary files /dev/null and b/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/aspire-structured-logs.png differ diff --git a/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/aspire-traces.png b/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/aspire-traces.png new file mode 100644 index 0000000000..20a5d65d3c Binary files /dev/null and b/docs/en/Community-Articles/2024-06-27-how-to-use-Aspire-with-ABP-framework/aspire-traces.png differ diff --git a/docs/en/Community-Articles/2024-07-01-Use_User-Defined_Function_Mapping_For_Global_Filter/POST.md b/docs/en/Community-Articles/2024-07-01-Use_User-Defined_Function_Mapping_For_Global_Filter/POST.md new file mode 100644 index 0000000000..37171d1219 --- /dev/null +++ b/docs/en/Community-Articles/2024-07-01-Use_User-Defined_Function_Mapping_For_Global_Filter/POST.md @@ -0,0 +1,130 @@ +# Use User-Defined Function Mapping for Global Filter + +## Introduction + +ABP provides data filters that can filter queries automatically based on some rules. This feature is useful for implementing multi-tenancy, soft delete, and other global filters. It uses [EF Core's Global Query Filters system](https://learn.microsoft.com/en-us/ef/core/querying/filters) for the EF Core Integration. + +EF Core Global Query Filters generate filter conditions and apply them to SQL queries. ABP controls whether this filter condition takes effect through a variable. However, this variable may cause performance losses in some scenarios. + +## The Filter Condition Variable + +Think of a scenario with a global filter `IIsActive`, which filters out inactive entities: + +```csharp +public class Book : IIsActive +{ + public string Name { get; set; } + + public bool IsActive { get; set; } +} +``` + +The SQL generated by the [EF Core Global Query Filters](https://learn.microsoft.com/en-us/ef/core/querying/filters) is as follows: + +```SQL +SELECT * FROM [AppBooks] AS [a] +WHERE (@__ef_filter__p_0 = CAST(1 AS bit) OR [a].[IsActive] = CAST(1 AS bit)) +``` + +> The `__ef_filter__p_0` variable controls whether the filter condition takes effect. + +The generated SQL is not optimal, and some databases do not optimize it well. + +## Using User-defined function mapping for global filters + +In the [upcoming preview version of ABP, v8.3.0-rc.1](https://github.com/abpframework/abp/pull/20065), we start the [User-defined function mapping](https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping) to implement global filters more efficiently. This feature is enabled by default, so you don't need to make any changes if you create a new solution and start from scratch. Otherwise, you can enable it easily by following the instructions below. + +To use this new feature for your custom global filters, you need to change your `DbContext` as follows: + +````csharp +protected bool IsActiveFilterEnabled => DataFilter?.IsEnabled() ?? false; + +protected override bool ShouldFilterEntity(IMutableEntityType entityType) +{ + if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))) + { + return true; + } + + return base.ShouldFilterEntity(entityType); +} + +protected override Expression> CreateFilterExpression(ModelBuilder modelBuilder) +{ + var expression = base.CreateFilterExpression(modelBuilder); + + if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))) + { + Expression> isActiveFilter = e => !IsActiveFilterEnabled || EF.Property(e, "IsActive"); + + if (UseDbFunction()) + { + isActiveFilter = e => IsActiveFilter(((IIsActive)e).IsActive, true); + + var abpEfCoreCurrentDbContext = this.GetService(); + modelBuilder.HasDbFunction(typeof(MyProjectNameDbContext).GetMethod(nameof(IsActiveFilter))!) + .HasTranslation(args => + { + // (bool isActive, bool boolParam) + var isActive = args[0]; + var boolParam = args[1]; + + if (abpEfCoreCurrentDbContext.Context?.DataFilter.IsEnabled() == true) + { + // isActive == true + return new SqlBinaryExpression( + ExpressionType.Equal, + isActive, + new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping), + boolParam.Type, + boolParam.TypeMapping); + } + + // empty where sql + return new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping); + }); + } + + expression = expression == null ? isActiveFilter : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter); + } + + return expression; +} + +public static bool IsActiveFilter(bool isActive, bool boolParam) +{ + throw new NotSupportedException(AbpEfCoreDataFilterDbFunctionMethods.NotSupportedExceptionMessage); +} + +public override string GetCompiledQueryCacheKey() +{ + return $"{base.GetCompiledQueryCacheKey()}:{IsActiveFilterEnabled}"; +} +```` + +After these changes, the SQL generated by the EF Core Global Query Filters will be as follows: + +Enabling the `IIsActive` filter: + +```SQL +SELECT * FROM [AppBooks] AS [a] WHERE +[a].[IsActive] = CAST(1 AS bit) +``` + +Disabling the `IIsActive` filter: + +```SQL +SELECT * FROM [AppBooks] AS [a] +``` + +## Conclusion + +We have implemented global filters using [User-defined function mapping](https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping), which can generate more efficient SQL and thus improve performance. + +Upgrade to the latest ABP version and enjoy the performance improvement! + +## References + +- [ABP Framework Data Filtering](https://docs.abp.io/en/abp/latest/Data-Filtering) +- [EF Core's Global Query Filters system](https://learn.microsoft.com/en-us/ef/core/querying/filters) +- [User-defined function mapping](https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping) diff --git a/docs/en/Contribution/Index.md b/docs/en/Contribution/Index.md index 8ebac70c20..77dd3cdb8b 100644 --- a/docs/en/Contribution/Index.md +++ b/docs/en/Contribution/Index.md @@ -29,23 +29,6 @@ You may want to fix a known bug or work on a planned enhancement. See [the issue If you have a feature idea for the framework or modules, [create an issue](https://github.com/abpframework/abp/issues/new) on Github or attend to an existing discussion. Then you can implement it if it's embraced by the community. -## Document Translation - -You may want to translate the complete [documentation](https://docs.abp.io) (including this one) to your mother language. If so, follow these steps: - -* Clone the [ABP repository](https://github.com/abpframework/abp/) from Github. -* To add a new language, create a new folder inside the [docs](https://github.com/abpframework/abp/tree/master/docs) folder. Folder names can be "en", "es", "fr", "tr" and so on based on the language (see [all culture codes](https://msdn.microsoft.com/en-us/library/hh441729.aspx)). -* Get the ["en" folder](https://github.com/abpframework/abp/tree/master/docs/en) as a reference for the file names and folder structure. Keep the same naming if you are translating the same documentation. -* Send a pull request (PR) once you translate any document. Please translate documents & send PRs one by one. Don't wait to finish translations for all documents. - -There are some fundamental documents need to be translated before publishing a language on the [ABP documentation web site](https://docs.abp.io): - -* Index (Home) -* Getting Started -* Web Application Development Tutorial - -A new language is published after these minimum translations have been completed. - ## Resource Localization ABP framework has a flexible [localization system](../Localization.md). You can create localized user interfaces for your own application. diff --git a/docs/en/Data-Filtering.md b/docs/en/Data-Filtering.md index 830979e710..4706912fe7 100644 --- a/docs/en/Data-Filtering.md +++ b/docs/en/Data-Filtering.md @@ -217,17 +217,14 @@ protected override bool ShouldFilterEntity(IMutableEntityType entityTyp return base.ShouldFilterEntity(entityType); } -protected override Expression> CreateFilterExpression() +protected override Expression> CreateFilterExpression(ModelBuilder modelBuilder) { - var expression = base.CreateFilterExpression(); + var expression = base.CreateFilterExpression(modelBuilder); if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))) { - Expression> isActiveFilter = - e => !IsActiveFilterEnabled || EF.Property(e, "IsActive"); - expression = expression == null - ? isActiveFilter - : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter); + Expression> isActiveFilter = e => !IsActiveFilterEnabled || EF.Property(e, "IsActive"); + expression = expression == null ? isActiveFilter : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter); } return expression; @@ -251,6 +248,78 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) } ```` +#### Using User-defined function mapping for global filters + +Using [User-defined function mapping](https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping) for global filters will gain performance improvements. + +To use this feature, you need to change your DbContext like below: + +````csharp +protected bool IsActiveFilterEnabled => DataFilter?.IsEnabled() ?? false; + +protected override bool ShouldFilterEntity(IMutableEntityType entityType) +{ + if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))) + { + return true; + } + + return base.ShouldFilterEntity(entityType); +} + +protected override Expression> CreateFilterExpression(ModelBuilder modelBuilder) +{ + var expression = base.CreateFilterExpression(modelBuilder); + + if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))) + { + Expression> isActiveFilter = e => !IsActiveFilterEnabled || EF.Property(e, "IsActive"); + + if (UseDbFunction()) + { + isActiveFilter = e => IsActiveFilter(((IIsActive)e).IsActive, true); + + var abpEfCoreCurrentDbContext = this.GetService(); + modelBuilder.HasDbFunction(typeof(MyProjectNameDbContext).GetMethod(nameof(IsActiveFilter))!) + .HasTranslation(args => + { + // (bool isActive, bool boolParam) + var isActive = args[0]; + var boolParam = args[1]; + + if (abpEfCoreCurrentDbContext.Context?.DataFilter.IsEnabled() == true) + { + // isActive == true + return new SqlBinaryExpression( + ExpressionType.Equal, + isActive, + new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping), + boolParam.Type, + boolParam.TypeMapping); + } + + // empty where sql + return new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping); + }); + } + + expression = expression == null ? isActiveFilter : QueryFilterExpressionHelper.CombineExpressions(expression, isActiveFilter); + } + + return expression; +} + +public static bool IsActiveFilter(bool isActive, bool boolParam) +{ + throw new NotSupportedException(AbpEfCoreDataFilterDbFunctionMethods.NotSupportedExceptionMessage); +} + +public override string GetCompiledQueryCacheKey() +{ + return $"{base.GetCompiledQueryCacheKey()}:{IsActiveFilterEnabled}"; +} +```` + ### MongoDB ABP abstracts the `IMongoDbRepositoryFilterer` interface to implement data filtering for the [MongoDB Integration](MongoDB.md), it works only if you use the repositories properly. Otherwise, you should manually filter the data. diff --git a/docs/en/Modules/Cms-Kit/Comments.md b/docs/en/Modules/Cms-Kit/Comments.md index ddd39fc675..4eca4cb93d 100644 --- a/docs/en/Modules/Cms-Kit/Comments.md +++ b/docs/en/Modules/Cms-Kit/Comments.md @@ -80,6 +80,12 @@ You can also view and manage replies on this page. ![comments-detail](../../images/cmskit-module-comments-detail.png) +## Settings + +You can configure the approval status of comments using the "Comment" tab under the "Cms" section on the Settings page. When this feature is enabled, you can approve and reject comments. In this way, users can only see the comments that you approve. By default, this feature is set to "false." + +![comments-settings](../../images/cmskit-module-comments-settings.png) + ## Internals ### Domain Layer diff --git a/docs/en/Modules/Cms-Kit/Index.md b/docs/en/Modules/Cms-Kit/Index.md index 6c3201d0f9..f546552f16 100644 --- a/docs/en/Modules/Cms-Kit/Index.md +++ b/docs/en/Modules/Cms-Kit/Index.md @@ -17,6 +17,7 @@ The following features are currently available: * Provides a [**menu**](Menus.md) system to manage public menus dynamically. * Provides a [**global resources**](Global-Resources.md) system to add global styles and scripts dynamically. * Provides a [**Dynamic Widget**](Dynamic-Widget.md) system to create dynamic widgets for page and blog posts. +* Provides a [**Marked Item**](MarkedItems.md) system to mark any kind of resource, like a blog post or a product, as a favorite, starred, flagged, or bookmarked. > You can click on the any feature links above to understand and learn how to use it. diff --git a/docs/en/Modules/Cms-Kit/MarkedItems.md b/docs/en/Modules/Cms-Kit/MarkedItems.md new file mode 100644 index 0000000000..b7bbb77519 --- /dev/null +++ b/docs/en/Modules/Cms-Kit/MarkedItems.md @@ -0,0 +1,123 @@ +# Marked Item System + +CMS kit provides a marking system to mark any kind of resource, like a blog post or a product, as a favorite, starred, flagged, or bookmarked. + +Marked toggling component allows users to mark your items via pre-defined icons/emojis. Here how the marked toggling components may look like: + +![markedItems](../../images/cmskit-module-markedItems.png) + + +you can also customize the marking icons shown in the toggling components. + +## Enabling the Marked Item Feature + +By default, CMS Kit features are disabled. Therefore, you need to enable the features you want, before starting to use it. You can use the [Global Feature](../../Global-Features.md) system to enable/disable CMS Kit features on development time. Alternatively, you can use the ABP Framework's [Feature System](https://docs.abp.io/en/abp/latest/Features) to disable a CMS Kit feature on runtime. + +> Check the ["How to Install" section of the CMS Kit Module documentation](Index.md#how-to-install) to see how to enable/disable CMS Kit features on development time. + +## Options + +Marking system provides a simple approach to define your entity type with mark types like favorite or starred. For example, if you want to use the marking system for products, you need to define an entity type named `product` with the icon name. + +`CmsKitMarkedItemOptions` can be configured in YourModule.cs, in the `ConfigureServices` method of your [module](https://docs.abp.io/en/abp/latest/Module-Development-Basics). Example: + +```csharp +Configure(options => +{ + options.EntityTypes.Add( + new MarkedItemEntityTypeDefinition( + "product", + StandardMarkedItems.Favorite + ) + ); +}); +``` + +`CmsKitMarkedItemOptions` properties: + +- `EntityTypes`: List of defined entity types (`CmsKitMarkedItemOptions`) in the marking system. + +`MarkedItemEntityTypeDefinition` properties: + +- `EntityType`: Name of the entity type. +- `IconName`: The name of the icon. + +## The Marked Item widget + +The marking system provides a toggle widget to allow users to add/remove the marks from an item. You can place the widget with the item as shown below: + +``` csharp +@await Component.InvokeAsync(typeof (MarkedItemToggleViewComponent), new +{ + entityId = "...", + entityType = "product", + needsConfirmation = true // (optional) +}) +``` +* `entityType` was explained in the previous section. +* `entityId` should be the unique id of the product, in this example. If you have a Product entity, you can use its Id here. +* `needsConfirmation` An optional parameter to let the user confirm when removing the mark. + +# Internals + +## Domain Layer + +#### Aggregates + +This module follows the [Entity Best Practices & Conventions](https://docs.abp.io/en/abp/latest/Best-Practices/Entities) guide. + +##### UserMarkedItem + +A user markedItem represents a user has marking on the item. + +- `UserMarkedItem` (aggregate root): Represents a marked item in the system. + +#### Repositories + +This module follows the [Repository Best Practices & Conventions](https://docs.abp.io/en/abp/latest/Best-Practices/Repositories) guide. + +Following custom repositories are defined for this feature: + +- `IUserMarkedItemRepository` + + +#### Domain services + +This module follows the [Domain Services Best Practices & Conventions](https://docs.abp.io/en/abp/latest/Best-Practices/Domain-Services) guide. + +##### Marked Item Manager + +`MarkedItemManager` is used to perform some operations for the `UserMarkedItem` aggregate root. + +### Application layer + +#### Application services + +- `MarkedItemPublicAppService` (implements `IMarkedItemPublicAppService`): Implements the use cases of marking system. + +### Database providers + +#### Common + +##### Table / collection prefix & schema + +All tables/collections use the `Cms` prefix by default. Set static properties on the `CmsKitDbProperties` class if you need to change the table prefix or set a schema name (if supported by your database provider). + +##### Connection string + +This module uses `CmsKit` for the connection string name. If you don't define a connection string with this name, it fallbacks to the `Default` connection string. + +See the [connection strings](https://docs.abp.io/en/abp/latest/Connection-Strings) documentation for details. + +#### Entity Framework Core + +##### Tables + +- CmsUserMarkedItems + +#### MongoDB + +##### Collections + +- **CmsUserMarkedItems** + diff --git a/docs/en/Multi-Tenancy.md b/docs/en/Multi-Tenancy.md index 922976767d..123eb45165 100644 --- a/docs/en/Multi-Tenancy.md +++ b/docs/en/Multi-Tenancy.md @@ -1,6 +1,6 @@ # Multi-Tenancy -Multi-Tenancy is a widely used architecture to create **SaaS applications** where the hardware and software **resources are shared by the customers** (tenants). ABP Framework provides all the base functionalities to create **multi tenant applications**. +Multi-Tenancy is a widely used architecture to create **SaaS applications** where the hardware and software **resources are shared by the customers** (tenants). ABP Framework provides all the base functionalities to create **multi tenant applications**. Wikipedia [defines](https://en.wikipedia.org/wiki/Multitenancy) the multi-tenancy as like that: @@ -10,8 +10,8 @@ Wikipedia [defines](https://en.wikipedia.org/wiki/Multitenancy) the multi-tenanc There are two main side of a typical SaaS / Multi-tenant application: -* A **Tenant** is a customer of the SaaS application that pays money to use the service. -* **Host** is the company that owns the SaaS application and manages the system. +- A **Tenant** is a customer of the SaaS application that pays money to use the service. +- **Host** is the company that owns the SaaS application and manages the system. The Host and the Tenant terms will be used for that purpose in the rest of the document. @@ -36,9 +36,9 @@ Configure(options => ABP Framework supports all the following approaches to store the tenant data in the database; -* **Single Database**: All tenants are stored in a single database. -* **Database per Tenant**: Every tenant has a separate, dedicated database to store the data related to that tenant. -* **Hybrid**: Some tenants share a single databases while some tenants may have their own databases. +- **Single Database**: All tenants are stored in a single database. +- **Database per Tenant**: Every tenant has a separate, dedicated database to store the data related to that tenant. +- **Hybrid**: Some tenants share a single database while some tenants may have their own databases. [Tenant management module](Modules/Tenant-Management.md) (which comes pre-installed with the startup projects) allows you to set a connection string for any tenant (as optional), so you can achieve any of the approaches. @@ -48,11 +48,11 @@ Multi-tenancy system is designed to **work seamlessly** and make your applicatio ### IMultiTenant -You should implement the `IMultiTenant` interface for your [entities](Entities.md) to make them **multi-tenancy ready**. +You should implement the `IMultiTenant` interface for your [entities](Entities.md) to make them **multi-tenancy ready**. -**Example: A multi-tenant *Product* entity** +**Example: A multi-tenant _Product_ entity** -````csharp +```csharp using System; using Volo.Abp.Domain.Entities; using Volo.Abp.MultiTenancy; @@ -68,7 +68,7 @@ namespace MultiTenancyDemo.Products public float Price { get; set; } } } -```` +``` `IMultiTenant` interface just defines a `TenantId` property. When you implement this interface, ABP Framework **automatically** [filters](Data-Filtering.md) entities for the current tenant when you query from database. So, you don't need to manually add `TenantId` condition while performing queries. A tenant can not access to data of another tenant by default. @@ -96,9 +96,9 @@ If you set the `TenantId` value for a specific entity object, it will override t `ICurrentTenant` defines the following properties; -* `Id` (`Guid`): Id of the current tenant. Can be `null` if the current user is a host user or the tenant could not be determined from the request. -* `Name` (`string`): Name of the current tenant. Can be `null` if the current user is a host user or the tenant could not be determined from the request. -* `IsAvailable` (`bool`): Returns `true` if the `Id` is not `null`. +- `Id` (`Guid`): Id of the current tenant. Can be `null` if the current user is a host user or the tenant could not be determined from the request. +- `Name` (`string`): Name of the current tenant. Can be `null` if the current user is a host user or the tenant could not be determined from the request. +- `IsAvailable` (`bool`): Returns `true` if the `Id` is not `null`. #### Change the Current Tenant @@ -108,7 +108,7 @@ ABP Framework automatically filters the resources (database, cache...) based on **Example: Get product count of a specific tenant** -````csharp +```csharp using System; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; @@ -134,11 +134,11 @@ namespace MultiTenancyDemo.Products } } } -```` +``` -* `Change` method can be used in a **nested way**. It restores the `CurrentTenant.Id` to the previous value after the `using` statement. -* When you use `CurrentTenant.Id` inside the `Change` scope, you get the `tenantId` provided to the `Change` method. So, the repository also get this `tenantId` and can filter the database query accordingly. -* Use `CurrentTenant.Change(null)` to change scope to the host context. +- `Change` method can be used in a **nested way**. It restores the `CurrentTenant.Id` to the previous value after the `using` statement. +- When you use `CurrentTenant.Id` inside the `Change` scope, you get the `tenantId` provided to the `Change` method. So, the repository also get this `tenantId` and can filter the database query accordingly. +- Use `CurrentTenant.Change(null)` to change scope to the host context. > Always use the `Change` method with a `using` statement like done in this example. @@ -148,7 +148,7 @@ As mentioned before, ABP Framework handles data isolation between tenants using **Example: Get count of products in the database, including all the products of all the tenants.** -````csharp +```csharp using System; using System.Threading.Tasks; using Volo.Abp.Data; @@ -181,7 +181,7 @@ namespace MultiTenancyDemo.Products } } -```` +``` See the [Data Filtering document](Data-Filtering.md) for more. @@ -201,15 +201,15 @@ ABP Framework provides an extensible **Tenant Resolving** system for that purpos The following resolvers are provided and configured by default; -* `CurrentUserTenantResolveContributor`: Gets the tenant id from claims of the current user, if the current user has logged in. **This should always be the first contributor for the security**. -* `QueryStringTenantResolveContributor`: Tries to find current tenant id from query string parameters. The parameter name is `__tenant` by default. -* `RouteTenantResolveContributor`: Tries to find current tenant id from route (URL path). The variable name is `__tenant` by default. If you defined a route with this variable, then it can determine the current tenant from the route. -* `HeaderTenantResolveContributor`: Tries to find current tenant id from HTTP headers. The header name is `__tenant` by default. -* `CookieTenantResolveContributor`: Tries to find current tenant id from cookie values. The cookie name is `__tenant` by default. +- `CurrentUserTenantResolveContributor`: Gets the tenant id from claims of the current user, if the current user has logged in. **This should always be the first contributor for the security**. +- `QueryStringTenantResolveContributor`: Tries to find current tenant id from query string parameters. The parameter name is `__tenant` by default. +- `RouteTenantResolveContributor`: Tries to find current tenant id from route (URL path). The variable name is `__tenant` by default. If you defined a route with this variable, then it can determine the current tenant from the route. +- `HeaderTenantResolveContributor`: Tries to find current tenant id from HTTP headers. The header name is `__tenant` by default. +- `CookieTenantResolveContributor`: Tries to find current tenant id from cookie values. The cookie name is `__tenant` by default. ###### Problems with the NGINX -You may have problems with the `__tenant` in the HTTP Headers if you're using the [nginx](https://www.nginx.com/) as the reverse proxy server. Because it doesn't allow to use underscore and some other special characters in the HTTP headers and you may need to manually configure it. See the following documents please: +You may have problems with the `__tenant` in the HTTP Headers if you're using the [nginx](https://www.nginx.com/) as the reverse proxy server. Because it doesn't allow to use underscore and some other special characters in the HTTP headers and you may need to manually configure it. See the following documents please: http://nginx.org/en/docs/http/ngx_http_core_module.html#ignore_invalid_headers http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers @@ -219,22 +219,24 @@ http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers **Example:** -````csharp +```csharp services.Configure(options => { options.TenantKey = "MyTenantKey"; }); -```` +``` -If you change the `TenantKey`, make sure to pass it to `CoreModule` in the Angular client as follows: +If you change the `TenantKey`, make sure to pass it to `provideAbpCore` via `withOptions` method in the Angular client as follows: ```js @NgModule({ - imports: [ - CoreModule.forRoot({ - // ... - tenantKey: 'MyTenantKey' - }), + providers: [ + provideAbpCore( + withOptions({ + // ... + tenantKey: "MyTenantKey", + }) + ), ], // ... }) @@ -249,7 +251,7 @@ import { TENANT_KEY } from '@abp/ng.core'; class SomeComponent { constructor(@Inject(TENANT_KEY) private tenantKey: string) {} -} +} ``` > However, we don't suggest to change this value since some clients may assume the the `__tenant` as the parameter name and they might need to manually configure then. @@ -277,30 +279,30 @@ In a real application, most of times you will want to determine the current tena **Example: Add a subdomain resolver** -````csharp +```csharp Configure(options => { options.AddDomainTenantResolver("{0}.mydomain.com"); }); -```` +``` -* `{0}` is the placeholder to determine the current tenant's unique name. -* Add this code to the `ConfigureServices` method of your [module](Module-Development-Basics.md). -* This should be done in the *Web/API Layer* since the URL is a web related stuff. +- `{0}` is the placeholder to determine the current tenant's unique name. +- Add this code to the `ConfigureServices` method of your [module](Module-Development-Basics.md). +- This should be done in the _Web/API Layer_ since the URL is a web related stuff. Openiddict is the default Auth Server in ABP (since v6.0). When you use OpenIddict, you must add this code to the `PreConfigure` method as well. ```csharp // using Volo.Abp.OpenIddict.WildcardDomains -PreConfigure(options => +PreConfigure(options => { options.EnableWildcardDomainSupport = true; options.WildcardDomainsFormat.Add("https://{0}.mydomain.com"); }); ``` -You must add this code to the `Configure` method as well. +You must add this code to the `Configure` method as well. ```csharp // using Volo.Abp.MultiTenancy; @@ -312,7 +314,7 @@ Configure(options => ``` -> There is an [example](https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver) that uses the subdomain to determine the current tenant. +> There is an [example](https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver) that uses the subdomain to determine the current tenant. If you use a sepereted Auth server, you must install `[Owl.TokenWildcardIssuerValidator](https://www.nuget.org/packages/Owl.TokenWildcardIssuerValidator)` on the `HTTPApi.Host` project @@ -332,7 +334,7 @@ context.Services options.Authority = configuration["AuthServer:Authority"]; options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]); options.Audience = "ExampleProjectName"; - + // start of added block options.TokenValidationParameters.IssuerValidator = TokenWildcardIssuerValidator.IssuerValidator; options.TokenValidationParameters.ValidIssuers = new[] @@ -348,16 +350,16 @@ context.Services You can add implement your custom tenant resolver and configure the `AbpTenantResolveOptions` in your module's `ConfigureServices` method as like below: -````csharp +```csharp Configure(options => { options.TenantResolvers.Add(new MyCustomTenantResolveContributor()); }); -```` +``` `MyCustomTenantResolveContributor` must inherit from the `TenantResolveContributorBase` (or implement the `ITenantResolveContributor`) as shown below: -````csharp +```csharp using System.Threading.Tasks; using Volo.Abp.MultiTenancy; @@ -373,10 +375,10 @@ namespace MultiTenancyDemo.Web } } } -```` +``` -* A tenant resolver should set `context.TenantIdOrName` if it can determine it. If not, just leave it as is to allow the next resolver to determine it. -* `context.ServiceProvider` can be used if you need to additional services to resolve from the [dependency injection](Dependency-Injection.md) system. +- A tenant resolver should set `context.TenantIdOrName` if it can determine it. If not, just leave it as is to allow the next resolver to determine it. +- `context.ServiceProvider` can be used if you need to additional services to resolve from the [dependency injection](Dependency-Injection.md) system. #### Multi-Tenancy Middleware @@ -384,9 +386,9 @@ Multi-Tenancy middleware is an ASP.NET Core request pipeline [middleware](https: Multi-Tenancy middleware is typically placed just under the [authentication](https://docs.microsoft.com/en-us/aspnet/core/security/authentication) middleware (`app.UseAuthentication()`): -````csharp +```csharp app.UseMultiTenancy(); -```` +``` > This middleware is already configured in the startup templates, so you normally don't need to manually add it. @@ -406,7 +408,7 @@ The [tenant management module](Modules/Tenant-Management) is **included in the s **Example: Define tenants in appsettings.json** -````json +```json "Tenants": [ { "Id": "446a5211-3d72-4339-9adc-845151f8ada0", @@ -422,7 +424,7 @@ The [tenant management module](Modules/Tenant-Management) is **included in the s } } ] -```` +``` > It is recommended to **use the Tenant Management module**, which is already pre-configured when you create a new application with the ABP startup templates. @@ -440,4 +442,4 @@ The [Tenant Management module](Modules/Tenant-Management.md) provides a basic UI ## See Also -* [Features](Features.md) +- [Features](Features.md) diff --git a/docs/en/Themes/LeptonXLite/Angular.md b/docs/en/Themes/LeptonXLite/Angular.md index e7c8142bda..8e46468bd2 100644 --- a/docs/en/Themes/LeptonXLite/Angular.md +++ b/docs/en/Themes/LeptonXLite/Angular.md @@ -31,20 +31,21 @@ yarn add bootstrap-icons Note: You should remove the old theme styles from "angular.json" if you are switching from "ThemeBasic" or "Lepton." Look at the [Theme Configurations](../../UI/Angular/Theme-Configurations) list of styles. Depending on your theme, you can alter your styles in angular.json. -- Finally, remove `ThemeBasicModule` from `app.module.ts`, and import the related modules in `app.module.ts` +- Finally, remove `ThemeBasicModule`, `provideThemeBasicConfig` from `app.module.ts`, and import the related modules in `app.module.ts` ```js import { ThemeLeptonXModule } from "@abp/ng.theme.lepton-x"; -import { SideMenuLayoutModule } from "@abp/ng.theme.lepton-x/layouts"; @NgModule({ imports: [ // ... - // do not forget to remove ThemeBasicModule or other old theme module - // ThemeBasicModule.forRoot(), - ThemeLeptonXModule.forRoot(), - SideMenuLayoutModule.forRoot(), + // ThemeBasicModule + ThemeLeptonXModule.forRoot() + ], + providers: [ + // do not forget to remove provideThemeBasicConfig or other old theme providers + // provideThemeBasicConfig ], // ... }) diff --git a/docs/en/UI/Angular/Account-Module.md b/docs/en/UI/Angular/Account-Module.md index 28852f6b4d..b5fedb8afe 100644 --- a/docs/en/UI/Angular/Account-Module.md +++ b/docs/en/UI/Angular/Account-Module.md @@ -7,7 +7,6 @@ If you add the account module to your project; - "My account" link in the current user dropdown on the top bar will redirect the user to a page in the account module. - You can switch the authentication flow to the resource owner password flow. - ### Account Module Implementation Install the `@abp/ng.account` NPM package by running the below command: @@ -18,18 +17,18 @@ npm install @abp/ng.account > Make sure v4.3 or higher version is installed. -Open the `app.module.ts` and add `AccountConfigModule.forRoot()` to the imports array as shown below: +Open the `app.module.ts` and add `provideAccountConfig()` to the providers array as shown below: ```js // app.module.ts -import { AccountConfigModule } from '@abp/ng.account/config'; +import { provideAccountConfig } from "@abp/ng.account/config"; //... @NgModule({ - imports: [ + providers: [ //... - AccountConfigModule.forRoot() + provideAccountConfig(), ], //... }) @@ -57,19 +56,19 @@ The pro startup template comes with `@volo/abp.ng.account` package. You should u ```bash npm install @volo/abp.ng.account ``` + > Make sure v4.3 or higher version is installed. Open the `app.module.ts` and add `AccountPublicConfigModule.forRoot()` to the imports array as shown below: > Ensure that the `Account Layout Module` has been added if you are using the Lepton X theme. If you miss the step, you will get an error message that says `Account layout not found. Please check your configuration. If you are using LeptonX, please make sure you have added "AccountLayoutModule.forRoot()" to your app.module configuration.` when you try to access the account pages. Otherwise, you can skip adding the `AccountLayoutModule` step. - ```js // app.module.ts -import { AccountPublicConfigModule } from '@volo/abp.ng.account/public/config'; +import { AccountPublicConfigModule } from "@volo/abp.ng.account/public/config"; // if you are using or want to use Lepton X, you should add AccountLayoutModule -// import { AccountLayoutModule } from '@volosoft/abp.ng.theme.lepton-x/account' +// import { AccountLayoutModule } from '@volosoft/abp.ng.theme.lepton-x/account' //... @@ -104,9 +103,9 @@ Before v4.3, the "My account" link in the current user dropdown on the top bar r ### Personal Info Page Confirm Message -When the user changes their own data on the personal settings tab in My Account, The data can not update the CurrentUser key of Application-Configuration. The information of the user is stored in claims. The only way to apply this information to the CurrentUser of Application-Configuration is user should log out and log in. When the Refresh-Token feature is implemented, it will be fixed. So We've added a confirmation alert. +When the user changes their own data on the personal settings tab in My Account, The data can not update the CurrentUser key of Application-Configuration. The information of the user is stored in claims. The only way to apply this information to the CurrentUser of Application-Configuration is user should log out and log in. When the Refresh-Token feature is implemented, it will be fixed. So We've added a confirmation alert. -If you want to disable these warning, You should set `isPersonalSettingsChangedConfirmationActive` false +If you want to disable these warning, You should set `isPersonalSettingsChangedConfirmationActive` false ```js // app-routing.module.ts diff --git a/docs/en/UI/Angular/Basic-Theme.md b/docs/en/UI/Angular/Basic-Theme.md index 651be9b637..3b11e81f14 100644 --- a/docs/en/UI/Angular/Basic-Theme.md +++ b/docs/en/UI/Angular/Basic-Theme.md @@ -11,7 +11,7 @@ The Basic Theme is a theme implementation for the Angular UI. It is a minimalist If you need to manually this theme, follow the steps below: * Install the [@abp/ng.theme.basic](https://www.npmjs.com/package/@abp/ng.theme.basic) NPM package to your Angular project. -* Open the `src/app/app.module.ts` file, import `ThemeBasicModule` (it can be imported from `@abp/ng.theme.basic` package), and add `ThemeBasicModule.forRoot()` to the `imports` array. +* Open the `src/app/app.module.ts` file, import `ThemeBasicModule`,`provideThemeBasicConfig` (it can be imported from `@abp/ng.theme.basic` package), and add `ThemeBasicModule` to the `imports` array and provide `provideThemeBasicConfig()` to the providers array. * Open the `src/app/shared/shared.module` file, import `ThemeBasicModule` (it can be imported from `@abp/ng.theme.basic` package), and add `ThemeBasicModule` to the `imports` and `exports` array. The `ThemeBasicModule` is registered own layouts (`ApplicationLayoutComponent`, `AccountLayoutComponent`, `EmptyLayoutComponent`) to a service which is exposed by `@abp/ng.core` package on application initialization. diff --git a/docs/en/UI/Angular/Component-Replacement.md b/docs/en/UI/Angular/Component-Replacement.md index d21489d232..73c7a2ed15 100644 --- a/docs/en/UI/Angular/Component-Replacement.md +++ b/docs/en/UI/Angular/Component-Replacement.md @@ -30,7 +30,6 @@ export class AppComponent { ![Example Usage](./images/component-replacement.gif) - ## How to Replace a Layout Each ABP theme module has 3 layouts named `ApplicationLayoutComponent`, `AccountLayoutComponent`, `EmptyLayoutComponent`. These layouts can be replaced the same way. @@ -88,11 +87,13 @@ This component should have a 'router-outlet' for dynamic content loading. You ca ```bash ng generate component new-layout ``` + This command will create a new component named `new-layout`. Now, open the new-layout.component.html file and add a `router-outlet` to it: ```html - + ``` + This 'router-outlet' will act as a placeholder that Angular dynamically fills based on the current router state. note: (don't forget: you should add the app in the app.module.ts file) @@ -103,10 +104,11 @@ Although this step is optional, it can be useful if you're going to use the layo ```javascript export const eCustomLayout = { - key: 'CustomLayout', - component: 'CustomLayoutComponent', + key: "CustomLayout", + component: "CustomLayoutComponent", }; ``` + In this variable, `key` is a unique identifier for the layout component, and `component` is the name of the layout component. You can use this variable when you need to refer to the layout component. @@ -120,19 +122,24 @@ Here's how you can do it: ```javascript export const CUSTOM_LAYOUT_PROVIDERS = [ - { provide: APP_INITIALIZER, useFactory: configureLayoutFn, deps: [ReplaceableComponentsService], multi: true }, - + { + provide: APP_INITIALIZER, + useFactory: configureLayoutFn, + deps: [ReplaceableComponentsService], + multi: true, + }, ]; function configureLayoutFn() { - const service= inject( ReplaceableComponentsService) - return () =>{ - service.add({ - key: eCustomLayout.component, - component: CustomLayoutComponent, - }) - } + const service = inject(ReplaceableComponentsService); + return () => { + service.add({ + key: eCustomLayout.component, + component: CustomLayoutComponent, + }); + }; } ``` + In this code, `configureLayoutFn` is a factory function that adds the new layout component to the `ReplaceableComponentsService`. The `APP_INITIALIZER` provider runs this function when the application starts. note: (don't forget: you should add the CUSTOM_LAYOUT_PROVIDERS in the app.module.ts file) @@ -149,34 +156,31 @@ export const myDynamicLayouts = new Map([...DEFAULT_DYNAMIC_LAYO #### Step 5: Pass the Dynamic Layouts to the CoreModule -The final step is to pass the dynamic layouts to the `CoreModule` using the `forRoot` method. This method allows you to configure the module with a static method. +The final step is to pass the dynamic layouts to the `provideAbpCore` using the `withOptions` method. This method allows you to configure the module with a static method. Here's how you can do it: -```javascript +```ts @NgModule({ - declarations: [AppComponent], - imports: [ - // other imports... - CoreModule.forRoot({ - dynamicLayouts: myDynamicLayouts, - environment, - registerLocaleFn: registerLocale(), - }), - // other imports... - NewLayoutComponent + providers: [ + // ... + provideAbpCore( + withOptions({ + dynamicLayouts: myDynamicLayouts, + environment, + registerLocaleFn: registerLocale(), + }), + ), ], - providers: [APP_ROUTE_PROVIDER, CUSTOM_LAYOUT_PROVIDERS], - bootstrap: [AppComponent], }) export class AppModule {} ``` -In this code, `myDynamicLayouts` is the map of dynamic layouts you defined earlier. We pass this map to the `CoreModule` using the `forRoot` method. +In this code, `myDynamicLayouts` is the map of dynamic layouts you defined earlier. We pass this map to the `provideAbpCore` using the `withOptions` method. Now that you have defined the new layout, you can use it in the router definition. You do this by adding a new route that uses the new layout. -Here's how you can do it: +Here's how you can do it: ```javascript // route.provider.ts @@ -221,14 +225,13 @@ Run the following command in `angular` folder to create a new component called ` yarn ng generate component logo --inlineTemplate --inlineStyle ``` - Open the generated `logo.component.ts` in `src/app/logo` folder and replace its content with the following: ```js -import { Component } from '@angular/core'; +import { Component } from "@angular/core"; @Component({ - selector: 'app-logo', + selector: "app-logo", template: ` @@ -284,14 +287,14 @@ yarn ng generate component routes Open the generated `routes.component.ts` in `src/app/routes` folder and replace its content with the following: ```js -import { Component, HostBinding } from '@angular/core'; +import { Component, HostBinding } from "@angular/core"; @Component({ - selector: 'app-routes', - templateUrl: 'routes.component.html', + selector: "app-routes", + templateUrl: "routes.component.html", }) export class RoutesComponent { - @HostBinding('class.mx-auto') + @HostBinding("class.mx-auto") marginAuto = true; get smallScreen() { @@ -321,11 +324,14 @@ Open the generated `routes.component.html` in `src/app/routes` folder and replac