Browse Source

Merge branch 'dev' into pr/11417

pull/11417/head
maliming 4 years ago
parent
commit
43ce908eaf
No known key found for this signature in database GPG Key ID: 96224957E51C89E
  1. 16
      .github/workflows/auto-pr.yml
  2. 2
      .gitignore
  3. 24
      Directory.Build.props
  4. 6
      README.md
  5. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  6. 38
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
  7. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/en.json
  8. 237
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  9. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
  10. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json
  11. 21
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
  12. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json
  13. 1
      abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/en.json
  14. 1
      abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/pt-BR.json
  15. 1
      abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/ro-RO.json
  16. 1
      abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/sl.json
  17. 1
      abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/tr.json
  18. 1
      abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/zh-Hans.json
  19. 1
      abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/zh-Hant.json
  20. 51
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  21. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json
  22. 1
      build/common.ps1
  23. 4
      common.props
  24. 2
      configureawait.props
  25. 4
      docs/cs/CLI.md
  26. 2
      docs/en/API/Swagger-Integration.md
  27. 4
      docs/en/Background-Jobs.md
  28. 14
      docs/en/Background-Workers-Hangfire.md
  29. 14
      docs/en/Background-Workers.md
  30. 258
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/POST.md
  31. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/app-nolayers-get-started.png
  32. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/community-talks-2022.4.png
  33. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/cover-53.png
  34. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/deployment-documentation.png
  35. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/gdpr-personal-data-page.png
  36. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/gdpr-user-menu.png
  37. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/leptonx-lite-documentations.png
  38. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/oauth-external-provider.gif
  39. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/poll-new-question.png
  40. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/poll-question-example.png
  41. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/poll-questions.png
  42. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/webinar.png
  43. 8
      docs/en/CLI-New-Command-Samples.md
  44. 41
      docs/en/CLI.md
  45. 2
      docs/en/Caching.md
  46. 243
      docs/en/Community-Articles/2022-05-16-Consuming-Rest-Api-By-Using-Static-Proxy/POST.md
  47. BIN
      docs/en/Community-Articles/2022-05-16-Consuming-Rest-Api-By-Using-Static-Proxy/permission.png
  48. BIN
      docs/en/Community-Articles/2022-05-16-Consuming-Rest-Api-By-Using-Static-Proxy/static-proxy.png
  49. 54
      docs/en/Contribution/How-to-Contribute-abp.io-as-a-frontend-developer.md
  50. 8
      docs/en/Contribution/Index.md
  51. 2
      docs/en/CurrentUser.md
  52. 2
      docs/en/Dependency-Injection.md
  53. 48
      docs/en/Deployment/Clustered-Environment.md
  54. 2
      docs/en/Deployment/Index.md
  55. 219
      docs/en/Distributed-Event-Bus.md
  56. 4
      docs/en/Distributed-Locking.md
  57. 4
      docs/en/Getting-Started-Create-Solution.md
  58. 6
      docs/en/Getting-Started-React-Native.md
  59. 6
      docs/en/Getting-Started-Running-Solution.md
  60. 4
      docs/en/Index.md
  61. 44
      docs/en/Local-Event-Bus.md
  62. 6
      docs/en/Microservice-Architecture.md
  63. 11
      docs/en/Migration-Guides/Abp-5_3.md
  64. 1
      docs/en/Migration-Guides/Index.md
  65. 6
      docs/en/Modules/Account.md
  66. 1
      docs/en/Modules/Index.md
  67. 215
      docs/en/Modules/OpenIddict.md
  68. 11
      docs/en/PlugIn-Modules.md
  69. 4
      docs/en/Repositories.md
  70. 14
      docs/en/Road-Map.md
  71. 18
      docs/en/Samples/Index.md
  72. 2
      docs/en/Samples/Microservice-Demo.md
  73. 107
      docs/en/Startup-Templates/Application-Single-Layer.md
  74. 106
      docs/en/Startup-Templates/Application.md
  75. 8
      docs/en/Startup-Templates/Module.md
  76. 2
      docs/en/Themes/LeptonXLite/angular.md
  77. 37
      docs/en/Themes/LeptonXLite/blazor.md
  78. 13
      docs/en/Themes/LeptonXLite/mvc.md
  79. 15
      docs/en/Tutorials/Todo/Index.md
  80. 14
      docs/en/Tutorials/Todo/Overall.md
  81. 755
      docs/en/Tutorials/Todo/Single-Layer/Index.md
  82. BIN
      docs/en/Tutorials/Todo/Single-Layer/todo-efcore-migration-single-layer.png
  83. 2
      docs/en/UI/Angular/Account-Module.md
  84. 29
      docs/en/UI/Angular/DateTime-Format-Pipe.md
  85. 47
      docs/en/UI/Angular/GlobalFeatures.md
  86. 44
      docs/en/UI/Angular/Loading-Directive.md
  87. 2
      docs/en/UI/Angular/Multi-Tenancy.md
  88. BIN
      docs/en/UI/Angular/images/abp-loading.png
  89. 2
      docs/en/UI/AspNetCore/Branding.md
  90. 24
      docs/en/UI/AspNetCore/JavaScript-API/GlobalFeatures.md
  91. 1
      docs/en/UI/AspNetCore/JavaScript-API/Index.md
  92. 8
      docs/en/UI/AspNetCore/Theming.md
  93. 22
      docs/en/UI/Blazor/Authentication.md
  94. 71
      docs/en/UI/Blazor/Basic-Theme.md
  95. 27
      docs/en/UI/Blazor/Customization-Overriding-Components.md
  96. 40
      docs/en/UI/Blazor/Error-Handling.md
  97. 31
      docs/en/UI/Blazor/Page-Layout.md
  98. 64
      docs/en/UI/Blazor/Theming.md
  99. 19
      docs/en/UI/Blazor/Toolbars.md
  100. 61
      docs/en/docs-nav.json

16
.github/workflows/auto-pr.yml

@ -1,10 +1,10 @@
name: Merge branch dev with rel-5.2
name: Merge branch dev with rel-5.3
on:
push:
branches:
- rel-5.2
- rel-5.3
jobs:
merge-dev-with-rel-5-2:
merge-rel-5-3-with-rel-5-2:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@ -12,13 +12,13 @@ jobs:
ref: dev
- name: Reset promotion branch
run: |
git fetch origin rel-5.2:rel-5.2
git reset --hard rel-5.2
git fetch origin rel-5.3:rel-5.3
git reset --hard rel-5.3
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
branch: auto-merge/rel-5-2/${{github.run_number}}
title: Merge branch dev with rel-5.2
body: This PR generated automatically to merge dev with rel-5.2. Please review the changed files before merging to prevent any errors that may occur.
branch: auto-merge/rel-5-3/${{github.run_number}}
title: Merge branch dev with rel-5.3
body: This PR generated automatically to merge dev with rel-5.3. Please review the changed files before merging to prevent any errors that may occur.
reviewers: ${{github.actor}}
token: ${{ github.token }}

2
.gitignore

@ -301,7 +301,7 @@ samples/MicroserviceDemo/microservices/TenantManagementService.Host/Logs/logs.tx
/npm/packs/bootstrap/package-lock.json
/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/package-lock.json
/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/package-lock.json
/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/package-lock.json
/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/package-lock.json
modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/Logs/
/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/package-lock.json

24
Directory.Build.props

@ -1,14 +1,20 @@
<Project>
<PropertyGroup>
<!-- All Microsoft AspNetCore packages -->
<MicrosoftAspNetCorePackageVersion>6.0.5</MicrosoftAspNetCorePackageVersion>
<!-- All Microsoft EntityFrameworkCore packages -->
<MicrosoftEntityFrameworkCorePackageVersion>6.0.5</MicrosoftEntityFrameworkCorePackageVersion>
<!-- All Microsoft packages -->
<MicrosoftPackageVersion>6.0.0</MicrosoftPackageVersion>
<!-- Microsoft.NET.Test.Sdk https://www.nuget.org/packages/Microsoft.NET.Test.Sdk -->
<MicrosoftNETTestSdkPackageVersion>16.11.0</MicrosoftNETTestSdkPackageVersion>
<MicrosoftNETTestSdkPackageVersion>17.2.0</MicrosoftNETTestSdkPackageVersion>
<!-- NSubstitute https://www.nuget.org/packages/NSubstitute -->
<NSubstitutePackageVersion>4.2.2</NSubstitutePackageVersion>
<NSubstitutePackageVersion>4.3.0</NSubstitutePackageVersion>
<!-- Shouldly https://www.nuget.org/packages/Shouldly -->
<ShouldlyPackageVersion>4.0.3</ShouldlyPackageVersion>
@ -20,20 +26,26 @@
<xUnitExtensibilityExecutionPackageVersion>2.4.1</xUnitExtensibilityExecutionPackageVersion>
<!-- xunit.runner.visualstudio https://www.nuget.org/packages/xunit.runner.visualstudio -->
<xUnitRunnerVisualstudioPackageVersion>2.4.3</xUnitRunnerVisualstudioPackageVersion>
<xUnitRunnerVisualstudioPackageVersion>2.4.5</xUnitRunnerVisualstudioPackageVersion>
<!-- Mongo2Go https://www.nuget.org/packages/Mongo2Go -->
<Mongo2GoPackageVersion>3.1.3</Mongo2GoPackageVersion>
<!-- Microsoft.CodeAnalysis https://www.nuget.org/packages/Microsoft.CodeAnalysis -->
<MicrosoftCodeAnalysisPackageVersion>4.0.1</MicrosoftCodeAnalysisPackageVersion>
<MicrosoftCodeAnalysisPackageVersion>4.2.0</MicrosoftCodeAnalysisPackageVersion>
<!-- NUglify https://www.nuget.org/packages/NUglify -->
<NUglifyPackageVersion>1.20.0</NUglifyPackageVersion>
<!-- Polly https://www.nuget.org/packages/Polly -->
<PollyPackageVersion>7.2.3</PollyPackageVersion>
<IsTestProject Condition="$(MSBuildProjectFullPath.Contains('test')) and ($(MSBuildProjectName.EndsWith('.Tests')) or $(MSBuildProjectName.EndsWith('.TestBase')))">true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Condition="'$(IsTestProject)' == 'true'" Include="coverlet.collector" Version="3.1.0">
<PackageReference Condition="'$(IsTestProject)' == 'true'" Include="coverlet.collector" Version="3.1.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

6
README.md

@ -7,7 +7,9 @@
[![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)
ABP Framework is a complete **infrastructure** based on the **ASP.NET Core** to create **modern web applications** and **APIs** by following the software development **best practices** and the **latest technologies**.
[![ABP Discord server](https://img.shields.io/discord/951497912645476422?label=Discord)](https://discord.gg/abp)
ABP Framework is a complete **infrastructure** based on the **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
## Getting Started
@ -65,7 +67,7 @@ ABP is a modular framework and the Application Modules provide **pre-built appli
- [**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.
- [**IdentityServer**](https://docs.abp.io/en/abp/latest/Modules/IdentityServer): Integrates to IdentityServer4.
- [**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.

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

@ -393,6 +393,7 @@
"StartTime": "Start Time",
"EndTime": "End Time",
"CreateABookDiscount": "Create a book discount",
"BookDiscountDeletionConfirmationMessage": "Are you sure you want to delete this book discount?"
"BookDiscountDeletionConfirmationMessage": "Are you sure you want to delete this book discount?",
"CustomPaymentFlexSwitchDescription": "With license"
}
}

38
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json

@ -26,6 +26,8 @@
"Volo.AbpIo.Domain:030009": "User not found!",
"Volo.AbpIo.Domain:030010": "To purchase the trial license, you first need to activate your trial license!",
"Volo.AbpIo.Domain:030011": "You cannot delete a trial license when it is purchased!",
"Volo.AbpIo.Domain:070000": "The organization name can only contain latin letters, numbers, dots and hyphens!",
"Volo.AbpIo.Domain:070001": "The company name can only contain latin letters, numbers, dots, space and hyphens!",
"WantToLearn?": "Want to learn?",
"ReadyToGetStarted?": "Ready to get started?",
"JoinOurCommunity": "Join our community",
@ -125,6 +127,40 @@
"Volo.AbpIo.Domain:080001": "Start Time can not be greater than End Time",
"Enum:BookType:0": "Mastering ABP Framework",
"Enum:PurchasePlatform:0": "Amazon",
"Enum:PurchasePlatform:1": "Packt"
"Enum:PurchasePlatform:1": "Packt",
"Copied": "Copied!",
"CouldNotCopy": "Could not copy!",
"CopyNotSupportByYourBrowser": "This feature does not work in the browser you are using.",
"City": "City",
"ZipCode": "Zip Code",
"Address": "Address",
"Homepage": "Homepage",
"Year": "Year",
"Copyright": "Copyright © <a href=\"{0}\" target=\"_blank\">{1}</a>",
"DomainDrivenDesign": "Domain Driven Design",
"CrossCuttingConcerns": "Cross Cutting Concerns",
"AbpCommunity": "ABP Community",
"Footer_GithubStarCount": "{0} Star on GitHub",
"Footer_NugetDownloadCount": "{0} Downloads on NuGet",
"AbpDescription": "ABP is an open source application framework focused on AspNet Core based web application development. Don't repeat yourself, focus on your own business code.",
"Layout_AbpFramework_MetaTitle": "ABP Framework - Open Source Web Application Framework",
"CommunityTalks_CountdownDays": "Days",
"CommunityTalks_CountdownHours": "Hrs",
"CommunityTalks_CountdownMinutes": "Min",
"CommunityTalks_CountdownSeconds": "Sec",
"SeePreviousEvents": "See Previous Events",
"CookieConsent_Accept": "Accept",
"CookieConsent_Explanation_1": "We use cookies to give you the best experience on our website.",
"CookieConsent_Explanation_2": "If you continue to browse, then you agree to our <a href=\"@Url.Page(\"/Privacy\")\">Privacy policy and cookie policy.</a>.",
"Error_Page_400_Title": "There was a problem serving the requested page.",
"Error_Page_400_Description_1": "Usually this means that an unexpected error happened while processing your request.",
"Error_Page_400_Description_2": "If the problem persists, contact us at <a href=\"mailto:info@abp.io\">info@abp.io</a> and we'll help get you on your way.",
"GoToHomepage": "Go to Homepage",
"Error_Page_404_Title": "Page Not Found!",
"Error_Page_404_Description_1": "This is not the web page you're looking for.",
"Error_Page_500_Title": "Looks like something went wrong!",
"Error_Page_500_Description_1": "We track these errors automatically, but if the problem persists feel free to <br /> contact us. In the meantime, try refreshing.",
"Error_Page_500_Description_2": "Contact with us at <a href=\"mailto:info@abp.io\" target=\"_blank\">info@abp.io</a>.",
"Books": "Books"
}
}

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

@ -1,5 +1,7 @@
{
"culture": "en",
"texts": {
"AbpTitle": "ABP Framework - Open Source Web Application Framework",
"AbpDescription": "ABP is an open source application framework focused on AspNet Core based web application development. Don't repeat yourself, focus on your own business code."
}
}

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

@ -10,7 +10,7 @@
"Unlimited": "Unlimited",
"Owners": "Owners",
"Owner": "Owner",
"AddMember": "Add member",
"AddMember": "Add Member",
"AddNewOwner": "Add New Owner",
"AddNewDeveloper": "Add New Developer",
"UserName": "Username",
@ -30,7 +30,7 @@
"LicenseAddDeveloperMessage": "{0} developers added to your license",
"Volo.AbpIo.Commercial:010004": "Can not find the specified user! The user must have already been registered.",
"MyOrganizations": "My organizations",
"ApiKey": "API key",
"ApiKey": "API Key",
"UserNameNotFound": "There is no user with the username {0}",
"SuccessfullyAddedToNewsletter": "Thank you for subscribing to our newsletter!",
"MyProfile": "My profile",
@ -128,6 +128,8 @@
"TellUsWhatYouNeed": "Tell us what you need.",
"YourMessage": "Your Message",
"YourFullName": "Your full name",
"FirstNameField": "First Name",
"LastNameField": "Last Name",
"EmailField": "E-mail Address",
"YourEmailAddress": "Your e-mail address",
"HowMayWeHelpYou": "How may we help you?",
@ -158,6 +160,8 @@
"SearchQuestionPlaceholder": "Search in frequently asked questions",
"WhatIsTheABPCommercial": "What is ABP Commercial?",
"WhatAreDifferencesThanAbpFramework": "What are the differences between the open source ABP Framework and ABP Commercial?",
"AbpCommercialMetaTitle": "ABP Commercial - Complete Web Development Platform : {0} | ABP Commercial",
"AbpCommercialMetaDescription": "ABP Commercial is a set of pre-built application modules, rapid development tooling, UI themes and services built on top of the open-source ABP framework.",
"ABPCommercialExplanation": "ABP Commercial is a set of premium modules, tools, themes and services that are built on top of the open source <a target=\"_blank\" href=\"{0}\">ABP framework</a>. ABP Commercial is being developed and supported by the same team behind the ABP framework.",
"WhatAreDifferencesThanABPFrameworkExplanation": "<p> <a target=\"_blank\" href=\"{0}\">ABP framework</a> is a modular, themeable, micro-service compatible application development framework for ASP.NET Core. It provides a complete architecture and a strong infrastructure to let you focus on your own business code rather than repeating yourself for every new project. It is based on the best practices of software development and popular tools you already know. </p> <p> ABP framework is completely free, open source and community-driven. It also provides a free theme and some pre-built modules (e.g. identity management and tenant management).</p>",
"VisitTheFrameworkVSCommercialDocument": "Visit the following link for more information <a href=\"{0}\" target=\"_blank\"> {1} </a>",
@ -199,6 +203,7 @@
"WhatHappensWhenLicenseEndsExplanation5": "You can not use the ABP Suite.",
"WhatHappensWhenLicenseEndsExplanation6": "You can not get the <a href=\"{0}\">premium support</a> anymore.",
"WhatHappensWhenLicenseEndsExplanation7": "You can extend (renew) your license if you want to continue getting these benefits. If you extend your license within <strong>1 month</strong> after your license expires, the following discounts will be applied: Team License {0}% discount, Business License {1}% discount, Enterprise License {2}% discount.",
"WhatHappensWhenLicenseEndsExplanation8": "The ABP projects you generated are not stored on our servers. Therefore, it is your responsibility to keep the source code you download. When your license expires, there's no way to get your generated ABP project source code.",
"WhenShouldIRenewMyLicense": "When should I renew my license?",
"WhenShouldIRenewMyLicenseExplanation": "If you renew your license within <strong>1 month</strong> after your license expires, the following discounts will be applied: Team License {0}% discount, Business License {1}% discount, Enterprise License {2}% discount. However, if you renew your license after <strong>1 month</strong> since the expiry date of your license, the renewal price will be the same as the license purchase price and there will be no discount on your renewal.",
"TrialPlan": "Do you have a trial plan?",
@ -378,13 +383,11 @@
"TaxNoValidationMessage": "TAX/VAT No is too long!",
"NotesValidationMessage": "Notes field is too long!",
"CheckYourBillingInfo": "You can create your invoice only once! Check your billing information before creating your invoice.",
"Volo.AbpIo.Commercial:030000": "You already used your trial period.",
"Volo.AbpIo.Commercial:030001": "This organization name already exists.",
"StartYourFreeTrial": "Start your free trial",
"TrialLicenseModelInvalidErrorMessage": "One of the following fields is invalid: Country Name, Company Size, Industry or Purpose Of Usage.",
"Trial": "Trial",
"Purchased": "Purchased",
"PurchaseLicense": "Purchase Now",
"PurchaseNow": "Purchase Now",
"PurchaseTrialLicenseMessage": "Your license expiration date is {0}. <br> If you want to continue using the projects you created during your free trial period, you need to change the license keys in your <code>appsettings.secrets.json</code> files. Here is your license key:",
"TrialLicenseExpireMessage": "You are using the trial license and your trial license will expire on {0}.",
"TryForFree": "Try For Free",
@ -487,25 +490,239 @@
"BackOfficeApplicationExplanation": "The actual web application of your system, with multiple UI framework options. You can create any kind of business application.",
"LandingWebsite": "Landing Website",
"LandingWebsiteExplanation": "A generic landing/public website that can be used for several purposes, like introducing your company, selling your products, etc.",
"ABPFrameworkEBook": "E-Book: Mastering ABP Framework",
"ABPFrameworkEBook": "Mastering ABP Framework e-book",
"MasteringAbpFrameworkEBookDescription": "Included within your ABP Commercial license",
"Volo.AbpIo.Domain:070000": "The organization name can only contain latin letters, numbers, dots and hyphens!",
"Volo.AbpIo.Domain:070001": "The company name can only contain latin letters, numbers, dots, space and hyphens!",
"FullName": "Full Name",
"LicenseTypeNotCorrect": "The license type is not correct!",
"Trainings": "Trainings",
"ChoseTrainingPlaceholder": "Chose the training...",
"ChooseTrainingPlaceholder": "Choose the training...",
"DoYouNeedTrainings": "Do you need one of these trainings?",
"DoYouNeedTraining": "Do you need {0} training?",
"GetInTouchUs": "Get in touch with us",
"ForMoreInformationClickHere": "For more information, click <a href='{0}'>here.</a>",
"IsGetOnboardingTraining": "Would you like to get onboarding & web application development training?",
"OnboardingWebApplicationDevelopmentTrainingMessage": "To schedule your training calendar, please contact {0} after creating the organization",
"CustomPurchaseMessage": "For the next step, click {0} to contact us.",
"Note": "Note",
"AdditionalNote": "Additional Note",
"OnboardingTrainingFaqTitle": "Do you have ABP onboarding training?",
"OnboardingTrainingFaqExplanation": "Yes, we have ABP Training Services to help you get your ABP project started fast. You will learn about ABP from an ABP core team member and you will get the skills to begin your ABP project. In the onboarding training, we will explain how to set up your development environment, install the required tools, create a fully functional CRUD page. The training will be live and the Zoom application will be used, and we are open to using other online meeting platforms. The language of the training will be English. You can also ask your questions about ABP during the sessions. A convenient time and date will be planned for both parties. To get more information, contact us at <a href=\"mailto:info@abp.io\">info@abp.io</a>.",
"AddBasket": "Add to Basket",
"SendTrainingRequest": "Send Training Request"
"SendTrainingRequest": "Send Training Request",
"OnlyEnglishVersionOfThisDocumentIsTheRecentAndValid": "* The English version of this document is the most up-to-date and the English version will prevail in any dispute.",
"Pricing_Page_Title": "Plans & Pricing",
"Pricing_Page_Description": "Choose the features and functionality your business needs today. Buy an ABP Commercial license and create unlimited projects.",
"Pricing_Page_HurryUp": "Hurry Up!",
"Pricing_Page_BuyLicense": "Buy a license at <strong>2021 prices</strong> until January 16!",
"Pricing_Page_ValidForExistingCustomers": "Also valid for existing customers and license renewals.",
"Pricing_Page_Hint1": "The license price includes a certain number of developer seats. If you have more developers, you can always purchase additional seats.",
"Pricing_Page_Hint2": "You can purchase more developer licenses now or in the future. Licenses are seat based, so you can transfer a seat from a developer to another.",
"Pricing_Page_Hint3": "You can develop unlimited count of different products with your license.",
"Pricing_Page_Hint4": "ABP Suite is a tool to assist your development to improve your productivity. It supports generating CRUD pages and creating new projects.",
"Pricing_Page_Hint5": "You can use all the pre-built modules in your applications.",
"Pricing_Page_Hint6": "You can use all the pre-built themes in your applications.",
"Pricing_Page_Hint7": "A startup template is a Visual Studio solution to make you jump-start to your project. All fundamental modules are added and pre-configured for you.",
"Pricing_Page_Hint8": "Mastering ABP Framework e-book explains how to implement .NET solutions with best practices. It is sold on Amazon.com and you can download the book for free within your license.",
"Pricing_Page_Hint9": "You can download the source-code of any module. You may want to add the source code to your solution to make radical changes or just keep it for yourself for security reasons.",
"Pricing_Page_Hint10": "Licenses are for lifetime. That means you can continue to develop your application forever. Accessing to the latest version and getting support are granted within the license period (1 year unless you renew it).",
"Pricing_Page_Hint11": "No restrictions on deployment! You can deploy to as many servers as you want, including the cloud services or on-premises.",
"Pricing_Page_Hint12": "You can update the modules, themes and tools to the latest version within your active license period. After your license expires, you need to renew it, to continue to get updates for bug fixes, new features and enhancements.",
"Pricing_Page_Hint13": "You can get the premium support for one year (you can renew your license to extend it).",
"Pricing_Page_Hint14": "Team and Business licenses have incident/question count limit. If you buy additional developer licenses, your incident limit increases by {0} (for the Team License) or {1} (for the Business License) per developer.",
"Pricing_Page_Hint15": "Only Enterprise License includes private support. You can send e-mail directly to the ABP Team or ask questions on support.abp.io with private ticket option. The private tickets are not visible to the public.",
"Pricing_Page_Hint16": "You can download the source-code of all ABP themes. You may want to add the source code to your solution to make radical changes or just keep it for yourself for security reasons.",
"Pricing_Page_Testimonial_1": "ABP Commercial allowed SC Ventures to deliver a bank-grade multi-tenant silo-database SaaS platform in 9 months to support the accounts receivable / accounts payable supply chain financing of significant value invoices from multiple integrated anchors. The modularity of ABP made it possible for the team to deliver in record time, pass all VAPT, and deploy the containerized micro-services stack via full CI/CD and pipelines into production.",
"Pricing_Page_Testimonial_2": "We are seeing the value of using ABP Commercial to reduce the overhead of custom development projects. And the team is able to unify the code pattern in different project streams. We see more potential in the framework for us to build new features faster than before. We trust we will be constantly seeing the value of leveraging ABP Commercial.",
"Pricing_Page_Testimonial_3": "We love ABP. We don't have to write everything from scratch. We start from out-of-the-box features and just focus on what we really need to write. Also, ABP is well-architected and the code is high quality with fewer bugs. If we would have to write everything we needed on our own, we might have to spend years. Once more things we like is that the new version, or issue fixing, or improvement come out very soon every other week. We don't wait too long.",
"Pricing_Page_Testimonial_4": "ABP Commercial is a fantastic product would recommend. Commercial products to market for our customers in a single configurable platform. The jump start that the framework and tooling provide any team is worth every cent. ABP Commercial was the best fit for our needs.",
"AbpBookDownloadArea_ClaimYourEBook": "Claim your <span class='gradient-framework'>Mastering ABP Framework</span> E-Book",
"AddMemberModal_Warning_1": "If the <strong>username</strong> you are trying to add doesn't exist in the system, please ask your team member to register on <a href='{0}/Account/Register'>{0}</a> and share the username of his/her account with you.",
"MyOrganizations_Detail_WelcomeMessage": "Welcome to your organization, {0}",
"MyOrganizations_Detail_OrganizationManagement": "Organization <span class=\"gradient-commercial\">Management</span>",
"OrganizationDisplayName": "Organization Display Name",
"MyOrganizations_Detail_EditDisplayName": "Edit Display Name",
"MyOrganizations_Detail_UpgradeYourLicense": "Upgrade your license",
"MyOrganizations_Detail_LicenseStartAndExpiryDate": "License Start Date - Expiry Date",
"MyOrganizations_Detail_OwnerRightInfo": "You are using {0} of your {1} owners rights.",
"MyOrganizations_Detail_CopyApiKey": "Copy the Key",
"MyOrganizations_Detail_ApiKeyDescription": "The API Key is the token of PRO packages hosted on <a href=\"{0}\" target=\"_blank\" class=\"text-primary\" rel=\"noopener\">{1}.</a>",
"MyOrganizations_Detail_YourPrivateNugetSource": "Your private NuGet source is <a href=\"{0}\" arget=\"_blank\" class=\"text-primary\" rel=\"noopener\">{0}</a>",
"MyOrganizations_Detail_PrivateNugetSourceWarning": "This is automatically added as a feed to your NuGet.Config in your ABP solution. Do not share your private key with unauthorized users!",
"MyOrganizations_Detail_DeveloperSeatInfo": "You are using {0} of your {1} developer seats.",
"NeedMoreSeatsForYourTeam": "Need more seats for your team?",
"MyOrganizations_Detail_PricePerYear": "{0} / per year",
"MyOrganizations_Detail_PurchaseDeveloperSeats": "Purchase Developer Seats",
"Invoices": "Invoices",
"RequestInvoice": "Request Invoice",
"OrderNumber": "Order Number",
"Date": "Date",
"Products": "Products",
"TotalPrice": "Total Price",
"ThereIsNoInvoice": "There is no invoice",
"MyOrganizations_Detail_PaymentProviderInfo": "If you have purchased your license through <i>{0}</i> gateway, it sends the PDF invoice to your email address, see <a href=\"{1}\" target=\"_blank\">{0} invoicing.</a>",
"MyOrganizations_Detail_PayUInfo": "If you have purchased through the <i>PayU</i> gateway, click the \"Request Invoice\" button and fill in the billing information.",
"MyOrganizations_Detail_ConclusionInfo": "Your invoice request will be concluded within {0} business days.",
"ExtendYourLicense": "Extend your {0} license",
"Continue": "Continue",
"PurchaseLicense": "Purchase {0} license",
"DownloadInvoiceModal_DownloadInvoice": "Download Invoice",
"DownloadInvoiceModal_SaveInformationOnlyOnce": "You can save your billing information only once.",
"InvoiceModal_EnterCompanyName": "Enter your legal company name...",
"InvoiceModal_EnterCompanyAddress": "Enter your legal company address...",
"InvoiceModal_EnterTaxNumber": "Enter your TAX/VAT number if available...",
"RequestInvoiceModal_EnterNotes": "Enter your extra message about your invoice...",
"PrePayment_PayWithIyzico": "You will pay with Iyzico",
"ContinueToCheckout": "Continue to Checkout",
"PrePayment_IyzicoRedirectionInfo": "You will be redirected to Iyzico Payment Gateway to complete your purchase securely.",
"PrePayment_IyzicoAcceptVisaAndMasterCard": "Iyzico accepts Visa and MasterCard.",
"Purchase": "Purchase",
"AcceptTermsAndConditions": "I have read, understand and accept the <a href=\"{0}\" target=\"_blank\" class=\"text-primary\" rel=\"noopener\">privacy policy</a>, <a href=\"{1}\" target=\"_blank\" class=\"text-primary\" rel=\"noopener\">terms & conditions</a> and <a href=\"{2}\" target=\"_blank\" class=\"text-primary\"> EULA.</a>",
"AcceptTermsAndConditionsWarningMessage": "Please accept the privacy policy and terms & conditions",
"SelectGatewayToContinue": "Please select a Gateway to continue!",
"GatewaySelection_SelectGateway": "Select a Payment Gateway",
"GatewaySelection_RedirectionMessage": "Next, you will be redirected to the selected payment gateway's website for the transaction.",
"PaymentSucceed_PaymentSuccessMessage": "Payment Successful",
"PaymentSucceed_ThanksForPurchase": "Thank you for your purchase!",
"PaymentSucceed_CreateYourOrganization": "Create your organization",
"PaymentSucceed_AddMeAsDeveloper": "I'm a developer too, add me as a a developer to my organization.",
"PaymentSucceed_CreateOrganization": "Create Organization",
"PaymentSucceed_OrganizationDescription": "An organization consists of developers and owners. The developers are users who write code on ABP project and will benefit from the <a href=\"{0}\" target=\"_blank\">{1}</a> website. The owners are users who allocate developer seats and manage licensing.",
"PaymentSucceed_ViewOrganization": "Click here to view organization",
"Purchase_TotalAnnualPrice": "TOTAL <small class=\"opacity-50\">(annual fee)</small>",
"Purchase_TrainingPrice": "Training Price",
"Purchase_OnboardingTraining": "ABP Onboarding & Web Application Development Live Training",
"TotalDeveloperPrice": "Total Developer Price",
"Purchase_PricePerDeveloper": "<span>{0} {1}</span> per developer",
"Purchase_IncludedDeveloperInfo": "{0} {1} included.",
"Purchase_LicenseExtraDeveloperPurchaseMessage": "The <span class=\"fw-6\">{0} license</span> contains {1} developer(s). You can add additional developers now or later.",
"StartupTemplates_Page_Title": "The Startup Templates",
"StartupTemplates_Page_Description": "ABP Commercial allows you to build solutions with any level of complexity. It provides two main pre-built startup solutions. You can select the one close to your requirements and build your own custom solution on top of it.",
"MicroserviceStartupSolutionForDotnet": "Microservice Startup Solution for .NET",
"MonolithSolutionForDotnet": "Monolith (modular) Solution for .NET",
"TrainingDetailsHeaderInfo_TrainingHour": "{0} hour(s)",
"Trainings_Content": "Content of Training",
"Trial_Page_StartYourFreeTrial": "Start Your <span class=\"gradient-commercial\">Free Trial</span>",
"Contact_Page_Title": "Contact with ABP Development Team",
"Contact_Page_Description": "Contact with ABP Development team, if you need any help or share your thoughts and opinions! ABP Support Team is ready to help.",
"Demo_Page_Title": "Create a Demo",
"Demo_Page_Description": "Create a free demo to see a sample application created using the ABP Commercial startup template. Don't repeat yourself for common application requirements.",
"Discounted_Page_Title": "Discounted pricing",
"Discounted_Page_Description": "Choose the features and functionality your business needs today. Buy an ABP Commercial license and create unlimited projects",
"Faq_Page_Title": "Frequently Asked Questions (FAQ)",
"Faq_Page_Description": "Do you have any questions? Search frequently asked questions or ask us a question using the contact form.",
"Faq_Page_SwiftCode": "SWIFT Code",
"Faq_Page_BankName": "Bank Name",
"Faq_Page_AccountName": "Account Name",
"Faq_Page_AccountNumber": "Account Number",
"Faq_Page_Currency": "Currency",
"Faq_Page_VatNumber": "VAT number",
"Faq_Page_OtherCurrenciesInfo": "For other currencies, see <a href='{0}'>all accounts</a>",
"ModuleDetail_Page_Title": "Module Detail - {0}",
"ProjectCreatedSuccess_Page_Title": "Your project created",
"ProjectCreatedSuccess_Page_Description": "Your ABP project created successfully!",
"Suite_Page_Title": "ABP Suite - Create CRUD Pages",
"Suite_Page_Description": "ABP Commercial provides rapid application development tooling to increase developer productivity. ABP Suite allows you to create CRUD pages easily.",
"Themes_Page_Title": "Modern and Functional UI Themes",
"Themes_Page_Description": "ABP Commercial provides multiple professional, modern UI themes. Create a free demo to have a quick view of what the UI looks like.",
"Tools_Page_Title": "Rapid Application Development Tools",
"Tools_Page_Description": "ABP Commercial provides rapid application development tooling to increase developer productivity. ABP Suite allows you to create CRUD pages easily.",
"DeveloperPrice": "Developer Price",
"AdditionalDeveloperPaymentInfoSection_AdditionalDevelopers": "{0} <small>developers</small>",
"LicenseRemainingDays": "for <span> {0} </span> days",
"ExtendPaymentInfoSection_Description": "By extending/renewing your license, you will continue to get <a href=\"{0}\" target=\"_blank\">premium support</a>. You will also be able to get major updates for modules and themes. You will be able to continue creating new projects. And you will still be able to use <a href=\"{1}\" target=\"_blank\">ABP Suite</a> which speeds up your development.",
"LicenseRenewalPrice": "License renewal price",
"LicensePrice": "License Price",
"TrialLicensePaymentInfoSection_Description": "<strong>Purchase license:</strong> By purchasing a license, you will continue to get <a href=\"{0}\" target=\"_blank\" rel=\"noopener\">premium support</a>. You will also be able to get major updates for modules and themes. You will be able to continue creating new projects. And you will still be able to use <a href=\"{1}\" target=\"_blank\" rel=\"noopener\">ABP Suite</a> which speeds up your development.<br>See the <a href=\"{2}\" target=\"_blank\" rel=\"noopener\">license comparison table</a> to check the differences between the license types.",
"SelectTargetLicense": "Select Target License",
"UpgradePaymentInfoSection_ExtendMyLicenseForOneYear": "Yes, extend my license expiration date for 1 year.",
"UpgradePaymentInfoSection_WantToExtendLicense": "Do you want to extend your license for {0} more year(s)?",
"UpgradePaymentInfoSection_UpgradingWillNotExtendLicense": "Upgrading will not extend your license expiration date!",
"UpgradePaymentInfoSection_LicenseUpgradeDescription": "By upgrading your license, you will promote to a higher license type which will allow you to get additional benefits. See the <a href=\"/Pricing\" target=\"_blank\">license comparison table</a> to check the differences between the license types.",
"Landing_Page_CustomerStories": "Customer Stories",
"Landing_Page_OurGreatCustomers": "Our Great Customers",
"Landing_Page_WebApplicationFramework": "Web Application Framework",
"Landing_Page_WebDevelopmentPlatform": "Web Development Platform",
"Landing_Page_CompleteWebDevelopmentPlatform": "Complete Web Development Platform",
"Landing_Page_TryFreeDemo": "Try Free Demo",
"Landing_Page_StartingPointForWebApplications": "The starting point for ASP.NET Core based web applications! It is based on the ABP Framework for best web development.",
"Landing_Page_AbpProvidesSoftwareInfrastructure": "ABP Framework provides a software infrastructure to develop excellent web applications with best practices.",
"Landing_Page_MicroserviceCompatibleArchitecture": "Microservice Compatible Architecture",
"Landing_Page_PreBuiltApplicationModulesAndThemes": "Pre-Built Application Modules & Themes",
"Landing_Page_MultiTenantArchitecture": "Multi-Tenant Architecture",
"Landing_Page_MultiTenancyDescription": "SaaS applications made easy! Integrated multi-tenancy from database to UI.",
"Landing_Page_DDDIntroduction": "Designed and developed based on DDD patterns and principles. Provides a layered model for your application.",
"Landing_Page_CrossCuttingConcernsInfo": "Complete infrastructure for authorization, validation, exception handling, caching, audit logging, transaction management and more.",
"Landing_Page_PreBuiltApplicationModules": "Pre-Built Application Modules which include most common web application requirements.",
"Landing_Page_ChatModule": "Chat",
"Landing_Page_DocsModule": "Docs",
"Landing_Page_FileManagementModule": "Docs",
"Landing_Page_CustomerStory_1": "ABP Commercial allowed SC Ventures to deliver a bank-grade multi-tenant silo-database SaaS platform in 9 months to support the accounts receivable / accounts payable supply chain financing of significant value invoices from multiple integrated anchors. The modularity of ABP made it possible for the team to deliver in record time, pass all VAPT, and deploy the containerized micro-services stack via full CI/CD and pipelines into production.",
"Landing_Page_CustomerStory_2": "We are seeing the value of using ABP Commercial to reduce the overhead of custom development projects. And the team is able to unify the code pattern in different project streams. We see more potential in the framework for us to build new features faster than before. We trust we will be constantly seeing the value of leveraging ABP Commercial.",
"Landing_Page_CustomerStory_3": "We love ABP. We don't have to write everything from scratch. We start from out-of-the-box features and just focus on what we really need to write. Also, ABP is well-architected and the code is high quality with fewer bugs. If we would have to write everything we needed on our own, we might have to spend years. Once more things we like is that the new version, or issue fixing, or improvement come out very soon\n every other week. We don't wait too long.",
"Landing_Page_CustomerStory_4": "ABP Commercial is a fantastic product would recommend. Commercial products to market for our customers in a single configurable platform. The jump start that the framework and tooling provide any team is worth every cent. ABP Commercial was the best fit for our needs.",
"Landing_Page_AdditionalServices": "Custom or volume license, onboarding, live training & support, custom project development, porting existing projects and more...",
"Landing_Page_IncludedDeveloperLicenses": "Included <strong>{0}</strong> developer licenses",
"Landing_Page_SeeOnDemo": "See on Demo",
"Landing_Page_LeptonThemes": "LeptonThemes",
"Landing_Page_AccountModuleDescription_1": "This module implements the authentication system for an application;",
"Landing_Page_AccountModuleDescription_2": "Provides a <strong>login</strong> page with the username and password",
"Landing_Page_AccountModuleDescription_3": "Provides a <strong>register</strong> page to create a new account.",
"Landing_Page_AccountModuleDescription_4": "Provides a <strong>forgot password</strong> page to send a <strong>password reset</strong> link as an e-mail.",
"Landing_Page_AccountModuleDescription_5": "Provides <strong>email confirmation</strong> functionality with UI.",
"Landing_Page_AccountModuleDescription_6": "Implements <strong>two factor</strong> authentication (SMS and e-mail).",
"Landing_Page_AccountModuleDescription_7": "Implements <strong>user lockout</strong> (locks the account for the set amount of time when a certain number of failed logons occur due to invalid credentials within a certain interval of time).",
"Landing_Page_AccountModuleDescription_8": "Implements <strong>Identity Server</strong> authentication server UI and functionality.",
"Landing_Page_AccountModuleDescription_9": "Allows to <strong>switch between tenants</strong> in a multi-tenant environment.",
"Landing_Page_AccountModuleDescription_10": "Allows to change the <strong>UI language</strong> of the application.",
"Landing_Page_AuditLoggingModuleDescription_1": "This module provides the audit log reporting UI for the auditing infrastructure. Allows to search, filter and show audit log entries and entity change logs.",
"Landing_Page_AuditLoggingModuleDescription_2": "An audit log entry consists of critical data about each client request:",
"Landing_Page_AuditLoggingModuleDescription_3": "URL, Browser, IP address, client name",
"Landing_Page_AuditLoggingModuleDescription_4": "The user",
"Landing_Page_AuditLoggingModuleDescription_5": "HTTP method, HTTP return status code",
"Landing_Page_AuditLoggingModuleDescription_6": "Success/failure, exception details if available",
"Landing_Page_AuditLoggingModuleDescription_7": "Request execution duration",
"Landing_Page_AuditLoggingModuleDescription_8": "The entities have been created, deleted or updated in this request (with changed properties).",
"Landing_Page_BloggingModuleDescription_1": "This module adds a simple blog to your ABP application;",
"Landing_Page_BloggingModuleDescription_2": "Allows to create multiple blogs in a single application.",
"Landing_Page_BloggingModuleDescription_3": "Supports the Markdown format.",
"Landing_Page_BloggingModuleDescription_4": "Allows to write comment for a post.",
"Landing_Page_BloggingModuleDescription_5": "Allows to assign tags to the blog posts.",
"Landing_Page_BloggingModuleDescription_6": "See the <a href=\"blog.abp.io\">blog.abp.io</a> website as a live example of the blogging module.",
"Landing_Page_ChatModuleDescription_1": "This module is used for real-time messaging between users in application.",
"Landing_Page_ChatModuleDescription_2": "Real-time messaging on chat page.",
"Landing_Page_ChatModuleDescription_3": "Search users in application for new conversations.",
"Landing_Page_ChatModuleDescription_4": "Contact list for recent conversations.",
"Landing_Page_ChatModuleDescription_5": "New message notifications when user is looking at another page.",
"Landing_Page_ChatModuleDescription_6": "Total unread message count badge on menu icon.",
"Landing_Page_ChatModuleDescription_7": "Unread message count for each conversation.",
"Landing_Page_ChatModuleDescription_8": "Lazy loaded conversations.",
"Landing_Page_DocsModuleDescription_1": "This module is used to create technical documentation web sites;",
"Landing_Page_DocsModuleDescription_2": "Built-in <strong>GitHub integration</strong>: Directly write and manage documents on GitHub.",
"Landing_Page_DocsModuleDescription_3": "<strong>Versioning</strong> support directly integrated to GitHub releases.",
"Landing_Page_DocsModuleDescription_4": "Supports <strong>multi-language</strong> (with fallback support to the default language).",
"Landing_Page_DocsModuleDescription_5": "Supports the <strong>Markdown</strong> and HTML formats.",
"Landing_Page_DocsModuleDescription_6": "Provides a <strong>navigation</strong> and an <strong>outline</strong> section.",
"Landing_Page_DocsModuleDescription_7": "Allows to host <strong>multiple projects</strong> documentation in a single application.",
"Landing_Page_DocsModuleDescription_8": "Links to the file on GitHub, so anyone can easily contribute by clicking to the <strong>Edit link</strong>.",
"Landing_Page_DocsModuleDescription_9": "In addition to the GitHub source, allows to simply use a folder as the documentation source.",
"Landing_Page_FileManagementModuleDescription_1": "Upload, download and organize files in a hierarchical folder structure.",
"Landing_Page_FileManagementModuleDescription_2": "This module is used to upload, download and organize files in a hierarchical folder structure. It is also compatible to multi-tenancy and you can determine total size limit for your tenants.",
"Landing_Page_FileManagementModuleDescription_3": "This module is based on the <a href=\"https://docs.abp.io/en/abp/latest/Blob-Storing\">BLOB Storing</a> system, so it can use different storage providers to store the file contents.",
"Landing_Page_IdentityModuleDescription_1": "This module implements the User and Role system of an application;",
"Landing_Page_IdentityModuleDescription_2": "Built on the <a href=\"https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity\">Microsoft's ASP.NET Core Identity</a> library.",
"Landing_Page_IdentityModuleDescription_3": "Manage <strong>roles</strong> and <strong>users</strong> in the system. A user is allowed to have <strong>multiple roles</strong>.",
"Landing_Page_IdentityModuleDescription_4": "Set <strong>permissions</strong> in role and user levels.",
"Landing_Page_IdentityModuleDescription_5": "Enable/disable <strong>two factor authentication</strong> and user <strong>lockout</strong> per user.",
"Landing_Page_IdentityModuleDescription_6": "Manage basic <strong>user profile</strong> and <strong>password</strong>.",
"Landing_Page_IdentityModuleDescription_7": "Manage <strong>claim types</strong> in the system, set claims to roles and users.",
"Landing_Page_IdentityModuleDescription_8": "Setting page to manage <strong>password complexity</strong>, user sign-in, account and lockout.",
"Landing_Page_IdentityModuleDescription_9": "Supports <strong>LDAP</strong> authentication.",
"Landing_Page_IdentityModuleDescription_10": "Provides <strong>email &amp; phone number</strong> verification.",
"Landing_Page_IdentityModuleDescription_11": "Supports social login integrations (Twitter, Facebook, GitHub etc...).",
"Landing_Page_IdentityModuleDescription_12": "Manage <strong>organization units</strong> in the system.",
"Landing_Page_PaymentModuleDescription_1": "Provides integration for different payment gateways.",
"Landing_Page_PaymentModuleDescription_2": "This module provides integration for payment gateways, so you can easily get payment from your customers.",
"Landing_Page_PaymentModuleDescription_3": "This module supports the following payment gateways",
"Welcome_Page_UseSameCredentialForCommercialWebsites": "Use the same credentials for both <a href=\"https://commercial.abp.io\" class=\"text-primary\">commercial.abp.io</a> and <a href=\"https://support.abp.io\" class=\"text-primary\">support.abp.io</a>."
}
}

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json

@ -131,7 +131,7 @@
"YourFullName": "你的全名",
"EmailField": "E-mail地址",
"YourEmailAddress": "你的e-mail地址",
"HowMayWeHelpYou": "我们如何帮助你",
"HowMayWeHelpYou": "需要获得购买帮助?(提供中文服务)",
"SendMessage": "发送消息",
"Success": "成功",
"WeWillReplyYou": "你的消息已经发送! 我们会在短时间内给你答复.",

3
abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json

@ -102,6 +102,7 @@
"PostRequestMessageBody": "Here is the list of the requested posts by the Community. Do you want to write a requested post? Please click on the request and join the discussion.",
"Language": "Language",
"CreatePostLanguageInfo": "Language of the post",
"SeeMore": "See More"
"SeeMore": "See More",
"MemberNotPublishedPostYet": "This member hasn't published any posts yet."
}
}

21
abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json

@ -165,6 +165,25 @@
"SortBy": "Sort by",
"NoPublishedEventsYet": "No published events yet.",
"SubscribeYoutubeChannel": "Subscribe to the Youtube Channel",
"Enum:EventType:0": "Talks"
"Enum:EventType:0": "Talks",
"MemberNotPublishedPostYet": "This member hasn't published any posts yet.",
"TimeAgo": "{0} ago",
"Discord_Page_JoinCommunityMessage": "Join ABP Discord Community",
"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_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<span class=\"gradient-community\"> Community</span> Talks",
"Events_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_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",
"Layout_MetaDescription": "ABP Community is an environment where people can share posts about ABP framework and follows the projects.",
"Index_Page_CommunityIntroduction": "This is a hub for ABP Framework, .NET and software development. You can read the articles, watch the video tutorials, get informed about ABP’s development progress and ABP-related events, help other developers and share your expertise with the ABP community."
}
}

3
abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/tr.json

@ -142,6 +142,7 @@
"MinimumSearchContent": "En az 3 karakter girmelisiniz!",
"Volo.AbpIo.Domain:060001": "Kaynak URL (\"{PostUrl}\") Github URL'si değil",
"Volo.AbpIo.Domain:060002": "Makale İçeriği Github(\"{PostUrl}\") kaynağında mevcut değil.",
"Volo.AbpIo.Domain:060003": "Makale içeriği bulunamadı!"
"Volo.AbpIo.Domain:060003": "Makale içeriği bulunamadı!",
"MemberNotPublishedPostYet": "Bu üye henüz bir gönderi yayınlamadı."
}
}

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

@ -1,5 +1,6 @@
{
"culture": "en",
"texts": {
"FAQ": "FAQ"
}
}

1
abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/pt-BR.json

@ -1,5 +1,6 @@
{
"culture": "pt-BR",
"texts": {
"FAQ": "FAQ"
}
}

1
abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/ro-RO.json

@ -1,5 +1,6 @@
{
"culture": "ro-RO",
"texts": {
"FAQ": "FAQ"
}
}

1
abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/sl.json

@ -1,5 +1,6 @@
{
"culture": "sl",
"texts": {
"FAQ": "FAQ"
}
}

1
abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/tr.json

@ -1,5 +1,6 @@
{
"culture": "tr",
"texts": {
"FAQ": "SSS"
}
}

1
abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/zh-Hans.json

@ -1,5 +1,6 @@
{
"culture": "zh-Hans",
"texts": {
"FAQ": "常问问题"
}
}

1
abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/zh-Hant.json

@ -1,5 +1,6 @@
{
"culture": "zh-Hant",
"texts": {
"FAQ": "常问问题"
}
}

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

@ -174,6 +174,7 @@
"CreateProjectWizard": "This wizard creates a new project from the startup template which is properly configured to jump start your project.",
"TieredOption": "Creates a tiered solution where Web and Http API layers are physically separated. If not checked, creates a layered solution which is less complex and suitable for most scenarios.",
"SeparateIdentityServerOption": "Separates the server side into two applications: The first one is for the identity server and the second one is for your server side HTTP API.",
"ProgressiveWebApplicationOption": "Specifies the project as Progressive Web Application",
"UseslatestPreVersion": "Uses the latest pre-release version",
"ReadTheDocumentation": "Read The Documentation",
"Documentation": "Documentation",
@ -296,6 +297,7 @@
"EnterYouEmailToGetNews": "Enter your email to get the latest news about the ABP Framework",
"Tiered": "Tiered",
"SeparateIdentityServer": "Separate Identity Server",
"ProgressiveWebApplication": "Progressive Web Application",
"Preview": "Preview",
"CreateANewSolution": "Create a new solution",
"ABPFrameworkFeatures": "ABP Framework <span class=\"gradient-framework\">Features</span>",
@ -323,6 +325,53 @@
"CreateYourProjectNow": "Create Your Project Now",
"OrderOn": "Order on {0}",
"DownloadFreeDDDBook": "Download Free DDD Book",
"WhatIsABPFramework": "What is the ABP Framework?"
"WhatIsABPFramework": "What is the ABP Framework?",
"TenantDatabase": "Tenant {0} Database",
"SharedDatabase": "Shared Database",
"ConnectionResolver": "Connection Resolver",
"TenantBasedDataFilter": "Tenant Based Data Filter",
"ApplicationCode": "Application Code",
"TenantResolution": "Tenant Resolution",
"TenantUser": "Tenant {0} User",
"CardTitle": "Card title",
"View": "View",
"Model": "Model",
"Email": "Email",
"Password": "Password",
"Address": "Address",
"Gender": "Gender",
"Male": "Male",
"Female": "Female",
"Submit": "Submit",
"Unspecified": "Unspecified",
"StaticFileMiddleware": "Static File Middleware",
"RazorViewEngine": "Razor View Engine",
"PhysicalFiles": "Physical Files (wwwroot)",
"EmbeddedFiles": "Embedded Files (DLL)",
"DynamicFiles": "Dynamic Files (Memory)",
"BuildSolutionsWithAbp": "Build maintainable .NET solutions by following software development best practices using ABP.",
"BuyOnAmazon": "Buy on Amazon",
"BuyOnPackt": "Buy on Packt",
"Discounted": "Discounted",
"MasteringAbpFramework_Book_KeyFeatures": "Key Features",
"MasteringAbpFramework_Book_Key_Features_Description_1": "Build robust, maintainable, modular, and scalable software solutions using ABP Framework.",
"MasteringAbpFramework_Book_Key_Features_Description_2": "Learn how to implement SOLID principles and domain-driven design in your web applications.",
"MasteringAbpFramework_Book_Key_Features_Description_3": "Discover how ABP Framework speeds up your development cycle by automating repetitive tasks.",
"MasteringAbpFramework_Book_Description": "Book Description",
"MasteringAbpFramework_Book_Description_Details_1": "ABP Framework is a complete infrastructure for creating modern web applications by following software \n development best practices and conventions. With ABP's high-level framework and ecosystem, you can \n implement the Don't Repeat Yourself (DRY) principle and focus on your business code.",
"MasteringAbpFramework_Book_Description_Details_2": "Written by the creator of ABP Framework, this book will help you to gain a complete understanding of the\n framework and modern web application development techniques. With step-by-step explanations of essential\n concepts and practical examples, you'll understand the requirements of a modern web solution and how ABP\n Framework makes it enjoyable to develop your own solutions. You'll discover the common requirements of\n enterprise web application development and explore the infrastructure provided by ABP. Throughout the\n book, you'll get to grips with software development best practices for building maintainable and modular\n web solutions.",
"MasteringAbpFramework_Book_Description_Details_3": "By the end of this book, you'll be able to create a complete web solution that is easy to develop,\n maintain, and test.",
"MasteringAbpFramework_Book_WhatYouWillLearn": "What you will learn",
"MasteringAbpFramework_Book_What_You_Will_Learn_1": "Set up the development environment and get started with ABP Framework.",
"MasteringAbpFramework_Book_What_You_Will_Learn_2": "Work with Entity Framework Core and MongoDB to develop your data access layer.",
"MasteringAbpFramework_Book_What_You_Will_Learn_3": "Understand cross-cutting concerns and how ABP automates repetitive tasks.",
"MasteringAbpFramework_Book_What_You_Will_Learn_4": "Get to grips with implementing domain-driven design with ABP Framework.",
"MasteringAbpFramework_Book_What_You_Will_Learn_5": "Build UI pages and components with ASP.NET Core MVC (Razor Pages) and Blazor.",
"MasteringAbpFramework_Book_What_You_Will_Learn_6": "Work with multi-tenancy to create modular web applications.",
"MasteringAbpFramework_Book_What_You_Will_Learn_7": "Understand modularity and create reusable application modules.",
"MasteringAbpFramework_Book_What_You_Will_Learn_8": "Write unit, integration, and UI tests using ABP Framework.",
"MasteringAbpFramework_Book_WhoIsThisBookFor": "Who's this book for",
"MasteringAbpFramework_Book_WhoIsThisBookFor_Description": "This book is for web developers who want to learn software architectures and best practices for building\n maintainable web-based solutions using Microsoft technologies and ABP Framework. Basic knowledge of C#\n and ASP.NET Core is necessary to get started with this book.",
"ComputersAndTechnology": "Computers & Technology"
}
}

2
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json

@ -174,6 +174,8 @@
"CreateProjectWizard": "Bu sihirbaz, projenize atlamak için uygun şekilde yapılandırılmış başlangıç şablonundan yeni bir proje oluşturur.",
"TieredOption": "Web ve Http API katmanlarının fiziksel olarak ayrıldığı katmanlı bir çözüm oluşturur. İşaretlenmezse, daha az karmaşık olan ve çoğu senaryo için uygun olan katmanlı bir çözüm oluşturur.",
"SeparateIdentityServerOption": "Sunucu tarafını iki uygulamaya ayırır: Birincisi kimlik sunucusu için, ikincisi ise sunucu tarafı HTTP API'niz içindir.",
"ProgressiveWebApplicationOption": "Projeyi Progresif Web Uygulaması olarak ayarlayın.",
"ProgressiveWebApplication": "Progresif Web Uygulaması",
"UseslatestPreVersion": "En son yayın öncesi sürümünü kullanır",
"ReadTheDocumentation": "<span class=\"text-primary\">Belgeleri okuyun</span><span class=\"text-success\"></span>",
"Documentation": "belgeler",

1
build/common.ps1

@ -14,6 +14,7 @@ $solutionPaths = @(
"../modules/feature-management",
"../modules/identity",
"../modules/identityserver",
"../modules/openiddict",
"../modules/tenant-management",
"../modules/audit-logging",
"../modules/background-jobs",

4
common.props

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>5.3.0</Version>
<Version>6.0.0</Version>
<NoWarn>$(NoWarn);CS1591;CS0436</NoWarn>
<PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>https://abp.io/</PackageProjectUrl>
@ -13,7 +13,7 @@
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.0-beta-20204-02">
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

2
configureawait.props

@ -1,7 +1,7 @@
<Project>
<ItemGroup>
<PackageReference Include="ConfigureAwait.Fody" Version="3.3.1" PrivateAssets="All" />
<PackageReference Include="Fody" Version="6.5.3">
<PackageReference Include="Fody" Version="6.6.1">
<PrivateAssets>All</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>

4
docs/cs/CLI.md

@ -45,9 +45,9 @@ abp new Acme.BookStore
* `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-identity-server`: Oddělí identity server aplikaci od API host aplikace. Pokud není uvedeno, bude na straně serveru jediný koncový bod.
* `--separate-auth-server`: Oddělí identity 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-identity-server`: Oddělí identity server aplikaci od API host aplikace. Pokud není uvedeno, bude na straně serveru jediný koncový bod.
* `--separate-auth-server`: Oddělí identity 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.

2
docs/en/API/Swagger-Integration.md

@ -101,7 +101,7 @@ services.AddAbpSwaggerGen(
For non MVC/Tiered applications, we need to configure Swagger with OAUTH to handle authorization.
> ABP Framework uses IdentityServer by default. To get more information about IDS, check this [documentation](../Modules/IdentityServer.md).
> ABP Framework uses OpenIddict by default. To get more information about OpenIddict, check this [documentation](../Modules/OpenIddict.md).

4
docs/en/Background-Jobs.md

@ -195,14 +195,14 @@ Background Jobs module implements `IBackgroundJobStore` using various data acces
### Clustered Deployment
The default background job manager is compatible with [clustered environments](Deployment/Clustered-Environment.md) (where multiple instances of your application run concurrently). It uses a [distributed lock](Distributed-Locking.md) to ensure that the jobs are executed only in a single application instance in a time.
The default background job manager is compatible with [clustered environments](Deployment/Clustered-Environment.md) (where multiple instances of your application run concurrently). It uses a [distributed lock](Distributed-Locking.md) to ensure that the jobs are executed only in a single application instance at a time.
However, the distributed lock system works in-process by default. That means it is not distributed actually, unless you configure a distributed lock provider. So, **please follow the [distributed lock](Distributed-Locking.md) document to configure a provider for your application**, if it is not already configured.
If you don't want to use a distributed lock provider, you may go with the following options:
* Stop the background job manager (set `AbpBackgroundJobOptions.IsJobExecutionEnabled` to `false` as explained in the *Disable Job Execution* section) in all application instances except one of them, so only the single instance executes the jobs (while other application instances can still queue jobs).
* Stop the background job manager (set `AbpBackgroundJobOptions.IsJobExecutionEnabled` to `false` as explained in the *Disable Job Execution* section) in all application instances and create a dedicated application (maybe a console application running in its own container or a Windows Service running in background) to execute all the background jobs. This can be a good option if your background jobs consume high system resource (CPU, RAM or Disk), so you can deploy that background application to a dedicated server and your background jobs doesn't affect your application's performance.
* Stop the background job manager (set `AbpBackgroundJobOptions.IsJobExecutionEnabled` to `false` as explained in the *Disable Job Execution* section) in all application instances and create a dedicated application (maybe a console application running in its own container or a Windows Service running in the background) to execute all the background jobs. This can be a good option if your background jobs consume high system resources (CPU, RAM or Disk), so you can deploy that background application to a dedicated server and your background jobs don't affect your application's performance.
## Integrations

14
docs/en/Background-Workers-Hangfire.md

@ -95,29 +95,29 @@ public class MyLogWorker : HangfireBackgroundWorkerBase, IMyLogWorker
## Register BackgroundWorkerManager
After creating a background worker class, you should add it to the `IBackgroundWorkerManager`. The most common place is the `OnApplicationInitialization` method of your module class:
After creating a background worker class, you should add it to the `IBackgroundWorkerManager`. The most common place is the `OnApplicationInitializationAsync` method of your module class:
```` csharp
[DependsOn(typeof(AbpBackgroundWorkersModule))]
public class MyModule : AbpModule
{
public override void OnApplicationInitialization(
public override async Task OnApplicationInitializationAsync(
ApplicationInitializationContext context)
{
context.AddBackgroundWorker<MyLogWorker>();
await context.AddBackgroundWorkerAsync<MyLogWorker>();
//If the interface is defined
//context.AddBackgroundWorker<IMyLogWorker>();
//await context.AddBackgroundWorkerAsync<IMyLogWorker>();
}
}
````
`context.AddBackgroundWorker(...)` is a shortcut extension method for the expression below:
`context.AddBackgroundWorkerAsync(...)` is a shortcut extension method for the expression below:
```` csharp
context.ServiceProvider
.GetRequiredService<IBackgroundWorkerManager>()
.Add(
.AddAsync(
context
.ServiceProvider
.GetRequiredService<MyLogWorker>()
@ -126,4 +126,4 @@ context.ServiceProvider
So, it resolves the given background worker and adds to the `IBackgroundWorkerManager`.
While we generally add workers in OnApplicationInitialization, there are no restrictions on that. You can inject IBackgroundWorkerManager anywhere and add workers at runtime. Background worker manager will stop and release all the registered workers when your application is being shut down.
While we generally add workers in `OnApplicationInitializationAsync`, there are no restrictions on that. You can inject `IBackgroundWorkerManager` anywhere and add workers at runtime. Background worker manager will stop and release all the registered workers when your application is being shut down.

14
docs/en/Background-Workers.md

@ -80,16 +80,16 @@ public class PassiveUserCheckerWorker : AsyncPeriodicBackgroundWorkerBase
## Register Background Worker
After creating a background worker class, you should add it to the `IBackgroundWorkerManager`. The most common place is the `OnApplicationInitialization` method of your module class:
After creating a background worker class, you should add it to the `IBackgroundWorkerManager`. The most common place is the `OnApplicationInitializationAsync` method of your module class:
````csharp
[DependsOn(typeof(AbpBackgroundWorkersModule))]
public class MyModule : AbpModule
{
public override Task OnApplicationInitializationAsync(
public override async Task OnApplicationInitializationAsync(
ApplicationInitializationContext context)
{
context.AddBackgroundWorkerAsync<PassiveUserCheckerWorker>();
await context.AddBackgroundWorkerAsync<PassiveUserCheckerWorker>();
}
}
````
@ -108,7 +108,7 @@ await context.ServiceProvider
So, it resolves the given background worker and adds to the `IBackgroundWorkerManager`.
While we generally add workers in `OnApplicationInitialization`, there are no restrictions on that. You can inject `IBackgroundWorkerManager` anywhere and add workers at runtime. Background worker manager will stop and release all the registered workers when your application is being shut down.
While we generally add workers in `OnApplicationInitializationAsync`, there are no restrictions on that. You can inject `IBackgroundWorkerManager` anywhere and add workers at runtime. Background worker manager will stop and release all the registered workers when your application is being shut down.
## Options
@ -128,9 +128,9 @@ Be careful if you run multiple instances of your application simultaneously in a
If that's a problem for your workers, you have the following options:
* Implement your background workers so that they works in a clustered environment without any problem. Using the [distributed lock](../Distributed-Locking.md) to ensure concurrency control is a way of doing that. A background worker in an application instance may handle a distributed lock, so the workers in other application instances will wait the lock. In this way, only one worker does the actual work, while others wait in idle. If you implement this, your workers run safely without caring how the application is deployed.
* Stop background workers (set `AbpBackgroundWorkerOptions.IsEnabled` to `false`) in all application instances except one of them, so only the single instance runs the workers.
* Stop background workers (set `AbpBackgroundWorkerOptions.IsEnabled` to `false`) in all application instances and create a dedicated application (maybe a console application running in its own container or a Windows Service running in background) to execute all the background tasks. This can be a good option if your background workers consume high system resource (CPU, RAM or Disk), so you can deploy that background application to a dedicated server and your background tasks doesn't affect your application's performance.
* Implement your background workers so that they work in a clustered environment without any problem. Using the [distributed lock](../Distributed-Locking.md) to ensure concurrency control is a way of doing that. A background worker in an application instance may handle a distributed lock, so the workers in other application instances will wait for the lock. In this way, only one worker does the actual work, while others wait in idle. If you implement this, your workers run safely without caring about how the application is deployed.
* Stop the background workers (set `AbpBackgroundWorkerOptions.IsEnabled` to `false`) in all application instances except one of them, so only the single instance runs the workers.
* Stop the background workers (set `AbpBackgroundWorkerOptions.IsEnabled` to `false`) in all application instances and create a dedicated application (maybe a console application running in its own container or a Windows Service running in the background) to execute all the background tasks. This can be a good option if your background workers consume high system resources (CPU, RAM or Disk), so you can deploy that background application to a dedicated server and your background tasks don't affect your application's performance.
## Integrations

258
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/POST.md

@ -0,0 +1,258 @@
# ABP.IO Platform 5.3 RC Has Been Released
Today, we are happy to release the [ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) version **5.3 RC** (Release Candidate). This blog post introduces the new features and important changes in this new version.
> **The planned release date for the [5.3.0 Stable](https://github.com/abpframework/abp/milestone/69) version is May 31, 2022**.
Please try this version and provide feedback for a more stable ABP version 5.3! Thank you all.
## Get Started with the 5.3 RC
Follow the steps below to try version 5.3.0 RC today:
1) **Upgrade** the ABP CLI to version `5.3.0-rc.1` using a command line terminal:
````bash
dotnet tool update Volo.Abp.Cli -g --version 5.3.0-rc.1
````
**or install** it if you haven't before:
````bash
dotnet tool install Volo.Abp.Cli -g --version 5.3.0-rc.1
````
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 *Direct Download* tab on the [Get Started](https://abp.io/get-started) page by selecting the **Preview checkbox**.
You can use any IDE that supports .NET 6.x, like **[Visual Studio 2022](https://visualstudio.microsoft.com/downloads/)**.
## Migration Notes
There is a change in this version that may effect your applications:
* Upgraded the [AutoMapper](https://github.com/AutoMapper/AutoMapper) library to **v11.0.1**. So, you need to change your project's target SDK that use the **AutoMapper** library (typically your `*.Application` project). You can change it from `netstandard2.0` to `netstandard2.1` or `net6` if needed. You can write to [#12189](https://github.com/abpframework/abp/pull/12189) if you need any help.
## What's New with ABP Framework 5.3?
In this section, I will introduce some major features released with this version. Here is a brief list of titles explained in the next sections:
* Single-layer option added to the [*Get Started*](https://abp.io/get-started) page
* PWA Support for Startup Templates
* Introduced the `Volo.Abp.Gdpr.Abstractions` package
* Batch Publish Events from Outbox to the Event Bus
* Improvements on **eShopOnAbp** Project & E-Book Announcement
* LeptonX Lite Documentations & Project Status & Roadmap
* OpenIddict Module & Keycloack Integration
* Deployment Documentations
* Other News
### Single-layer Option on *Get Started* Page
We've created a new startup template named `app-nolayers` and [announced](https://blog.abp.io/abp/ABP.IO-Platform-5-2-RC-Has-Been-Published) it in the previous version. In this version, we've also added this startup template option to the *Get Started* page.
*You can examine the screenshot below to see how to create an `app-nolayers` template from the ["Get Started"](https://abp.io/get-started) page:*
![](./app-nolayers-get-started.png)
### PWA Support for Startup Templates
ABP v5.3 application startup template now supports PWA for Blazor WASM & Angular UIs. To create a startup template with the PWA support, you can use the `--pwa` parameter.
Example:
```bash
abp new MyProgressiveWebApp -t app -u blazor --pwa
```
### Introducing the `Volo.Abp.Gdpr.Abstractions` Package
A new `Volo.Abp.Gdpr.Abstractions` package has been added to the framework. This is an abstraction package, so doesn't contain any actual GDPR implementation. It defines some classes and interfaces to put a standard for who want to implement a GDPR module that can run in a modular or microservice system.
At that point, we are introducing the **GDPR Module** for the ABP Commercial customers and this module does the GDPR-related operations on behalf of you, such as *"Download/Delete Personal Data"*. I'll describe the **GDPR Module** later in this blog post.
> Please see the **GDPR Module** section below to learn more about this module.
### Batch Publish Events from Outbox to the Event Bus
We introduced the "Transactional Outbox & Inbox Patterns" in [**ABP v5.0**](https://blog.abp.io/abp/ABP-IO-Platform-5.0-RC-1-Has-Been-Released), it was one of the most awaited features by several software developers.
We've made some optimizations for the **Batch Event Publishing** in this version, you can examine the related development from [here](https://github.com/abpframework/abp/pull/11243). After the optimization, the results are impressive. It is enabled by default (if you have configured [event outbox](https://docs.abp.io/en/abp/latest/Distributed-Event-Bus#outbox-inbox-for-transactional-events)), so you don't need to any manual configuration.
### Improvements on eShopOnAbp Project & E-Book Announcement
There are some developments on the [eShopOnAbp project](https://github.com/abpframework/eShopOnAbp) made in this version. You can see the brief descriptions of some of the improvements below:
* Local certificates have been created to use while working in Kubernetes and also Helm Charts have been updated. See [#107](https://github.com/abpframework/eShopOnAbp/pull/107).
* The Order Management page has been created. See [#92](https://github.com/abpframework/eShopOnAbp/pull/92).
* Database migration event handlers have been removed and "Distributed Locking" is now used for database migrations. See [#85](https://github.com/abpframework/eShopOnAbp/pull/85) and [#102](https://github.com/abpframework/eShopOnAbp/pull/102).
* Switched from Ocelot to YARP as the gateway. See [#97](https://github.com/abpframework/eShopOnAbp/pull/97).
We have exciting news to share with the community, we're working on an "ABP Microservice Development" e-book. In this book, we're using the eShopOnAbp project as a reference microservice solution and we're trying to explain our experiences during the microservice application development process through this project.
We're planning to create this book in nine chapters and make it available after the third chapter is written. After that, you will be able to download this free e-book from the [abp.io](https://abp.io/) website.
### LeptonX Lite Documentations & Project Status & Roadmap
It is finally here, we've released the **1.0.0-beta.1** version for the **LeptonX Lite**.
![](./leptonx-lite-documentations.png)
Lepton X Lite documents have been written for the three UI types within this version. You can see the related documentation from the screenshot above. You can follow these documents and try the new **LeptonX Lite Theme**.
We don't suggest using the **beta.1** version on production, we highly demand you to test **LeptonX Lite** and provide feedback to us. It's really important for us to be able to release a more stable version. Thanks in advance.
For the following versions (beta.2 and RC versions), we will focus on:
* Fixing the reported bugs from the community
* Providing documentations as much as possible
* Adding new custom pages to the demo
### OpenIddict Module & Keycloack Integration
We have [announced the plan of replacing the IdentityServer](https://github.com/abpframework/abp/issues/11989). ABP currently uses **IdentityServer4** to add **OAuth** features as built-in on the server-side. However, since *IdentityServer4's support ends at the end of the year 2022*. Its replacement is Duende IdentityServer, which is not a free software anymore. (see [more](https://blog.duendesoftware.com/posts/20220111_fair_trade/))
Therefore, we've decided to completely drop the **IdentityServer4** from the ABP platform and implement the [OpenIddict](https://github.com/openiddict/openiddict-core) and install onto the startup templates.
We've implemented both open source and commercial OpenIddict modules, we plan to remove Identity Server and replace it with OpenIddict for template projects in **ABP v5.4**. Please check [#12084](https://github.com/abpframework/abp/pull/12084) to see the development made on the open-source side.
We're creating the documentation for the OpenIddict Module, if you want to have general knowledge about this module, you can check the documentation from [here](https://github.com/abpframework/abp/blob/dev/docs/en/Modules/OpenIddict.md). Currently, this is a draft documentation but it gives overall knowledge about the OpenIddict Module, we'll complete this documentation in ABP v5.4 and you'll be able to read it completely.
Currently, we are also working on Keycloak integration possibilities in parallel to the OpenIddict integration research and we've prepared some samples that you can examine. You can see [#154](https://github.com/abpframework/abp-samples/pull/154) and [#158](https://github.com/abpframework/abp-samples/pull/158).
### Deployment Documentations
Deploying an ABP-based application is not so different than deploying any .NET or ASP.NET Core application. You can deploy it to a cloud provider (e.g. Azure, AWS, Google Could) or on-premise server, IIS or any other web server. However, we wanted to prepare a "Deployment Guide" to mention the important points and considerations.
![](./deployment-documentation.png)
In the [Deploying to a Clustered Environment](https://docs.abp.io/en/abp/5.3/Deployment/Clustered-Environment) documentation, we've documented the topics that you should consider when you are developing your application to a clustered environment and explained how you can deal with these topics in your ABP-based application.
### Other News
* Global Features were only accessible from the C# code. From this version and on, Global Features can be also provided from application configurations. See [#12043](https://github.com/abpframework/abp/pull/12043).
* Getting the user's detailed information (name, surname and phone number) from external login. See [#12085](https://github.com/abpframework/abp/pull/12085).
* Date Pipes for Angular. See [#11909](https://github.com/abpframework/abp/issues/11909).
If you want to see more details, you can check [the release on GitHub](https://github.com/abpframework/abp/releases/tag/5.3.0-rc.1), which contains a list of all the issues and pull requests closed with this version.
## What's New with ABP Commercial 5.3?
### GDPR Module
> **GDPR (General Data Protection Regulation)** is a regulation in EU law on data protection and known as the toughest privacy and security law in the world. GDPR applies to any organization operating within the EU, as well as any organizations outside of the EU which offer goods or services to customers or businesses in the EU.
With this version, we are introducing the new **GDPR Module**. This was one of the most awaited features, so we've prioritized it and implemented it in this version.
The GDPR Module is pre-installed in the [startup templates](https://docs.abp.io/en/commercial/5.3/startup-templates/index) for MVC. So, no need to manually install it. When you create a new startup template, you can directly use this module. We'll also implement this module for the other UI types as soon as possible and also add extra functionality such as "Cookie Consent" and more.
Currently, there are two main functions of this module and they are "Download Personal Data" and "Delete Personal Data".
![](./gdpr-user-menu.png)
There is a "Personal Data" section in the user menu as in the screenshot above and when you click on this section, you'll be redirected to the "Personal Data" page. On that page, you can either request to "Download Personal Data" or "Delete Personal Data".
![](./gdpr-personal-data-page.png)
After you've requested to download "Personal Data", you need to wait for 1 hour by default (you can configure the related option). Because the GDPR module is developed by considering the distributed systems and therefore a specific time should be passed to ensure all the published events are handled and all personal data is collected.
### CMS Kit Pro - Polling Feature
We've added a **Polling** feature to the **CMS Kit Pro** module. This feature allows you to use a questionnaire/voting system in your application easily. You can create a question, define some options for it and the poll will be created for you. You can see the example poll in the screenshot below:
![](./poll-question-example.png)
Also, there is an admin side of the Polling Feature. You can easily manage your polls in your admin (back-office) project. You can create, update, delete and show the results of the poll on the Polls page:
![](./poll-questions.png)
### OAuth Resource Owner Password as External Login Provider
> The Resource Owner Password flow allows for the exchanging of the username and password of a user for an access token. When using the resource owner password credentials grant, the user provides the credentials (username and password) directly to the application.
Now, you can login by entering a username and password from an OAuth server.
Example: Use OAuth external login provider with Keycloak:
![](./oauth-external-provider.gif)
### Suite New Features & Enhancements
In this version, there are some enhancements and new features in **Suite** and they are listed briefly below:
* It's now possible to create an **app-nolayers (Application - single layer)** template via Suite and also code-generation is supported for the **app-nolayers** template with this version.
* Suite now allows users to see and download its logs.
* Suite now allows generating code via CLI. If you have a JSON file that contains code blocks, like entity configurations, you can use the `abp suite generate` command to generate CRUD pages based on it.
Example:
```bash
abp suite generate -e C:\Users\.suite\entities\Country.json -s C:\Users\my-proj\SuiteProj\SuiteProj.sln
```
### Suite Webinar: Take a closer look at the code generation
![](./webinar.png)
We've organized a webinar for Suite and in this webinar, we've talked about ABP Suite's capabilities, important features and more...
You can watch the event from [here](https://www.youtube.com/watch?v=RFArBh60RSA&t=3s), if you haven't watched it yet.
### Docker Compose Configurations for Single Layer Startup Template
Dockerfiles, docker-compose files and build script files have been added to the Single Layer Startup Template (app-nolayers) with this version.
And this way, applications created with this template now can be deployed more easily.
### Microservice Solution Enhancements
There are some enhancements made in the Microservice Solution. You can see the list of these enhancements:
* Initial migration on the template has been updated with the small improvement that was made in the **Language Management** module.
* Database migration event handlers have been removed and "Distributed Locking" is now used for the database migrations.
### PWA Support for the Application Pro Template
Application Pro template also supports the PWA for Blazor WASM & Angular UIS. To create a startup template with the PWA support, you can use the `--pwa` parameter.
Example:
```bash
abp new MyProgressiveWebApp -t app-pro -u blazor --pwa
```
## Community News
### New ABP Community Posts
* [Anto Subash](https://twitter.com/antosubash) created a series named ["Microservice with ABP"](https://blog.antosubash.com/posts/abp-microservice-series) and shared a couple of video posts about the ABP Microservice solution.
* [Francisco Kadzi](https://github.com/CiscoNinja) has created his first ABP Community article that shows how to ["Customize ABP Angular Application UI with AdminLTE"](https://community.abp.io/posts/customize-abp-angular-application-ui-with-adminlte.-7qu1m67s).
* [Jack Fistelmann](https://github.com/nebula2) has created an article to introduce a helpful project extension to speed up development on Visual Studio. You can read the article [here](https://community.abp.io/posts/using-switch-startup-project-extension-for-visual-studio-52yyw27v).
* [Jack Fistelmann](https://github.com/nebula2) has also created an article to show how you can generate PDF files with the `Sycyber.Core` package in ABP-based applications. You can read it [here](https://community.abp.io/posts/generate-pdfs-in-an-abp-framework-project-using-scryber.core-x9yh1vfa).
* [Halil Ibrahim Kalkan](https://twitter.com/hibrahimkalkan) has created an article to show ["Dealing with Multiple Implementations of a Service in ASP.NET Core & ABP Dependency Injection"](https://community.abp.io/posts/dealing-with-multiple-implementations-of-a-service-in-asp.net-core-abp-dependency-injection-ysfp4ho2) with examples.
* [Manoj Kumar](https://community.abp.io/members/manojkumar.t@shloklabs.com) submitted a new article about how to use "ABP authentication in a Flutter application". It was a frequently asked topic, which you can read [here](https://community.abp.io/posts/flutter-web-authentication-from-abp-mp6l2ehx).
* [Engincan Veske](https://twitter.com/EngincanVeske) created a new Community Article to show "Concurrency Check/Control in ABP". You can read it [here](https://community.abp.io/posts/handle-concurrency-with-ef-core-in-an-abp-framework-project-with-asp.net-core-mvc-jlkc3w8f).
### ABP Community Talks 2022.4: How can you contribute to the open source ABP Framework? (May 10, 2022 - 17:00 UTC)
![](./community-talks-2022.4.png)
We've [asked you to pick the topic of the next Community Talks](https://twitter.com/abpframework/status/1514567683072745474?s=20&t=rJfHrB3DYDNsk2EXS8zBBQ) and you've chosen the "How to contribute to open source ABP Framework?" for the next talk topic. So, in this Community Talk, we will be talking about "How to contribute to ABP Framework" with one of the top contributors of the ABP Framework, [Ismail Yılmaz](https://github.com/iyilm4z). The event will be on **May 10, 2022, at 17:00 (UTC)** on YouTube.
> You can register for the event from [here](https://kommunity.com/volosoft/events/abp-community-talks-20224-how-to-contribute-to-the-open-source-abp-framework-d9b50664), if you haven't registered yet.
You can also [subscribe to the Volosoft channel](https://www.youtube.com/channel/UCO3XKlpvq8CA5MQNVS6b3dQ) to be informed about future ABP events and videos.
### Discord Server
We've created an official ABP Discord server so the ABP Community can interact with each other and created a blog-post to introduce it. You can read the [ABP Discord Server announcement post](https://blog.abp.io/abp/Official-ABP-Discord-Server-is-Here) to learn more about the ABP Discord Server.
Thanks to the ABP Community, **700+** people joined our Discord Server so far and it grows every day.
You can join our Discord Server from [here](https://discord.gg/abp), if you haven't yet.

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/app-nolayers-get-started.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/community-talks-2022.4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/cover-53.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/deployment-documentation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/gdpr-personal-data-page.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/gdpr-user-menu.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/leptonx-lite-documentations.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/oauth-external-provider.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/poll-new-question.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/poll-question-example.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/poll-questions.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/webinar.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

8
docs/en/CLI-New-Command-Samples.md

@ -15,7 +15,7 @@ The following commands are for creating Angular UI projects:
* **Entity Framework Core**, default app template, **separate Identity Server**, creates the project in a new folder:
```bash
abp new Acme.BookStore -t app -u angular -m none --separate-identity-server --database-provider ef -csf
abp new Acme.BookStore -t app -u angular -m none --separate-auth-server --database-provider ef -csf
```
* **Entity Framework Core**, **custom connection string**, creates the project in a new folder:
@ -33,7 +33,7 @@ The following commands are for creating Angular UI projects:
* **MongoDB**, default app template, no mobile app, **separate Identity Server**, creates the project in a new folder:
```bash
abp new Acme.BookStore -t app -u angular -m none --separate-identity-server --database-provider mongodb -csf
abp new Acme.BookStore -t app -u angular -m none --separate-auth-server --database-provider mongodb -csf
```
## MVC
@ -78,7 +78,7 @@ The following commands are for creating Blazor projects:
* **Entity Framework Core**, **separate Identity Server**, mobile app included:
```bash
abp new Acme.BookStore -u blazor --separate-identity-server
abp new Acme.BookStore -u blazor --separate-auth-server
```
* **MongoDB**, no mobile app, creates the project in a new folder:
@ -116,7 +116,7 @@ In the default app template, there is always a frontend project. In this option
* **Entity Framework Core**, separate Identity Server, creates the project in a new folder:
```bash
abp new Acme.BookStore -u none --separate-identity-server -csf
abp new Acme.BookStore -u none --separate-auth-server -csf
```
* **MongoDB**, no mobile app:

41
docs/en/CLI.md

@ -41,6 +41,7 @@ Here, is the list of all available commands before explaining their details:
* **`switch-to-stable`**: Switches to the latest stable versions of the ABP related packages on a solution.
* **`translate`**: Simplifies to translate localization files when you have multiple JSON [localization](Localization.md) files in a source control repository.
* **`login`**: Authenticates on your computer with your [abp.io](https://abp.io/) username and password.
* **`login-info`**: Shows the current user's login information.
* **`logout`**: Logouts from your computer if you've authenticated before.
* **`bundle`**: Generates script and style references for an ABP Blazor project.
* **`install-libs`**: Install NPM Packages for MVC / Razor Pages and Blazor Server UI types.
@ -91,13 +92,15 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample
* `mvc`: ASP.NET Core MVC. There are some additional options for this template:
* `--tiered`: Creates a tiered solution where Web and Http API layers are physically separated. If not specified, it creates a layered solution which is less complex and suitable for most scenarios.
* `angular`: Angular UI. There are some additional options for this template:
* `--separate-identity-server`: The Identity Server project comes as a separate project and runs at a different endpoint. It separates the Identity Server from the API Host application. If not specified, you will have a single endpoint in the server side.
* `--separate-auth-server`: The Identity Server project comes as a separate project and runs at a different endpoint. It separates the Identity Server from the API Host application. If not specified, you will have a single endpoint in the server side.
* `--pwa`: Specifies the project as Progressive Web Application.
* `blazor`: Blazor UI. There are some additional options for this template:
* `--separate-identity-server`The Identity Server project comes as a separate project and runs at a different endpoint. It separates the Identity Server from the API Host application. If not specified, you will have a single endpoint in the server side.
* `--separate-auth-server`The Identity Server project comes as a separate project and runs at a different endpoint. It separates the Identity Server from the API Host application. If not specified, you will have a single endpoint in the server side.
* `--pwa`: Specifies the project as Progressive Web Application.
* `blazor-server`: Blazor Server UI. There are some additional options for this template:
* `--tiered`: The Identity Server and the API Host project comes as separate projects and run at different endpoints. It has 3 startup projects: *HttpApi.Host*, *IdentityServer* and *Blazor* and and each runs on different endpoints. If not specified, you will have a single endpoint for your web project.
* `--tiered`: The Identity Server and the API Host project comes as separate projects and run at different endpoints. It has 3 startup projects: *HttpApi.Host*, *AuthServer* and *Blazor* and and each runs on different endpoints. If not specified, you will have a single endpoint for your web project.
* `none`: Without UI. No front-end layer will be created. There are some additional options for this template:
* `--separate-identity-server`: The Identity Server project comes as a separate project and runs at a different endpoint. It separates the Identity Server from the API Host application. If not specified, you will have a single endpoint in the server side.
* `--separate-auth-server`: The Identity Server project comes as a separate project and runs at a different endpoint. It separates the Identity Server from the API Host application. If not specified, you will have a single endpoint in the server side.
* `--mobile` or `-m`: Specifies the mobile application framework. If not specified, no mobile application will be created. Available options:
* `react-native`: React Native.
* `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers:
@ -106,7 +109,7 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample
* **`module`**: [Module template](Startup-Templates/Module.md). Additional options:
* `--no-ui`: Specifies to not include the UI. This makes possible to create service-only modules (a.k.a. microservices - without UI).
* **`console`**: [Console template](Startup-Templates/Console.md).
* **`app-nolayers`**: Application single layer template.
* **`app-nolayers`**: [Single-layer application template](Startup-Templates/Application-Single-Layer.md). Additional options:
* `--ui` or `-u`: Specifies the UI framework. Default framework is `mvc`. Available frameworks:
* `mvc`: ASP.NET Core MVC.
* `angular`: Angular UI.
@ -115,7 +118,6 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample
* `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers:
* `ef`: Entity Framework Core.
* `mongodb`: MongoDB.
* `--pwa`: Specifies to Configure Angular or Blazor WebAssembly project as Progressive Web Application.
* `--output-folder` or `-o`: Specifies the output folder. Default value is the current directory.
* `--version` or `-v`: Specifies the ABP & template version. It can be a [release tag](https://github.com/abpframework/abp/releases) or a [branch name](https://github.com/abpframework/abp/branches). Uses the latest release if not specified. Most of the times, you will want to use the latest version.
* `--preview`: Use latest preview version.
@ -136,7 +138,7 @@ See some [examples for the new command](CLI-New-Command-Samples.md) here.
### update
Updating all ABP related packages can be tedious since there are many packages of the framework and modules. This command automatically updates all ABP related NuGet and NPM packages in a solution or project to the latest versions.
Updating all ABP related packages can be tedious since there are many packages of the framework and modules. This command automatically updates all ABP related NuGet and NPM packages in a solution or project to the latest versions. You can run it in the root folder of your solutions.
Usage:
@ -144,8 +146,11 @@ Usage:
abp update [options]
````
* If you run in a directory with a .sln file, it updates all ABP related packages of the all projects of the solution to the latest versions.
* If you run in a directory with a .csproj file, it updates all ABP related packages of the project to the latest versions.
* If you run in a directory with a .sln file, it updates all ABP related packages of the all projects of the solution to the latest versions.
* If you run in a directory that contains multiple solutions in sub-folders, it can update all the solutions, including Angular projects.
Note that this command can upgrade your solution from a previous version, and also can upgrade it from a preview release to the stable release of the same version.
#### Options
@ -466,23 +471,21 @@ abp login <username> -p <password> -o <organization> # You can enter both your
A new login with an already active session overwrites the previous session.
### logout
### login-info
Logs you out by removing the session token from your computer.
Shows your login information such as **Name**, **Surname**, **Username**, **Email Address** and **Organization**.
```
abp logout
```bash
abp login-info
```
#### Options
* ```--working-directory``` or ```-wd```: Specifies the working directory. This option is useful when the command is executed outside of a GIT repository or when executing directory doesn't contain a .NET solution file.
* ```--build-name``` or ```-n```: Specifies a name for the build. This option is useful when same repository is used for more than one different builds.
* ```--dotnet-build-arguments``` or ```-a```: Arguments to pass ```dotnet build``` when building project files. This parameter must be passed like ```"\"{params}\""``` .
* ```--force``` or ```-f```: Forces to build projects even they are not changed from the last successful build.
### logout
For more details, see [build command documentation](CLI-BuildCommand.md).
Logs you out by removing the session token from your computer.
```bash
abp logout
```
### bundle

2
docs/en/Caching.md

@ -2,7 +2,7 @@
ABP Framework extends the [ASP.NET Core distributed cache](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed).
> **Default implementation of the `IDistributedCache` interface is the `MemoryDistributedCache` which works in-memory.** See [ASP.NET Core's documentation](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) to see how to switch to Redis or another cache provider. Also, see the [Redis Cache](Redis-Cache.md) document if you want to use the Redis as the distributed cache server.
> **Default implementation of the `IDistributedCache` interface is` MemoryDistributedCache` which works in-memory.** See [ASP.NET Core's documentation](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) to see how to switch to Redis or another cache provider. Also, see the [Redis Cache](Redis-Cache.md) document if you want to use Redis as the distributed cache server.
## Installation

243
docs/en/Community-Articles/2022-05-16-Consuming-Rest-Api-By-Using-Static-Proxy/POST.md

@ -0,0 +1,243 @@
# Consuming HTTP APIs from a .NET Client Using ABP's Client Proxy System
In this article, I will explain how to consume HTTP APIs from a .NET application using ABP's [dynamic](https://docs.abp.io/en/abp/latest/API/Dynamic-CSharp-API-Clients) and [static](https://docs.abp.io/en/abp/latest/API/Static-CSharp-API-Clients) client-side proxy systems. I will start by creating a new project and consume the HTTP APIs from a .NET console application using dynamic client proxies. Then I will switch to static client proxies. Finally, I will glance at the differences and similarities between static and dynamic generic proxies.
Here the main benefits of using the client-side proxy system (either dynamic or static):
* Automatically maps C# method calls to remote server HTTP calls by considering the HTTP method, route, query string parameters, request payload and other details.
* Authenticates the HTTP Client by adding an access token to the HTTP header.
* Serializes to and deserialize from JSON.
* Handles HTTP API versioning.
* Adds correlation id, current tenant id and the current culture to the request.
* Properly handles the error messages sent by the server and throws proper exceptions.
## Create a new ABP application with the ABP CLI
Firstly create a new solution via [ABP CLI](https://docs.abp.io/en/abp/latest/CLI):
```shell
abp new Acme.BookStore
```
> See ABP's [Getting Started document](https://docs.abp.io/en/abp/latest/Getting-Started-Setup-Environment?UI=MVC&DB=EF&Tiered=No) to learn how to create and run your application, if you haven't done it before.
## Create the application service interface
I will start by creating an application service and exposing it as an HTTP API to be consumed by remote clients. First, define an interface for the application service; Create an `IBookAppService` interface in the `Books` folder (namespace) of the `Acme.BookStore.Application.Contracts` project:
````csharp
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore.Books
{
public interface IBookAppService : IApplicationService
{
Task<PagedResultDto<BookDto>> GetListAsync();
}
}
````
Also add a `BookDto` class inside the same `Books` folder:
```csharp
using System;
using Volo.Abp.Application.Dtos;
namespace Acme.BookStore.Books
{
public class BookDto
{
public string Name { get; set; }
public string AuthorName { get; set; }
public float Price { get; set; }
}
}
```
## Implement the application service
It is time to implement the `IBookAppService` interface. Create a new class named `BookAppService` in the `Books` namespace (folder) of the `Acme.BookStore.Application` project:
```csharp
using Acme.BookStore.Permissions;
using Microsoft.AspNetCore.Authorization;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore.Books
{
public class BookAppService : ApplicationService, IBookAppService
{
public Task<PagedResultDto<BookDto>> GetListAsync()
{
var bookDtos = new List<BookDto>()
{
new BookDto(){ Name = "Hunger", AuthorName ="Knut Hamsun", Price = 50},
new BookDto(){ Name = "Crime and Punishment", AuthorName ="Dostoevsky", Price = 60},
new BookDto(){ Name = "For Whom the Bell Tolls", AuthorName ="Ernest Hemingway", Price = 70}
};
return Task.FromResult(new PagedResultDto<BookDto>(
bookDtos.Count,
bookDtos
));
}
}
}
```
It simply returns a list of books. You probably want to get the books from a database, but it doesn't matter for this article. If you want it, you can fully implement [this tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1?UI=MVC&DB=EF).
## Consume the app service from the console application
The startup solution comes with an example .NET console application (`Acme.BookStore.HttpApi.Client.ConsoleTestApp`) that is fully configured to consume your HTTP APIs remotely. Change `ClientDemoService` as shown in the following `Acme.BookStore.HttpApi.Client.ConsoleTestApp` project (it is under the `test` folder).
```csharp
using Acme.BookStore.Books;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.DependencyInjection;
namespace Acme.BookStore.HttpApi.Client.ConsoleTestApp;
public class ClientDemoService : ITransientDependency
{
private readonly IBookAppService _bookAppService;
public ClientDemoService(IBookAppService bookAppService )
{
_bookAppService = bookAppService;
}
public async Task RunAsync()
{
var listOfBooks = await _bookAppService.GetListAsync(new PagedAndSortedResultRequestDto());
Console.WriteLine($"Books: {string.Join(", ", listOfBooks.Items.Select(p => p.Name).ToList())}");
}
}
```
We are basically injecting the `IBookAppService` interface to consume the remote service. ABP handles all the details (performing HTTP request, deserializing the resulting JSON object, etc) for us.
You can run the application to see the output:
```
Books: Hunger, Crime and Punishment, For Whom the Bell Tolls
```
## Convert the application to use static client proxies
The [application startup template](https://docs.abp.io/en/abp/latest/Startup-Templates/Application) comes pre-configured for the **dynamic** client proxy generation, in the `HttpApi.Client` project. If you want to switch to the **static** client proxies, you should change `context.Services.AddHttpClientProxies` to `context.Services.AddStaticHttpClientProxies` in the module class of your `HttpApi.Client` project:
```csharp
public class BookStoreHttpApiClientModule : AbpModule
{
public const string RemoteServiceName = "Default";
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Other configurations...
context.Services.AddStaticHttpClientProxies(
typeof(BookStoreApplicationContractsModule).Assembly,
RemoteServiceName
);
}
}
```
The `AddStaticHttpClientProxies` method gets an assembly, finds all service interfaces in the given assembly, and prepares for static client proxy generation.
Now you're ready to generate the client proxy code by running the following command in the root folder of your client project **while your server-side project is running**:
````bash
abp generate-proxy -t csharp -u http://localhost:44397/
````
> The URL (`-u` parameter's value) might be different for your application. It should be the server's root URL.
You should see the generated files under the selected folder:
![files of the static proxy](./static-proxy.png)
Now you can run the console client application again. You should see the same output:
````
Books: Hunger, Crime and Punishment, For Whom the Bell Tolls
````
## Add authorization
The ABP Framework provides an [authorization system](https://docs.abp.io/en/abp/latest/Authorization) based on [ASP.NET Core's authorization infrastructure](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/introduction). We can define permissions and restrict access to some of our application's functionalities, so only the allowed users/clients can use these functionalities. Here, I will define a permission to be able to get the list of books.
### Defining a permission
Under `Acme.BookStore.Application.Contracts` open `BookStorePermissions` and paste the below code:
```csharp
namespace Acme.BookStore.Permissions;
public static class BookStorePermissions
{
public const string GroupName = "BookStore";
public static class Books
{
public const string Default = GroupName + ".Books";
}
}
```
You also need to change `BookStorePermissionDefinitionProvider` under the same folder and project as follows:
```csharp
using Acme.BookStore.Localization;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Localization;
public class BookStorePermissionDefinitionProvider : PermissionDefinitionProvider
{
public override void Define(IPermissionDefinitionContext context)
{
var bookStoreGroup = context.AddGroup(BookStorePermissions.GroupName);
bookStoreGroup.AddPermission(BookStorePermissions.Books.Default);
}
}
```
### Authorizing the application service
We can now add the `[Authorize(BookStorePermissions.Books.Default)]` attribute to the `BookAppService` class:
```csharp
[Authorize(BookStorePermissions.Books.Default)]
public class BookAppService : ApplicationService, IBookAppService
{
...
}
```
If you run the server now, then run the console client application, you will see the following error on the console application:
```
Unhandled exception. Volo.Abp.Http.Client.AbpRemoteCallException: Forbidden at
Volo.Abp.Http.Client.ClientProxying.ClientProxyBase`1
.ThrowExceptionForResponseAsync(HttpResponseMessage response)...
```
To fix the problem, we should grant permission to the admin user. We are granting permission to the admin user because the console application is configured to use the Resource Owner Password Grant Flow. That means the client application is consuming services on behalf of the admin user. You can see the configuration in the `appsettings.json` file of the console application.
### Granting the permission
Once you define the permissions, you can see them on the permission management modal.
Go to the Administration -> Identity -> Roles page, select the Permissions action for the admin role to open the permission management modal:
![persmisson](./permission.png)
Grant the permissions you want and save the modal.
## Dynamic vs static proxies
Static generic proxies provide **better performance** because they don't need to run on runtime, but you should **re-generate** them once you change the API endpoint definition. Dynamic generic proxies don't need to be re-generated because they work on the runtime but they have a slight performance penalty.
## Further Reading
In this tutorial, I explained how you can create an example project and apply a static client proxy instead of a dynamic client proxy. I also summarized the differences between both approaches. If you want to get more information, you can read the following documents:
* [Static C# API Client Proxies](https://docs.abp.io/en/abp/latest/API/Static-CSharp-API-Clients)
* [Dynamic C# API Client Proxies](https://docs.abp.io/en/abp/latest/API/Dynamic-CSharp-API-Clients)
* [Web Application Development Tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1?UI=MVC&DB=EF)

BIN
docs/en/Community-Articles/2022-05-16-Consuming-Rest-Api-By-Using-Static-Proxy/permission.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
docs/en/Community-Articles/2022-05-16-Consuming-Rest-Api-By-Using-Static-Proxy/static-proxy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

54
docs/en/Contribution/How-to-Contribute-abp.io-as-a-frontend-developer.md

@ -0,0 +1,54 @@
# How to contribute to abp.io as a frontend developer
## How to setup development environment
### Pre-requirements
- Dotnet core SDK https://dotnet.microsoft.com/en-us/download
- Nodejs LTS https://nodejs.org/en/
- Docker https://docs.docker.com/engine/install
- Angular CLI. https://angular.io/guide/what-is-angular#angular-cli
- Abp CLI https://docs.abp.io/en/abp/latest/cli
- A code editor
Note: This arcticle prepare Windows OS. You may change the path type of your OS. an Example
Windows: `templates\app\aspnet-core\src\MyCompanyName.MyProjectName.DbMigrator\appsettings.json`
Unix: `templates/app/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json`
### Sample docker commands
You need to install SQL Server and Redis. You can install these programs without docker, but my example uses docker containers. Your computer should have Docker Engine. Then open the terminal en execute the commands one by one.
For the Sql Server
docker run -v sqlvolume:/var/opt/mssql -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=yourpassword -p 1433:1433 -d mcr.microsoft.com/mssql/server:2019-CU3-ubuntu-18.04
For the Redis
docker run -p 6379:6379 -d redis
Then we are ready to download and execute the code.
## Folder Structure
The app has a backend written in .net core (c#) and an angular app. It would help if you ran both of them.
### Running Backend App
The path of the Backend app is “templates\app\aspnet-core.” If you want to work with dockerized SQL Server, you should change connection strings for running with docker. The path of the connection string is
`templates\app\aspnet-core\src\MyCompanyName.MyProjectName.DbMigrator\appsettings.json`.
Before running the backend, you should run the Db migrator project. The DbMigrator created initial tables and values. The path of DbMigrator is `templates\app\aspnet-core\src\MyCompanyName.MyProjectName.DbMigrator`. Open a terminal in the path and execute the command `dotnet run` in terminal
One last step before the running the backend is installing client-side libraries. Go to `templates\app\aspnet-core`. Open a terminal in the path and execute the command `abp install-libs` in terminal
Next step you should go to path of backend host project. The path is `templates\app\aspnet-core\src\MyCompanyName.MyProjectName.HttpApi.HostWithIds`. Open a terminal in the path and execute the command `dotnet run` in terminal
Your backend should be running successfully
### Running Frontend App
There is a demo app. The path of the demo app is `npm\ng-packs\apps\dev-app`. The demo app is connected to the packages with local references. Open the terminal in `npm\ng-packs\apps\dev-app` and execute `yarn` or `npm i` in terminal. After the package installed run `npm start` or `yarn start`.
The repo uses Nx and packages connected with `local references`. The packages path is `”npm\ng-packs\packages`

8
docs/en/Contribution/Index.md

@ -70,3 +70,11 @@ If you want to make a change on a specific resource file, you can find the file
## Bug Report
If you find any bug, please [create an issue on the Github repository](https://github.com/abpframework/abp/issues/new).
## Setup Frontend Development Environment
[How to contribute to abp.io as a frontend developer](How-to-Contribute-abp.io-as-a-frontend-developer.md)
## See Also
* [ABP Community Talks 2022.4: How can you contribute to the open source ABP Framework?](https://www.youtube.com/watch?v=Wz4Z-O-YoPg&list=PLsNclT2aHJcOsPustEkzG6DywiO8eh0lB)

2
docs/en/CurrentUser.md

@ -90,7 +90,7 @@ Beside these standard methods, there are some extension methods:
For a web application, it gets the `User` property of the current `HttpContext`. For a non-web application, it returns the `Thread.CurrentPrincipal`.
> You generally don't need to this low level `ICurrentPrincipalAccessor` service and directly work with the `ICurrentUser` explained above.
> You generally don't need to use this low level `ICurrentPrincipalAccessor` service and just directly work with the `ICurrentUser` explained above.
### Basic Usage

2
docs/en/Dependency-Injection.md

@ -131,7 +131,7 @@ public class TaxCalculator: ICalculator, ITaxCalculator, ICanCalculate, ITransie
If you do not specify which services to expose, ABP expose services by convention. So taking the ``TaxCalculator`` defined above:
* The class itself is exposed by default. That means you can inject it by ``TaxCalculator`` class.
* Default interfaces are exposed by default. Default interfaces are determined by naming convention. In this example, ``ICalculator`` and ``ITaxCalculator`` are default interfaces of ``TaxCalculator``, but ``ICanCalculate`` is not.
* Default interfaces are exposed by default. Default interfaces are determined by naming convention. In this example, ``ICalculator`` and ``ITaxCalculator`` are default interfaces of ``TaxCalculator``, but ``ICanCalculate`` is not. A generic interface (e.g. `ICalculator<string>`) is also considered as a default interface if the naming convention is satisfied.
### Combining All Together

48
docs/en/Deployment/Clustered-Environment.md

@ -1,10 +1,10 @@
# Deploying to a Clustered Environment
This document introduces the topics that you should care when you are deploying your application to a clustered environment where **multiple instances of your application runs concurrently**, and explains how you can deal with these topics in your ABP based application.
This document introduces the topics that you should consider when you are deploying your application to a clustered environment where **multiple instances of your application run concurrently**, and explains how you can deal with these topics in your ABP based application.
> This document is valid regardless you have a monolith application or a microservice solution. The Application term is used for a process. An application can be a monolith web application, a service in a microservice solution, a console application, or another kind of executable process.
> This document is valid regardless you have a monolith application or a microservice solution. The Application term is used for a process. An application can be a monolith web application, a service in a microservice solution, a console application, or another kind of an executable process.
>
> For example, if you are deploying your application to Kubernetes and configure so that your application or service runs in multiple pods, then your application or service runs in a clustered environment.
> For example, if you are deploying your application to Kubernetes and configure your application or service to run in multiple pods, then your application or service runs in a clustered environment.
## Understanding the Clustered Environment
@ -20,36 +20,36 @@ Browsers and other client applications can directly make HTTP requests to your a
### Clustered Deployment
**Clustered deployment** is the way of running **multiple instances** of your application **concurrently** in a single or multiple servers. In this way, different instances can serve to different requests and you can scale by adding new servers to the system. The following figure shows a typical implementation of clustering using a **load balancer**:
**Clustered deployment** is the way of running **multiple instances** of your application **concurrently** in a single or multiple servers. In this way, different instances can serve different requests and you can scale by adding new servers to the system. The following figure shows a typical implementation of clustering using a **load balancer**:
![deployment-clustered](../images/deployment-clustered.png)
### Load Balancers
[Load balancers](https://en.wikipedia.org/wiki/Load_balancing_(computing)) have a lot of features, but they fundamentally **forwards an incoming HTTP request** to an instance of your application and returns your response back to the client application.
[Load balancers](https://en.wikipedia.org/wiki/Load_balancing_(computing)) have a lot of features, but they fundamentally **forward an incoming HTTP request** to an instance of your application and return your response back to the client application.
Load balancers can use different algorithms for selecting the application instance while determining the application instance that is used to deliver the incoming request. **Round Robin** is one of the simplest and most used algorithms. Requests are delivered to the application instances in rotation. First instance gets the first request, second instance gets the second, and so on. It returns to the first instance after all the instances are used, and the algorithm goes like that for the next requests.
### Potential Problems
Once multiple instances of your application runs in parallel, you should carefully consider the following topics:
Once multiple instances of your application run in parallel, you should carefully consider the following topics:
* Any **state (data) stored in memory** of your application will become a problem when you have multiple instances. A state stored in memory of an application instance may not be available in the next request since the next request will be handled by a different application instance. While there are some solutions (like sticky sessions) to overcome this problem user-basis, it is a **best practice to design your application as stateless** if you want to run it in a cluster, container or/and cloud.
* **In-memory caching** is a kind of in-memory state and should not be used in a clustered application. You should use **distributed caching** instead.
* You shouldn't store data in the **local file system** that should be available to all instances of your application. Difference application instance may run in different containers or servers and they may not be able to access to the same file system. You can use a **cloud or external storage provider** as a solution.
* You shouldn't store data in the **local file system**. It should be available to all instances of your application. Different application instance may run in different containers or servers and they may not be able to have access to the same file system. You can use a **cloud or external storage provider** as a solution.
* If you have **background workers** or **job queue managers**, you should be careful since multiple instances may try to execute the same job or perform the same work concurrently. As a result, you may have the same work done multiple times or you may get a lot of errors while trying to access and change the same resources.
You may have more problems with clustered deployment, but these are the most common ones. ABP has been designed to be compatible with clustered deployment scenario. The following sections explains what you should do when you are deploying your ABP based application to a clustered environment.
You may have more problems with clustered deployment, but these are the most common ones. ABP has been designed to be compatible with the clustered deployment scenario. The following sections explain what you should do when you are deploying your ABP based application to a clustered environment.
## Switching to a Distributed Cache
ASP.NET Core provides different kind of caching features. [In-memory cache](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/memory) stores your objects in the memory of the local server and only available to the application that stored the object. Non-sticky sessions in a clustered environment should use the [distributed caching](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) except some specific scenarios (for example, you can cache a local CSS file into memory. It is a read-only data and it is the same in all application instances. You can cache it in memory for performance reasons without any problem).
ASP.NET Core provides different kind of caching features. [In-memory cache](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/memory) stores your objects in the memory of the local server and is only available to the application that stored the object. Non-sticky sessions in a clustered environment should use the [distributed caching](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) except some specific scenarios (for example, you can cache a local CSS file into memory. It is read-only data and it is the same in all application instances. You can cache it in memory for performance reasons without any problem).
[ABP's Distributed Cache](../Caching.md) extends [ASP.NET Core's distributed cache](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) infrastructure. It works in-memory by default. You should configure an actual distributed cache provider when you want to deploy your application to a clustered environment.
> You should configure the cache provider for a clustered deployment, even if your application doesn't directly use `IDistributedCache`. Because ABP Framework and pre-built [application modules](../Modules/Index.md) are using the distributed cache.
> You should configure the cache provider for clustered deployment, even if your application doesn't directly use `IDistributedCache`. Because the ABP Framework and the pre-built [application modules](../Modules/Index.md) are using distributed cache.
ASP.NET Core's provides multiple integrations to use as your distributed cache provider, like [Redis](https://redis.io/) and [NCache](https://www.alachisoft.com/ncache/). You can follow [Microsoft's documentation](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) to learn how to use them in your applications.
ASP.NET Core provides multiple integrations to use as your distributed cache provider, like [Redis](https://redis.io/) and [NCache](https://www.alachisoft.com/ncache/). You can follow [Microsoft's documentation](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) to learn how to use them in your applications.
If you decided to use Redis as your distributed cache provider, **follow [ABP's Redis Cache Integration document](../Redis-Cache.md)** for the steps you need to follow to install it into your application and setup your Redis configuration.
@ -57,30 +57,30 @@ If you decided to use Redis as your distributed cache provider, **follow [ABP's
## Using a Proper BLOB Storage Provider
If you have used ABP's [BLOB Storing](../Blob-Storing.md) feature with the [File System provider](../Blob-Storing-File-System.md), you should use another provider in your clustered environment since the File System provider uses application's local file system.
If you have used ABP's [BLOB Storing](../Blob-Storing.md) feature with the [File System provider](../Blob-Storing-File-System.md), you should use another provider in your clustered environment since the File System provider uses the application's local file system.
The [Database BLOB provider](../Blob-Storing-Database) is the easiest way since it uses your application's main database (or another database if you configure) to store BLOBs. However, you should remember that BLOBs are large objects and may quickly increase your database's size.
> [ABP Commercial](https://commercial.abp.io/) startup solution templates come with the database BLOB provider as pre-installed, and stores BLOBs in the application's database.
Check the [BLOB Storing](../Blob-Storing.md) document to see all available BLOG storage providers.
Check the [BLOB Storing](../Blob-Storing.md) document to see all the available BLOG storage providers.
## Configuring Background Jobs
ABP's [background job system](../Background-Jobs.md) is used to queue tasks to be executed in background. Background job queue is persistent and a queued task is guaranteed to be executed (it is re-tried if it fails).
ABP's [background job system](../Background-Jobs.md) is used to queue tasks to be executed in the background. Background job queue is persistent and a queued task is guaranteed to be executed (it is re-tried if it fails).
ABP's default background job manager is compatible with clustered environments. It uses a [distributed lock](../Distributed-Locking.md) to ensure that the jobs are executed only in a single application instance in a time. See the *Configuring a Distributed Lock Provider* section below to learn how to configure a distributed lock provider for your application, so the default background job manager properly works in a clustered environment.
ABP's default background job manager is compatible with clustered environments. It uses a [distributed lock](../Distributed-Locking.md) to ensure that the jobs are executed only in a single application instance at a time. See the *Configuring a Distributed Lock Provider* section below to learn how to configure a distributed lock provider for your application, so the default background job manager properly works in a clustered environment.
If you don't want to use a distributed lock provider, you may go with the following options:
* Stop the background job manager (set `AbpBackgroundJobOptions.IsJobExecutionEnabled` to `false`) in all application instances except one of them, so only the single instance executes the jobs (while other application instances can still queue jobs).
* Stop the background job manager (set `AbpBackgroundJobOptions.IsJobExecutionEnabled` to `false`) in all application instances and create a dedicated application (maybe a console application running in its own container or a Windows Service running in background) to execute all the background jobs. This can be a good option if your background jobs consume high system resource (CPU, RAM or Disk), so you can deploy that background application to a dedicated server and your background jobs doesn't affect your application's performance.
* Stop the background job manager (set `AbpBackgroundJobOptions.IsJobExecutionEnabled` to `false`) in all application instances and create a dedicated application (maybe a console application running in its own container or a Windows Service running in the background) to execute all the background jobs. This can be a good option if your background jobs consume high system resources (CPU, RAM or Disk), so you can deploy that background application to a dedicated server and your background jobs don't affect your application's performance.
> If you are using an external background job integration (e.g. [Hangfire](../Background-Workers-Hangfire.md) or [Quartz](../Background-Workers-Quartz.md)) instead of the default background job manager, then please refer your provider's documentation to learn how it should be configured for a clustered environment.
> If you are using an external background job integration (e.g. [Hangfire](../Background-Workers-Hangfire.md) or [Quartz](../Background-Workers-Quartz.md)) instead of the default background job manager, then please refer to your provider's documentation to learn how it should be configured for a clustered environment.
## Configuring a Distributed Lock Provider
ABP provides a distributed locking abstraction with an implementation made with the [DistributedLock](https://github.com/madelson/DistributedLock) library. A distributed lock is used to control concurrent access to a shared resource by multiple applications to prevent corruption of the resource because of concurrent writes. ABP Framework and some pre-built [application modules](../Modules/Index.md) are using the distributed locking for several reasons.
ABP provides a distributed locking abstraction with an implementation made with the [DistributedLock](https://github.com/madelson/DistributedLock) library. A distributed lock is used to control concurrent access to a shared resource by multiple applications to prevent corruption of the resource because of concurrent writes. The ABP Framework and some pre-built [application modules](../Modules/Index.md) are using distributed locking for several reasons.
However, the distributed lock system works in-process by default. That means it is not distributed actually, unless you configure a distributed lock provider. So, please follow the [distributed lock](../Distributed-Locking.md) document to configure a provider for your application, if it is not already configured.
@ -88,12 +88,12 @@ However, the distributed lock system works in-process by default. That means it
ASP.NET Core provides [hosted services](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services) and ABP provides [background workers](../Background-Workers.md) to perform tasks in background threads in your application.
If your application has tasks running in background, you should care on how they will behave in a clustered environment, especially if your background tasks are using the same resources. You should design your background tasks so they continue to work properly in the clustered environment.
If your application has tasks running in the background, you should consider how they will behave in a clustered environment, especially if your background tasks are using the same resources. You should design your background tasks so that they continue to work properly in the clustered environment.
Assume that your background worker in your SaaS application checks user subscriptions and sends emails if their subscription renewal date approaches. If the background task run in multiple application instances, it is probable to send the same email many times to some users, which will disturb them.
Assume that your background worker in your SaaS application checks user subscriptions and sends emails if their subscription renewal date approaches. If the background task runs in multiple application instances, it is probable to send the same email many times to some users, which will disturb them.
We suggest to you to use one of the following approaches to overcome the problem:
We suggest you to use one of the following approaches to overcome the problem:
* Implement your background workers so that they works in a clustered environment without any problem. Using the [distributed lock](../Distributed-Locking.md) to ensure concurrency control is a way of doing that. A background worker in an application instance may handle a distributed lock, so the workers in other application instances will wait the lock. In this way, only one worker does the actual work, while others wait in idle. If you implement this, your workers run safely without caring how the application is deployed.
* Stop background workers (set `AbpBackgroundWorkerOptions.IsEnabled` to `false`) in all application instances except one of them, so only the single instance runs the workers.
* Stop background workers (set `AbpBackgroundWorkerOptions.IsEnabled` to `false`) in all application instances and create a dedicated application (maybe a console application running in its own container or a Windows Service running in background) to execute all the background tasks. This can be a good option if your background workers consume high system resource (CPU, RAM or Disk), so you can deploy that background application to a dedicated server and your background tasks doesn't affect your application's performance.
* Implement your background workers so that they work in a clustered environment without any problem. Using the [distributed lock](../Distributed-Locking.md) to ensure concurrency control is a way of doing that. A background worker in an application instance may handle a distributed lock, so the workers in other application instances will wait for the lock. In this way, only one worker does the actual work, while others wait in idle. If you implement this, your workers run safely without caring about how the application is deployed.
* Stop the background workers (set `AbpBackgroundWorkerOptions.IsEnabled` to `false`) in all application instances except one of them, so only the single instance runs the workers.
* Stop the background workers (set `AbpBackgroundWorkerOptions.IsEnabled` to `false`) in all application instances and create a dedicated application (maybe a console application running in its own container or a Windows Service running in the background) to execute all the background tasks. This can be a good option if your background workers consume high system resources (CPU, RAM or Disk), so you can deploy that background application to a dedicated server and your background tasks don't affect your application's performance.

2
docs/en/Deployment/Index.md

@ -2,7 +2,7 @@
Deploying an ABP application is not different than deploying any .NET or ASP.NET Core application. You can deploy it to a cloud provider (e.g. Azure, AWS, Google Could) or on-premise server, IIS or any other web server. ABP's documentation doesn't contain much information on deployment. You can refer to your provider's documentation.
However, there are some topics you should care when you are deploying your applications. Most of them are general software deployment considerations, but you should understand how to handle them within your ABP based applications. We've prepared guides for this purpose and we suggest you to read these guides carefully before designing your deployment configuration.
However, there are some topics that you should care about when you are deploying your applications. Most of them are general software deployment considerations, but you should understand how to handle them within your ABP based applications. We've prepared guides for this purpose and we suggest you to read these guides carefully before designing your deployment configuration.
## Guides

219
docs/en/Distributed-Event-Bus.md

@ -20,7 +20,7 @@ For example, [pre-built application modules](Modules/Index.md) is designed to wo
There are two ways of publishing distributed events explained in the following sections.
### IDistributedEventBus
### Using IDistributedEventBus to Publish Events
`IDistributedEventBus` can be [injected](Dependency-Injection.md) and used to publish a distributed event.
@ -57,7 +57,7 @@ namespace AbpDemo
}
````
`PublishAsync` method gets a single parameter: the event object, which is responsible to hold the data related to the event. It is a simple plain class:
`PublishAsync` method gets the event object, which is responsible to hold the data related to the event. It is a simple plain class:
````csharp
using System;
@ -80,15 +80,15 @@ Even if you don't need to transfer any data, you need to create a class (which i
#### Event Name
`EventName` attribute is optional, but suggested. If you don't declare it, the event name will be the full name of the event class, `AbpDemo.StockCountChangedEto` in this case.
`EventName` attribute is optional, but suggested. If you don't declare it for an event type (ETO class), the event name will be the full name of the event class, `AbpDemo.StockCountChangedEto` in this case.
#### About Serialization for the Event Objects
Event transfer objects **must be serializable** since they will be serialized/deserialized to JSON or other format when it is transferred to out of the process.
Event transfer objects (ETOs) **must be serializable** since they will be serialized/deserialized to JSON or other format when it is transferred to out of the process.
Avoid circular references, polymorphism, private setters and provide default (empty) constructors if you have any other constructor as a good practice (while some serializers may tolerate it), just like the DTOs.
### Inside Entity / Aggregate Root Classes
### Publishing Events Inside Entity / Aggregate Root Classes
[Entities](Entities.md) can not inject services via dependency injection, but it is very common to publish distributed events inside entity / aggregate root classes.
@ -294,4 +294,211 @@ This example;
* Adds a selector to allow to publish the create, update and delete events for the `Product` entity.
* Configure to use the `ProductEto` as the event transfer object to publish for the `Product` related events.
> Distributed event system use the [object to object mapping](Object-To-Object-Mapping.md) system to map `Product` objects to `ProductEto` objects. So, you need to configure the object mapping (`Product` -> `ProductEto`) too. You can check the [object to object mapping document](Object-To-Object-Mapping.md) to learn how to do it.
> Distributed event system use the [object to object mapping](Object-To-Object-Mapping.md) system to map `Product` objects to `ProductEto` objects. So, you need to configure the object mapping (`Product` -> `ProductEto`) too. You can check the [object to object mapping document](Object-To-Object-Mapping.md) to learn how to do it.
## Transaction and Exception Handling
Distributed event bus works in-process (since default implementation is `LocalDistributedEventBus`) unless you configure an actual provider (e.g. [Kafka](Distributed-Event-Bus-Kafka-Integration.md) or [RabbitMQ](Distributed-Event-Bus-RabbitMQ-Integration.md)). In-process event bus always executes event handlers in the same [unit of work](Unit-Of-Work.md) scope that you publishes the events in. That means, if an event handler throws an exception, then the related unit of work (the database transaction) is rolled back. In this way, your application logic and event handling logic becomes transactional (atomic) and consistent. If you want to ignore errors in an event handler, you must use a `try-catch` block in your handler and shouldn't re-throw the exception.
When you switch to an actual distributed event bus provider (e.g. [Kafka](Distributed-Event-Bus-Kafka-Integration.md) or [RabbitMQ](Distributed-Event-Bus-RabbitMQ-Integration.md)), then the event handlers will be executed in different processes/applications as their purpose is to create distributed systems. In this case, the only way to implement transactional event publishing is to use the outbox/inbox patterns as explained in the *Outbox / Inbox for Transactional Events* section.
If you don't configure outbox/inbox pattern or use the `LocalDistributedEventBus`, then events are published at the end of the unit of work by default, just before the unit of work is completed (that means throwing exception in an event handler still rollbacks the unit of work), even if you publish them in the middle of unit of work. If you want to immediately publish the event, you can set `onUnitOfWorkComplete` to `false` while using `IDistributedEventBus.PublishAsync` method.
> Keeping the default behavior is recommended unless you don't have a unique requirement. `onUnitOfWorkComplete` option is not available when you publish events inside entity / aggregate root classes (see the *Publishing Events Inside Entity / Aggregate Root Classes* section).
## Outbox / Inbox for Transactional Events
The **[transactional outbox pattern](https://microservices.io/patterns/data/transactional-outbox.html)** is used to publishing distributed events within the **same transaction** that manipulates the application's database. When you enable outbox, distributed events are saved into the database inside the same transaction with your data changes, then sent to the actual message broker by a separate [background worker](Background-Workers.md) with a re-try system. In this way, it ensures the consistency between your database state and the published events.
The **transactional inbox pattern**, on the other hand, saves incoming events into database first. Then (in a [background worker](Background-Workers.md)) executes the event handler in a transactional manner and removes the event from the inbox queue in the same transaction. It ensures that the event is only executed one time by keeping the processed messages for a while and discarding the duplicate events received from the message broker.
Enabling the event outbox and inbox systems require a few manual steps for your application. Please apply the instructions in the following sections to make them running.
> Outbox and Inbox can be separately enabled and configured, so you may only use one of them if you want.
### Pre-requirements
* The outbox/inbox system uses the distributed lock system to handle concurrency when you run multiple instances of your application/service. So, you should **configure the distributed lock system** with one of the providers as [explained in this document](Distributed-Locking.md).
* The outbox/inbox system supports [Entity Framework Core](Entity-Framework-Core.md) (EF Core) and [MongoDB](MongoDB.md) **database providers** out of the box. So, your applications should use one of these database providers. For other database providers, see the *Implementing a Custom Database Provider* section.
> If you are using MongoDB, be sure that you enabled multi-document database transactions that was introduced in MongoDB version 4.0. See the *Transactions* section of the [MongoDB](MongoDB.md) document.
### Enabling event outbox
Open your `DbContext` class (EF Core or MongoDB), implement the `IHasEventOutbox` interface. You should end up by adding a `DbSet` property into your `DbContext` class:
```csharp
public DbSet<OutgoingEventRecord> OutgoingEvents { get; set; }
```
Add the following lines inside the `OnModelCreating` method of your `DbContext` class (only for EF Core):
```csharp
builder.ConfigureEventOutbox();
```
For EF Core, use the standard `Add-Migration` and `Update-Database` commands to apply changes into your database (you can skip this step for MongoDB). If you want to use the command-line terminal, run the following commands in the root directory of the database integration project:
```bash
dotnet ef migrations add "Added_Event_Outbox"
dotnet ef database update
```
Finally, write the following configuration code inside the `ConfigureServices` method of your [module class](Module-Development-Basics.md) (replace `YourDbContext` with your own `DbContext` class):
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Outboxes.Configure(config =>
{
config.UseDbContext<YourDbContext>();
});
});
````
### Enabling event inbox
Open your `DbContext` class (EF Core or MongoDB), implement the `IHasEventInbox` interface. You should end up by adding a `DbSet` property into your `DbContext` class:
```csharp
public DbSet<IncomingEventRecord> IncomingEvents { get; set; }
```
Add the following lines inside the `OnModelCreating` method of your `DbContext` class (only for EF Core):
```csharp
builder.ConfigureEventInbox();
```
For EF Core, use the standard `Add-Migration` and `Update-Database` commands to apply changes into your database (you can skip this step for MongoDB). If you want to use the command-line terminal, run the following commands in the root directory of the database integration project:
```bash
dotnet ef migrations add "Added_Event_Inbox"
dotnet ef database update
```
Finally, write the following configuration code inside the `ConfigureServices` method of your [module class](Module-Development-Basics.md) (replace `YourDbContext` with your own `DbContext` class):
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Inboxes.Configure(config =>
{
config.UseDbContext<YourDbContext>();
});
});
````
### Additional Configuration
> The default configuration will be enough for most cases. However, there are some options you may want to set for outbox and inbox.
#### Outbox configuration
Remember how outboxes are configured:
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Outboxes.Configure(config =>
{
// TODO: Set options
});
});
````
Here, the following properties are available on the `config` object:
* `IsSendingEnabled` (default: `true`): You can set to `false` to disable sending outbox events to the actual event bus. If you disable this, events can still be added to outbox, but not sent. This can be helpful if you have multiple applications (or application instances) writing to outbox, but use one of them to send the events.
* `Selector`: A predicate to filter the event (ETO) types to be used for this configuration. Should return `true` to select the event. It selects all the events by default. This is especially useful if you want to ignore some ETO types from the outbox, or want to define named outbox configurations and group events within these configurations. See the *Named Configurations* section.
* `ImplementationType`: Type of the class that implements the database operations for the outbox. This is normally set when you call `UseDbContext` as shown before. See *Implementing a Custom Outbox/Inbox Database Provider* section for advanced usages.
#### Inbox configuration
Remember how inboxes are configured:
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Inboxes.Configure(config =>
{
// TODO: Set options
});
});
````
Here, the following properties are available on the `config` object:
* `IsProcessingEnabled` (default: `true`): You can set to `false` to disable processing (handling) events in the inbox. If you disable this, events can still be received, but not executed. This can be helpful if you have multiple applications (or application instances), but use one of them to execute the event handlers.
* `EventSelector`: A predicate to filter the event (ETO) types to be used for this configuration. This is especially useful if you want to ignore some ETO types from the inbox, or want to define named inbox configurations and group events within these configurations. See the *Named Configurations* section.
* `HandlerSelector`: A predicate to filter the event handled types (classes implementing the `IDistributedEventHandler<TEvent>` interface) to be used for this configuration. This is especially useful if you want to ignore some event handler types from inbox processing, or want to define named inbox configurations and group event handlers within these configurations. See the *Named Configurations* section.
* `ImplementationType`: Type of the class that implements the database operations for the inbox. This is normally set when you call `UseDbContext` as shown before. See *Implementing a Custom Outbox/Inbox Database Provider* section for advanced usages.
### Skipping Outbox
`IDistributedEventBus.PublishAsync` method provides an optional parameter, `useOutbox`, which is set to `true` by default. If you bypass outbox and immediately publish an event, you can set it to `false` for a specific event publishing operation.
### Advanced Topics
#### Named Configurations
> All the concepts explained in this section is also valid for inbox configurations. We will show examples only for outbox to keep the document shorter.
See the following outbox configuration code:
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Outboxes.Configure(config =>
{
//TODO
});
});
````
This is equivalent of the following code:
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Outboxes.Configure("Default", config =>
{
//TODO
});
});
````
`Default` is this code indicates the configuration name. If you don't specify it (like in the previous code block), `Default` is used as the configuration name.
That means you can define more than one configuration for outbox (also for inbox) with different names. ABP runs all the configured outboxes.
Multiple outboxes can be needed if your application have more than one database and you want to run different outbox queues for different databases. In this case, you can use the `Selector` option to decide the events should be handled by an outbox. See the *Additional Configurations* section above.
#### Implementing a Custom Outbox/Inbox Database Provider
If your application or service is using a database provider other than [EF Core](Entity-Framework-Core.md) and [MongoDB](MongoDB.md), you should manually integrate outbox/inbox system with your database provider.
> Outbox and Inbox table/data must be stored in the same database with your application's data (since we want to create a single database transaction that includes application's database operations and outbox/inbox table operations). Otherwise, you should care about distributed (multi-database) transaction support which is not provided by most of the vendors and may require additional configuration.
ABP provides `IEventOutbox` and `IEventInbox` abstractions as extension point for the outbox/inbox system. You can create classes by implementing these interfaces and register them to [dependency injection](Dependency-Injection.md).
Once you implement your custom event boxes, you can configure `AbpDistributedEventBusOptions` to use your event box classes:
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Outboxes.Configure(config =>
{
config.ImplementationType = typeof(MyOutbox); //Your Outbox class
});
options.Inboxes.Configure(config =>
{
config.ImplementationType = typeof(MyInbox); //Your Inbox class
});
});
````
## See Also
* [Local Event Bus](Local-Event-Bus.md)

4
docs/en/Distributed-Locking.md

@ -1,5 +1,5 @@
# Distributed Locking
Distributed locking is a technique to manage many applications that try to access the same resource. The main purpose is to allow only one of many applications to access the same resource at the same time. Otherwise, accessing the same object from various applications may corrupt the value of resources.
Distributed locking is a technique to manage many applications that try to access the same resource. The main purpose is to allow only one of many applications to access the same resource at the same time. Otherwise, accessing the same object from various applications may corrupt the value of the resources.
> ABP's current distributed locking implementation is based on the [DistributedLock](https://github.com/madelson/DistributedLock) library.
@ -107,4 +107,4 @@ ABP's `IAbpDistributedLock` service is very limited and mainly designed to be in
## The Volo.Abp.DistributedLocking.Abstractions Package
If you are building a reusable library or an application module, then you may not want to bring an additional dependency to your module for simple applications those run as a single instance. In this case, your library can depend on the [Volo.Abp.DistributedLocking.Abstractions](https://nuget.org/packages/Volo.Abp.DistributedLocking.Abstractions) package which defines the `IAbpDistributedLock` service and implements it as in-process (not distributed actually). In this way, your library can run properly (without a distributed lock provider dependency) in an application that runs as a single instance. If the application is deployed to a [clustered environment](Deployment/Clustered-Environment.md), then the application developer should install a real distributed provider as explained in the *Installation* section.
If you are building a reusable library or an application module, then you may not want to bring an additional dependency to your module for simple applications that run as a single instance. In this case, your library can depend on the [Volo.Abp.DistributedLocking.Abstractions](https://nuget.org/packages/Volo.Abp.DistributedLocking.Abstractions) package which defines the `IAbpDistributedLock` service and implements it as in-process (not distributed actually). In this way, your library can run properly (without a distributed lock provider dependency) in an application that runs as a single instance. If the application is deployed to a [clustered environment](Deployment/Clustered-Environment.md), then the application developer should install a real distributed provider as explained in the *Installation* section.

4
docs/en/Getting-Started-Create-Solution.md

@ -20,7 +20,7 @@ We will use the ABP CLI to create a new ABP project.
Use the `new` command of the ABP CLI to create a new project:
````shell
abp new Acme.BookStore{{if UI == "NG"}} -u angular{{else if UI == "Blazor"}} -u blazor{{else if UI == "BlazorServer"}} -u blazor-server{{end}}{{if DB == "Mongo"}} -d mongodb{{end}}{{if Tiered == "Yes"}}{{if UI == "MVC" || UI == "BlazorServer"}} --tiered{{else}} --separate-identity-server{{end}}{{end}}
abp new Acme.BookStore{{if UI == "NG"}} -u angular{{else if UI == "Blazor"}} -u blazor{{else if UI == "BlazorServer"}} -u blazor-server{{end}}{{if DB == "Mongo"}} -d mongodb{{end}}{{if Tiered == "Yes"}}{{if UI == "MVC" || UI == "BlazorServer"}} --tiered{{else}} --separate-auth-server{{end}}{{end}}
````
*You can use different level of namespaces; e.g. BookStore, Acme.BookStore or Acme.Retail.BookStore.*
@ -33,7 +33,7 @@ abp new Acme.BookStore{{if UI == "NG"}} -u angular{{else if UI == "Blazor"}} -u
{{ else }}
* `--separate-identity-server` argument is used to separate the identity server application from the API host application. If not specified, you will have a single endpoint on the server.
* `--separate-auth-server` argument is used to separate the identity server application from the API host application. If not specified, you will have a single endpoint on the server.
{{ end }}

6
docs/en/Getting-Started-React-Native.md

@ -65,8 +65,8 @@ A React Native application running on an Android emulator or a physical phone **
![React Native tiered project local IP entry](images/rn-tiered-local-ip.png)
* Open the `appsettings.json` in the `.IdentityServer` folder. Replace the `localhost` address on the `SelfUrl` property with your local IP address.
* Open the `launchSettings.json` in the `.IdentityServer/Properties` folder. Replace the `localhost` address on the `applicationUrl` properties with your local IP address.
* Open the `appsettings.json` in the `.AuthServer` folder. Replace the `localhost` address on the `SelfUrl` property with your local IP address.
* Open the `launchSettings.json` in the `.AuthServer/Properties` folder. Replace the `localhost` address on the `applicationUrl` properties with your local IP address.
* Open the `appsettings.json` in the `.HttpApi.Host` folder. Replace the `localhost` address on the `Authority` property with your local IP address.
* Open the `launchSettings.json` in the `.HttpApi.Host/Properties` folder. Replace the `localhost` address on the `applicationUrl` properties with your local IP address.
@ -85,7 +85,7 @@ Run the backend application as described in the [getting started document](Getti
{{ if Tiered == "Yes" }}
> Make sure that `issuer` matches the running address of the `.IdentityServer` project, `apiUrl` matches the running address of the `.HttpApi.Host` or `.Web` project.
> Make sure that `issuer` matches the running address of the `.AuthServer` project, `apiUrl` matches the running address of the `.HttpApi.Host` or `.Web` project.
{{else}}

6
docs/en/Getting-Started-Running-Solution.md

@ -15,7 +15,7 @@
### Connection String
Check the **connection string** in the `appsettings.json` file under the {{if Tiered == "Yes"}}`.IdentityServer` and `.HttpApi.Host` projects{{else}}{{if UI=="MVC"}}`.Web` project{{else if UI=="BlazorServer"}}`.Blazor` project{{else}}`.HttpApi.Host` project{{end}}{{end}}.
Check the **connection string** in the `appsettings.json` file under the {{if Tiered == "Yes"}}`.AuthServer` and `.HttpApi.Host` projects{{else}}{{if UI=="MVC"}}`.Web` project{{else if UI=="BlazorServer"}}`.Blazor` project{{else}}`.HttpApi.Host` project{{end}}{{end}}.
{{ if DB == "EF" }}
@ -99,7 +99,7 @@ Right click to the `.DbMigrator` project and select **Set as StartUp Project**
> Tiered solutions use **Redis** as the distributed cache. Ensure that it is installed and running in your local computer. If you are using a remote Redis Server, set the configuration in the `appsettings.json` files of the projects below.
1. Ensure that the `.IdentityServer` project is the startup project. Run this application that will open a **login** page in your browser.
1. Ensure that the `.AuthServer` project is the startup project. Run this application that will open a **login** page in your browser.
> Use Ctrl+F5 in Visual Studio (instead of F5) to run the application without debugging. If you don't have a debug purpose, this will be faster.
@ -137,7 +137,7 @@ Ensure that the {{if UI=="MVC"}}`.Web`{{else}}`.Blazor`{{end}} project is the st
> Tiered solutions use Redis as the distributed cache. Ensure that it is installed and running in your local computer. If you are using a remote Redis Server, set the configuration in the `appsettings.json` files of the projects below.
Ensure that the `.IdentityServer` project is the startup project. Run the application which will open a **login** page in your browser.
Ensure that the `.AuthServer` project is the startup project. Run the application which will open a **login** page in your browser.
> Use Ctrl+F5 in Visual Studio (instead of F5) to run the application without debugging. If you don't have a debug purpose, this will be faster.

4
docs/en/Index.md

@ -4,7 +4,7 @@ ABP Framework offers an **opinionated architecture** to build enterprise softwar
## Getting Started
* [Quick Start](Tutorials/Todo/Index.md) 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.
* [Quick Start](Tutorials/Todo/Overall.md) 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](Getting-Started.md) guide can be used to create and run ABP based solutions with different options and details.
* [Web Application Development Tutorial](Tutorials/Part-1.md) is a complete tutorial to develop a full stack web application with all aspects of a real-life solution.
@ -47,7 +47,7 @@ Application Modules provides pre-built application functionalities;
* [**Account**](Modules/Account.md): Provides UI for the account management and allows user to login/register to the application.
* **[Identity](Modules/Identity.md)**: Manages organization units, roles, users and their permissions, based on the Microsoft Identity library.
* [**IdentityServer**](Modules/IdentityServer.md): Integrates to IdentityServer4.
* [**OpenIddict**](Modules/OpenIddict.md): Integrates to OpenIddict.
* [**Tenant Management**](Modules/Tenant-Management.md): Manages tenants for a [multi-tenant](Multi-Tenancy.md) (SaaS) application.
See the [Application Modules](Modules/Index.md) document for all pre-built modules.

44
docs/en/Local-Event-Bus.md

@ -6,7 +6,7 @@ The Local Event Bus allows services to publish and subscribe to **in-process eve
There are two ways of publishing local events explained in the following sections.
### ILocalEventBus
### Publishing Events Using the ILocalEventBus
`ILocalEventBus` can be [injected](Dependency-Injection.md) and used to publish a local event.
@ -64,7 +64,7 @@ namespace AbpDemo
Even if you don't need to transfer any data, you need to create a class (which is an empty class in this case).
### Inside Entity / Aggregate Root Classes
### Publishing Events Inside Entity / Aggregate Root Classes
[Entities](Entities.md) can not inject services via dependency injection, but it is very common to publish local events inside entity / aggregate root classes.
@ -109,7 +109,7 @@ namespace AbpDemo
`AggregateRoot` class defines the `AddLocalEvent` to add a new local event, that is published when the aggregate root object is saved (created, updated or deleted) into the database.
> If an entity publishes such an event, it is a good practice to change the related properties in a controlled manner, just like the example above - `StockCount` can only be changed by the `ChangeStockCount` method which guarantees publishing the event.
> Tip: If an entity publishes such an event, it is a good practice to change the related properties in a controlled manner, just like the example above - `StockCount` can only be changed by the `ChangeStockCount` method which guarantees publishing the event.
#### IGeneratesDomainEvents Interface
@ -149,10 +149,10 @@ namespace AbpDemo
}
````
That's all. `MyHandler` is **automatically discovered** by the ABP Framework and `HandleEventAsync` is called whenever a `StockCountChangedEvent` occurs. You can inject any service and perform any required logic here.
That's all. `MyHandler` is **automatically discovered** by the ABP Framework and `HandleEventAsync` is called whenever a `StockCountChangedEvent` occurs. You can inject any service and perform any required logic in your handler class.
* **Zero or more handlers** can subscribe to the same event.
* A single event handler class can **subscribe to multiple events** but implementing the `ILocalEventHandler<TEvent>` interface for each event type.
* **One or more handlers** can subscribe to the same event.
* A single event handler class can **subscribe to multiple events** by implementing the `ILocalEventHandler<TEvent>` interface for each event type.
If you perform **database operations** and use the [repositories](Repositories.md) inside the event handler, you may need to create a [unit of work](Unit-Of-Work.md), because some repository methods need to work inside an **active unit of work**. Make the handle method `virtual` and add a `[UnitOfWork]` attribute for the method, or manually use the `IUnitOfWorkManager` to create a unit of work scope.
@ -160,10 +160,11 @@ If you perform **database operations** and use the [repositories](Repositories.m
### Transaction & Exception Behavior
When an event published, subscribed event handlers are immediately executed. So;
Event handlers are always executed in the same [unit of work](Unit-Of-Work.md) scope, that means in the same database transaction with the code that published the event. If an event handler throws an exception, the unit of work (database transaction) is rolled back. So, **use try-catch yourself** in the event handler if you want to hide the error.
* If a handler **throws an exception**, it effects the code that published the event. That means it gets the exception on the `PublishAsync` call. So, **use try-catch yourself** in the event handler if you want to hide the error.
* If the event publishing code is being executed inside a [Unit Of Work](Unit-Of-Work.md) scope, the event handlers also covered by the unit of work. That means if your UOW is transactional and a handler throws an exception, the transaction is rolled back.
When you call `ILocalEventBus.PublishAsync`, the event handlers are not immediately executed. Instead, they are executed just before the current unit of work completed (an unhandled exception in the handler still rollbacks the current unit of work). If you want to immediately execute the handlers, set the optional `onUnitOfWorkComplete` parameter to `false`.
> Keeping the default behavior is recommended unless you don't have a unique requirement. `onUnitOfWorkComplete` option is not available when you publish events inside entity / aggregate root classes (see the *Publishing Events Inside Entity / Aggregate Root Classes* section).
## Pre-Built Events
@ -195,35 +196,22 @@ namespace AbpDemo
}
````
This class subscribes to the `EntityCreatedEventData<IdentityUser>`, which is published just after a user was created. You may want to send a "Welcome" email to the new user.
There are two types of these events: events with past tense and events with continuous tense.
### Events with Past Tense
This class subscribes to the `EntityCreatedEventData<IdentityUser>`, which is published just after a user was created (but before the current transaction is completed). For example, you may want to send a "Welcome" email to the new user.
Events with past tense are published when the related unit of work completed and the entity change successfully saved to the database. If you throw an exception on these event handlers, it **can not rollback** the transaction since it was already committed.
The event types are;
The pre-built event types are;
* `EntityCreatedEventData<T>` is published just after an entity was successfully created.
* `EntityUpdatedEventData<T>` is published just after an entity was successfully updated.
* `EntityDeletedEventData<T>` is published just after an entity was successfully deleted.
* `EntityChangedEventData<T>` is published just after an entity was successfully created, updated or deleted. It can be a shortcut if you need to listen any type of change - instead of subscribing to the individual events.
### Events with Continuous Tense
Events with continuous tense are published before completing the transaction (if database transaction is supported by the database provider being used). If you throw an exception on these event handlers, it **can rollback** the transaction since it is not completed yet and the change is not saved to the database.
The event types are;
* `EntityCreatingEventData<T>` is published just before saving a new entity to the database.
* `EntityUpdatingEventData<T>` is published just before an existing entity is being updated.
* `EntityDeletingEventData<T>` is published just before an entity is being deleted.
* `EntityChangingEventData<T>` is published just before an entity is being created, updated or deleted. It can be a shortcut if you need to listen any type of change - instead of subscribing to the individual events.
#### How It Was Implemented?
Pre-build events are published when you save changes to the database;
* For EF Core, they are published on `DbContext.SaveChanges`.
* For MongoDB, they are published when you call repository's `InsertAsync`, `UpdateAsync` or `DeleteAsync` methods (since MongoDB has not a change tracking system).
## See Also
* [Distributed Event Bus](Distributed-Event-Bus.md)

6
docs/en/Microservice-Architecture.md

@ -23,8 +23,8 @@ One common advise to start a new solution is **always to start with a monolith**
However, developing such a well-modular application can be a problem since it is **hard to keep modules isolated** from each other as you would do it for microservices (see [Stefan Tilkov's article](https://martinfowler.com/articles/dont-start-monolith.html) about that). Microservice architecture naturally forces you to develop well isolated services, but in a modular monolithic application it's easy to tight couple modules to each other and design **weak module boundaries** and API contracts.
ABP can help you in that point by offerring a **microservice-compatible, strict module architecture** where your module is splitted into multiple layers/projects and developed in its own VS solution completely isolated and independent from other modules. Such a developed module is a natural microservice yet it can be easily plugged-in a monolithic application. See the [module development best practice guide](Best-Practices/Index.md) that offers a **microservice-first module design**. All [standard ABP modules](https://github.com/abpframework/abp/tree/master/modules) are developed based on this guide. So, you can use these modules by embedding into your monolithic solution or deploy them separately and use via remote APIs. They can share a single database or can have their own database based on your simple configuration.
ABP can help you in that point by offering a **microservice-compatible, strict module architecture** where your module is split into multiple layers/projects and developed in its own VS solution completely isolated and independent from other modules. Such a developed module is a natural microservice yet it can be easily plugged-in a monolithic application. See the [module development best practice guide](Best-Practices/Index.md) that offers a **microservice-first module design**. All [standard ABP modules](https://github.com/abpframework/abp/tree/master/modules) are developed based on this guide. So, you can use these modules by embedding into your monolithic solution or deploy them separately and use via remote APIs. They can share a single database or can have their own database based on your simple configuration.
## Microservice Demo Solution
## Microservice Demo Solution: eShopOnAbp
The [sample microservice solution](Samples/Microservice-Demo.md) demonstrates a complete microservice solution based on the ABP framework.
The [eShopOnAbp project](https://github.com/abpframework/eShopOnAbp) demonstrates a complete microservice solution based on the ABP framework.

11
docs/en/Migration-Guides/Abp-5_3.md

@ -0,0 +1,11 @@
# ABP Version 5.3 Migration Guide
This document is a guide for upgrading ABP v5.2 solutions to ABP v5.3. There is a change in this version that may effect your applications, please read it carefully and apply the necessary changes to your application.
## AutoMapper Upgraded to v11.0.1
AutoMapper library upgraded to **v11.0.1** in this version. So, you need to change your project's target SDK that use the **AutoMapper** library (typically your `*.Application` project). You can change it from `netstandard2.0` to `netstandard2.1` or `net6` if needed. Please see [#12189](https://github.com/abpframework/abp/pull/12189) for more info.
## See Also
* [Official blog post for the 5.3 release](https://blog.abp.io/abp/ABP.IO-Platform-5.3-RC-Has-Been-Published)

1
docs/en/Migration-Guides/Index.md

@ -2,6 +2,7 @@
The following documents explain how to migrate your existing ABP applications. We write migration documents only if you need to take an action while upgrading your solution. Otherwise, you can easily upgrade your solution using the [abp update command](../Upgrading.md).
- [5.2 to 5.3](Abp-5_3.md)
- [5.1 to 5.2](Abp-5_2.md)
- [4.x to 5.0](Abp-5_0.md)
- [4.2 to 4.3](Abp-4_3.md)

6
docs/en/Modules/Account.md

@ -2,7 +2,7 @@
Account module implements the basic authentication features like **login**, **register**, **forgot password** and **account management**.
This module is based on [Microsoft's Identity library](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity) and the [Identity Module](Identity.md). It has [IdentityServer](https://github.com/IdentityServer) integration (based on the [IdentityServer Module](IdentityServer.md)) to provide **single sign-on**, access control and other advanced authentication features.
This module is based on [Microsoft's Identity library](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity) and the [Identity Module](Identity.md). It has [IdentityServer](https://github.com/IdentityServer) integration (based on the [IdentityServer Module](IdentityServer.md)) and [OpenIddict](https://github.com/openiddict) integration (based on the [OpenIddict Module](OpenIddict.md)) to provide **single sign-on**, access control and other advanced authentication features.
## How to Install
@ -42,6 +42,10 @@ Social/external login buttons becomes visible if you setup it. See the *Social/E
![account-module-manage-account](../images/account-module-manage-account.png)
## OpenIddict Integration
[Volo.Abp.Account.Web.OpenIddict](https://www.nuget.org/packages/Volo.Abp.Account.Web.OpenIddict) package provides integration for the [OpenIddict](https://github.com/openiddict). This package comes as installed with the [application startup template](../Startup-Templates/Application.md). See the [OpenIddict Module](OpenIddict.md) documentation.
## IdentityServer Integration
[Volo.Abp.Account.Web.IdentityServer](https://www.nuget.org/packages/Volo.Abp.Account.Web.IdentityServer) package provides integration for the [IdentityServer](https://github.com/IdentityServer). This package comes as installed with the [application startup template](../Startup-Templates/Application.md). See the [IdentityServer Module](IdentityServer.md) documentation.

1
docs/en/Modules/Index.md

@ -19,6 +19,7 @@ There are some **free and open source** application modules developed and mainta
* [**Feature Management**](Feature-Management.md): Used to persist and manage the [features](../Features.md).
* **[Identity](Identity.md)**: Manages organization units, roles, users and their permissions, based on the Microsoft Identity library.
* [**IdentityServer**](IdentityServer.md): Integrates to IdentityServer4.
* [**OpenIddict**](OpenIddict.md): Integrates to OpenIddict.
* [**Permission Management**](Permission-Management.md): Used to persist permissions.
* **[Setting Management](Setting-Management.md)**: Used to persist and manage the [settings](../Settings.md).
* [**Tenant Management**](Tenant-Management.md): Manages tenants for a [multi-tenant](../Multi-Tenancy.md) application.

215
docs/en/Modules/OpenIddict.md

@ -0,0 +1,215 @@
## ABP OpenIddict Modules
## How to Install
TODO:
## User Interface
This module implements the domain logic and database integrations, but not provides any UI. Management UI is useful if you need to add applications and scopes on the fly. In this case, you may build the management UI yourself or consider to purchase the [ABP Commercial](https://commercial.abp.io/) which provides the management UI for this module.
## Relations to Other Modules
This module is based on the [Identity Module](Identity.md) and have an [integration package](https://www.nuget.org/packages/Volo.Abp.Account.Web.OpenIddict) with the [Account Module](Account.md).
## The module
### Demo projects
In the module's `app` directory there are six projects(including `angular`)
* `OpenIddict.Demo.Server`: An abp application with integrated modules (has two `clients` and a `scope`).
* `OpenIddict.Demo.API`: ASP NET Core API application using JwtBearer authentication
* `OpenIddict.Demo.Client.Mvc`: ASP NET Core MVC application using `OpenIdConnect` for authentication
* `OpenIddict.Demo.Client.Console`: Use `IdentityModel` to test OpenIddict's various endpoints, and call the api of `OpenIddict.Demo.API`
* `OpenIddict.Demo.Client.BlazorWASM:` ASP NET Core Blazor application using `OidcAuthentication` for authentication
* `angular`: An angular application that integrates the abp ng modules and uses oauth for authentication
#### How to run?
Confirm the connection string of `appsettings.json` in the `OpenIddict.Demo.Server` project. Running the project will automatically create the database and initialize the data.
After running the `OpenIddict.Demo.API` project, then you can run the rest of the projects to test.
### Domain module
There are four main entities included in this module.
* OpenIddictApplication: **Represents applications(client)**
* OpenIddictScope: **Represents scopes**
* OpenIddictAuthorization: **Represents authorizations, Track of logical chains of tokens and user consent..**
* OpenIddictToken: **Represents various tokens.**
Domain also implements four store interfaces in OpenIddict, OpenIddict uses store to manage entities, corresponding to the above four entities, Custom entity repository is used in the store.
```cs
//Manager
OpenIddictApplicationManager
OpenIddictScopeManager
OpenIddictAuthorizationManager
OpenIddictTokenManager
//Store
IOpenIddictApplicationStore
IOpenIddictScopeStore
IOpenIddictAuthorizationStore
IOpenIddictTokenStore
//Repository
IOpenIddictApplicationRepository
IOpenIddictScopeRepository
IOpenIddictAuthorizationRepository
IOpenIddictTokenRepository
```
We enabled most of OpenIddict's features in the `AddOpenIddict` method, You can change OpenIddict's related builder options via `PreConfigure`.
```cs
PreConfigure<OpenIddictBuilder>(builder =>
{
//builder
});
PreConfigure<OpenIddictCoreBuilder>(builder =>
{
//builder
});
PreConfigure<OpenIddictServerBuilder>(builder =>
{
//builder
});
```
#### AbpOpenIddictAspNetCoreOptions
`UpdateAbpClaimTypes(default: true)`: Updates AbpClaimTypes to be compatible with identity server claims.
`AddDevelopmentEncryptionAndSigningCertificate(default: true)`: Registers (and generates if necessary) a user-specific development encryption/development signing certificate.
You can also change this options via `PreConfigure`.
#### Automatically removing orphaned tokens/authorizations
There is a background task in the `Domain` module (`enabled by default`) that automatically removes orphaned tokens/authorizations, you can configure `TokenCleanupOptions` to manage it.
### ASP NET Core module
This module integrates ASP NET Core, with built-in MVC controllers for four protocols. It uses OpenIddict's [Pass-through mode](https://documentation.openiddict.com/guides/index.html#pass-through-mode).
```cs
AuthorizeController -> connect/authorize
TokenController -> connect/token
LogoutController -> connect/logout
UserInfoController -> connect/userinfo
```
> We will implement the related functions of **device flow** in the PRO module..
#### How to control claims in access_token and id_token
You can use the [Claims Principal Factory](https://docs.abp.io/en/abp/latest/Authorization#claims-principal-factory) to add/remove claims to the `ClaimsPrincipal`.
The `AbpDefaultOpenIddictClaimDestinationsProvider` service will add `Name`, `Email` and `Role` types of Claims to `access_token` and `id_token`, other claims are only added to `access_token` by default, and remove the `SecurityStampClaimType` secret claim of `Identity`.
You can create a service that inherits from `IAbpOpenIddictClaimDestinationsProvider` and add it to DI to fully control the destinations of claims
```cs
public class MyClaimDestinationsProvider : IAbpOpenIddictClaimDestinationsProvider, ITransientDependency
{
public virtual Task SetDestinationsAsync(AbpOpenIddictClaimDestinationsProviderContext context)
{
// ...
return Task.CompletedTask;
}
}
Configure<AbpOpenIddictClaimDestinationsOptions>(options =>
{
options.ClaimDestinationsProvider.Add<MyClaimDestinationsProvider>();
});
```
For detailed information, please refer to: [OpenIddict claim destinations](https://documentation.openiddict.com/configuration/claim-destinations.html)
### EF Core module
Implements the above four repository interfaces.
### MongoDB module
Implements the above four repository interfaces.
## OpenIddict
### Documentation
For more details about OpenIddict, please refer to its official documentation and Github.
https://documentation.openiddict.com
https://github.com/openiddict/openiddict-core#resources
### Disable AccessToken Encryption
ABP disables the `access token encryption` by default for compatibility, you can manually enable it if needed.
```cs
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<OpenIddictServerBuilder>(builder =>
{
builder.Configure(options => options.DisableAccessTokenEncryption = false);
});
}
```
https://documentation.openiddict.com/configuration/token-formats.html#disabling-jwt-access-token-encryption
### PKCE
https://documentation.openiddict.com/configuration/proof-key-for-code-exchange.html
### Request/Response process
I will briefly introduce the principle of OpenIddict so that everyone can quickly understand it.
The `OpenIddict.Server.AspNetCore` adds an authentication scheme(`Name: OpenIddict.Server.AspNetCore, handler: OpenIddictServerAspNetCoreHandler`) and implements the `IAuthenticationRequestHandler` interface.
It will be executed first in `AuthenticationMiddleware` and can short-circuit the current request. Otherwise, `DefaultAuthenticateScheme` will be called and continue to execute the pipeline.
`OpenIddictServerAspNetCoreHandler` will call various built-in handlers(Handling requests and responses), And the handler will process according to the context or skip logic that has nothing to do with it.
Example a token request:
```
POST /connect/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=password&
client_id=AbpApp&
client_secret=1q2w3e*&
username=admin&
password=1q2w3E*&
scope=AbpAPI offline_access
```
This request will be processed by various handlers. They will confirm the endpoint type of the request, check `http/https`, verify that the request parameters (`client. scope etc`) are valid and exist in the database, etc. Various protocol checks. And build a `OpenIddictRequest` object, If there are any errors, the response content may be set and directly short-circuit the current request.
If everything is ok, the request will go to our processing controller(eg `TokenController`), we can get an `OpenIddictRequest` from the http request at this time. The rest of our work will be based on this object.
We may check the `username` and `password` in the request. If it is correct we create a `ClaimsPrincipal` object and return a `SignInResult`, which uses the `OpenIddict.Validation.AspNetCore` authentication scheme name, will calls `OpenIddictServerAspNetCoreHandler` for processing.
`OpenIddictServerAspNetCoreHandler` do some checks to generate json and replace the http response content.
The `ForbidResult` `ChallengeResult` are all the above types of processing.
If you need to customize OpenIddict, you need to replace/delete/add new handlers and make it execute in the correct order.
Please refer to:
https://documentation.openiddict.com/guides/index.html#events-model
## Sponsor
Please consider sponsoring this project: https://github.com/sponsors/kevinchalet

11
docs/en/PlugIn-Modules.md

@ -178,10 +178,8 @@ namespace MyMvcUIPlugIn
//Add plugin assembly
mvcBuilder.PartManager.ApplicationParts.Add(new AssemblyPart(typeof(MyMvcUIPlugInModule).Assembly));
//Add views assembly
var viewDllPath = Path.Combine(Path.GetDirectoryName(typeof(MyMvcUIPlugInModule).Assembly.Location), "MyMvcUIPlugIn.Views.dll");
var viewAssembly = new CompiledRazorAssemblyPart(Assembly.LoadFrom(viewDllPath));
mvcBuilder.PartManager.ApplicationParts.Add(viewAssembly);
//Add CompiledRazorAssemblyPart if the PlugIn module contains razor views.
mvcBuilder.PartManager.ApplicationParts.Add(new CompiledRazorAssemblyPart(typeof(MyMvcUIPlugInModule).Assembly));
});
}
}
@ -189,8 +187,7 @@ namespace MyMvcUIPlugIn
````
* Depending on the `AbpAspNetCoreMvcUiThemeSharedModule` since we added the related NuGet package.
* Adding the plug-in's assembly to the `PartManager` of ASP.NET Core MVC. This is required by ASP.NET Core. Otherwise, your controllers inside the plug-in doesn't work.
* Adding the plug-in's views assembly to the `PartManager` of ASP.NET Core MVC. This is required by ASP.NET Core. Otherwise, your views inside the plug-in doesn't work.
* Adding the plug-in's assembly as `AssemblyPart` and `CompiledRazorAssemblyPart` to the `PartManager` of ASP.NET Core MVC. This is required by ASP.NET Core. Otherwise, your controllers or views inside the plug-in doesn't work.
You can now add a razor page, like `MyPlugInPage.cshtml` inside the `Pages` folder:
@ -205,7 +202,7 @@ Now, you can build the plug-in project. It will produce the following output:
![simple-razor-plug-in-dll-file](images/simple-razor-plug-in-dll-file.png)
Copy the `MyMvcUIPlugIn.dll` and `MyMvcUIPlugIn.Views.dll` into the plug-in folder (`D:\Temp\MyPlugIns` for this example).
Copy the `MyMvcUIPlugIn.dll` into the plug-in folder (`D:\Temp\MyPlugIns` for this example).
If you have configured the main application like described above (see Basic Usage section), you should be able to visit the `/MyPlugInPage` URL when your application:

4
docs/en/Repositories.md

@ -164,6 +164,10 @@ If your entity is a soft-delete entity, you can use the `HardDeleteAsync` method
> See the [Data Filtering](Data-Filtering.md) documentation for more about soft-delete.
### Ensure Entities Exists
The `EnsureExistsAsync` extension method accepts entity id or entities query expression to ensure entities exist, otherwise, it will throw `EntityNotFoundException`.
## Other Generic Repository Types
Standard `IRepository<TEntity, TKey>` interface exposes the standard `IQueryable<TEntity>` and you can freely query using the standard LINQ methods. This is fine for most of the applications. However, some ORM providers or database systems may not support standard `IQueryable` interface. If you want to use such providers, you can't rely on the `IQueryable`.

14
docs/en/Road-Map.md

@ -4,15 +4,18 @@ This document provides a road map, release schedule and planned features for the
## Next Versions
### v5.3
### v6.0
In [5.3 milestone](https://github.com/abpframework/abp/milestone/65), we will be mostly working on the following topics:
In [6.0 milestone](https://github.com/abpframework/abp/milestone/61), we will be mostly working on the following topics:
* Providing an OpenIddict integration to replace current IdentityServer4 integration.
* Maturing and documenting the [eShopOnAbp](https://github.com/abpframework/eShopOnAbp) project, writing a free e-book that explains the solution.
* Working on the [LeptonX](https://blog.abp.io/abp/LeptonX-Theme-for-ABP-Framework-Alpha-Release) theme and making it as the default theme for the ABP Framework UI options.
* Working on more examples and guides.
* Improvements on the existing features and providing more guides.
The planned release date for v5.3 is **May, 2022**.
The planned stable release date for v6.0 is **July, 2022**.
> After the version 6.0, we will be working for ABP 7.0 which will be released in the end of 2022 based on .NET 7.0.
## Backlog Items
@ -20,8 +23,8 @@ The *Next Versions* section above shows the main focus of the planned versions.
Here, a list of major items in the backlog we are considering to work on in the next versions.
* [#7221](https://github.com/abpframework/abp/issues/7221) / Alternative to IdentityServer4
* [#2183](https://github.com/abpframework/abp/issues/2183) / Dapr integration
* [#6655](https://github.com/abpframework/abp/pull/6655) / Use Typescript for the MVC UI
* [#236](https://github.com/abpframework/abp/issues/236) / Resource based authorization system
* [#2882](https://github.com/abpframework/abp/issues/2882) / Providing a gRPC integration infrastructure (while it is [already possible](https://github.com/abpframework/abp-samples/tree/master/GrpcDemo) to create or consume gRPC endpoints for your application, we plan to create endpoints for the [standard application modules](https://docs.abp.io/en/abp/latest/Modules/Index))
* [#1754](https://github.com/abpframework/abp/issues/1754) / Multi-lingual entities
@ -31,7 +34,6 @@ Here, a list of major items in the backlog we are considering to work on in the
* [#4223](https://github.com/abpframework/abp/issues/4223) / WebHook system
* [#162](https://github.com/abpframework/abp/issues/162) / Azure ElasticDB Integration for multitenancy
* [#2296](https://github.com/abpframework/abp/issues/2296) / Feature toggling infrastructure
* [#6655](https://github.com/abpframework/abp/pull/6655) / Use Typescript for the MVC UI
You can always check the milestone planning and the prioritized backlog issues on [the GitHub repository](https://github.com/abpframework/abp/milestones) for a detailed road map. The backlog items are subject to change. We are adding new items and changing priorities based on the community feedbacks and goals of the project.

18
docs/en/Samples/Index.md

@ -2,15 +2,19 @@
Here, a list of official samples built with the ABP Framework. Most of these samples are located under the [abpframework/abp-samples](https://github.com/abpframework/abp-samples) GitHub repository.
### Microservice Demo
## eShopOnAbp
A complete solution to demonstrate how to build systems based on the microservice architecture.
Reference microservice solution built with the ABP Framework and .NET.
* [The complete documentation for this sample](Microservice-Demo.md)
* [Source code](https://github.com/abpframework/abp-samples/tree/master/MicroserviceDemo)
* [Microservice architecture document](../Microservice-Architecture.md)
* [Source code](https://github.com/abpframework/eShopOnAbp)
### Book Store
## EventHub
This is a reference application built with the ABP Framework. It implements the Domain Driven Design with multiple application layers.
* [Source code](https://github.com/abpframework/eventhub)
## Book Store
A simple CRUD application to show basic principles of developing an application with the ABP Framework. The same sample was implemented with different technologies:
@ -28,7 +32,7 @@ A simple CRUD application to show basic principles of developing an application
While there is no Razor Pages & MongoDB combination, you can check both documents to understand it since DB & UI selection don't effect each other.
### Other Samples
## Other Samples
* **Event Organizer**: A sample application to create events (meetups) and allow others to register the events. Developed using EF Core and Blazor UI.
* [Source code](https://github.com/abpframework/abp-samples/tree/master/EventOrganizer)

2
docs/en/Samples/Microservice-Demo.md

@ -1,5 +1,7 @@
# Microservice Demo Solution
> This solution is no longer maintained. See [the eShopOnAbp project](https://github.com/abpframework/eShopOnAbp) for the replacement solution.
*"Microservices are a software development technique—a variant of the **service-oriented architecture** (SOA) architectural style that structures an application as a collection of **loosely coupled services**. In a microservices architecture, services are **fine-grained** and the protocols are **lightweight**. The benefit of decomposing an application into different smaller services is that it improves **modularity**. This makes the application easier to understand, develop, test, and become more resilient to architecture erosion. It **parallelizes development** by enabling small autonomous teams to **develop, deploy and scale** their respective services independently. It also allows the architecture of an individual service to emerge through **continuous refactoring**. Microservices-based architectures enable **continuous delivery and deployment**."*
— [Wikipedia](https://en.wikipedia.org/wiki/Microservices)

107
docs/en/Startup-Templates/Application-Single-Layer.md

@ -0,0 +1,107 @@
# Application (Single Layer) Startup Template
## Introduction
This template provides a simple solution structure with a single project. This document explains that solution structure in details.
### The Difference Between the Application Startup Templates
ABP's [Application Startup Template](Application.md) provides a well-organized and layered solution to create maintainable business applications based on the [Domain Driven Design](../Domain-Driven-Design.md) (DDD) practices. However, some developers find this template a little bit complex for simple and short-term applications. The single-layer application template has been created to provide a simpler development model for such applications. This template has the same functionality, features and modules on runtime with the [Application Startup Template](Application.md) but the development model is minimal and everything is in a single project (`.csproj`).
## How to Start with It?
You can use the [ABP CLI](../CLI.md) to create a new project using this startup template. Alternatively, you can directly create & download this startup template from the [Get Started](https://abp.io/get-started) page. In this section, we will use the ABP CLI.
Firstly, install the ABP CLI if you haven't installed it before:
```bash
dotnet tool install -g Volo.Abp.Cli
```
Then, use the `abp new` command in an empty folder to create a new solution:
```bash
abp new Acme.BookStore -t app-nolayers
```
* `Acme.BookStore` is the solution name, like *YourCompany.YourProduct*. You can use single-level, two-level or three-level naming.
* In this example, the `-t` (or `--template`) option specifies the template name.
### Specify the UI Framework
This template provides multiple UI frameworks:
* `mvc`: ASP.NET Core MVC UI with Razor Pages (default)
* `blazor-server`: Blazor Server UI
* `angular`: Angular UI
* `none`: Without UI (for HTTP API development)
> This template doesn't have Blazor WebAssembly UI, because it requires 3 projects at least (server-side, UI and shared library between these two projects). We are recommending to use the layered [application startup template](Application.md) for Blazor WebAssembly projects.
Use the `-u` (or `--ui`) option to specify the UI framework while creating the solution:
```bash
abp new Acme.BookStore -t app-nolayers -u angular
```
This example specifies the UI type (the `-u` option) as `angular`. You can also specify `mvc`, `blazor-server` or `none` for the UI type.
### Specify the Database Provider
This template supports the following database providers:
- `ef`: Entity Framework Core (default)
- `mongodb`: MongoDB
Use the `-d` (or `--database-provider`) option to specify the database provider while creating the solution:
```bash
abp new Acme.BookStore -t app-nolayers -d mongodb
```
## Solution Structure
If you don't specify any additional options while creating an `app-nolayers` template, you will have a solution as shown below:
![](../images/bookstore-single-layer-solution-structure.png)
In the next sections, we will explain the structure based on this example. Your startup solution can be slightly different based on your preferences.
### Folder Structure
Since this template provides a single-project solution, we've separated concerns into folders instead of projects. You can see the pre-defined folders as shown below:
![](../images/single-layer-folder-structure.png)
* Define your database mappings (for [EF Core](../Entity-Framework-Core.md) or [MongoDB](../MongoDB.md)) and [repositories](../Repositories.md) in the `Data` folder.
* Define your [entities](../Entities.md) in the `Entities` folder.
* Define your UI localization keys/values in the `Localization` folder.
* Define your UI menu items in the `Menus` folder.
* Define your [object-to-object mapping](../Object-To-Object-Mapping.md) classes in the `ObjectMapping` folder.
* Define your UI pages (Razor Pages) in the `Pages` folder (create `Controllers` and `Views` folder yourself if you prefer the MVC pattern).
* Define your [application services](../Application-Services.md) in the `Services` folder.
### How to Run?
Before running the application, you need to create the database and seed the initial data. To do that, you can run the following command in the directory of your project (in the same folder of the `.csproj` file):
```bash
dotnet run --migrate-database
```
This command will create the database and seed the initial data for you. Then you can run the application with any IDE that supports .NET or by running the `dotnet run` command in the directory of your project. The default username is `admin` and the password is `1q2w3E*`.
> While creating a database & applying migrations seem only necessary for relational databases, you should run this command even if you choose a NoSQL database provider (like MongoDB). In that case, it still seeds the initial data which is necessary for the application.
### The Angular UI
If you choose `Angular` as the UI framework, the solution will be separated into two folders:
* An `angular` folder that contains the Angular UI application, the client-side code.
* An `aspnet-core` folder that contains the ASP.NET Core solution (a single project), the server-side code.
The server-side is similar to the solution described in the *Solution Structure* section above. This project serves the API, so the Angular application can consume it.
The client-side application consumes the HTTP APIs as mentioned. You can see the folder structure of the Angular project shown below:
![](../images/single-layer-angular-folder-structure.png)

106
docs/en/Startup-Templates/Application.md

@ -13,7 +13,7 @@ This document explains **the solution structure** and projects in details. If yo
You can use the [ABP CLI](../CLI.md) to create a new project using this startup template. Alternatively, you can directly create & download from the [Get Started](https://abp.io/get-started) page. CLI approach is used here.
First, install the ABP CLI if you haven't installed before:
First, install the ABP CLI if you haven't installed it before:
````bash
dotnet tool install -g Volo.Abp.Cli
@ -25,8 +25,8 @@ Then use the `abp new` command in an empty folder to create a new solution:
abp new Acme.BookStore -t app
````
* `Acme.BookStore` is the solution name, like *YourCompany.YourProduct*. You can use single level, two-levels or three-levels naming.
* This example specified the template name (`-t` or `--template` option). However, `app` is already the default template if you don't specify it.
* `Acme.BookStore` is the solution name, like *YourCompany.YourProduct*. You can use single-level, two-level or three-level naming.
* This example specified the template name (`-t` or `--template` option). However, `app` is already the default template if you didn't specify it.
### Specify the UI Framework
@ -36,7 +36,7 @@ This template provides multiple UI frameworks:
* `blazor`: Blazor UI
* `angular`: Angular UI
Use `-u` or `--ui` option to specify the UI framework:
Use the `-u` or `--ui` option to specify the UI framework:
````bash
abp new Acme.BookStore -u angular
@ -61,7 +61,7 @@ This template supports the following mobile application frameworks:
- `react-native`: React Native
Use `-m` (or `--mobile`) option to specify the mobile application framework:
Use the `-m` (or `--mobile`) option to specify the mobile application framework:
````bash
abp new Acme.BookStore -m react-native
@ -75,7 +75,7 @@ Based on the options you've specified, you will get a slightly different solutio
### Default Structure
If you don't specify any additional option, you will have a solution like shown below:
If you don't specify any additional options, you will have a solution as shown below:
![bookstore-visual-studio-solution-v3](../images/bookstore-visual-studio-solution-v3.png)
@ -93,7 +93,7 @@ This project contains constants, enums and other objects these are actually a pa
A `BookType` enum and a `BookConsts` class (which may have some constant fields for the `Book` entity, like `MaxNameLength`) are good candidates for this project.
* This project has no dependency to other projects in the solution. All other projects depend on this directly or indirectly.
* This project has no dependency on other projects in the solution. All other projects depend on this one directly or indirectly.
#### .Domain Project
@ -105,7 +105,7 @@ A `Book` entity, a `BookManager` domain service and an `IBookRepository` interfa
#### .Application.Contracts Project
This project mainly contains [application service](../Application-Services.md) **interfaces** and [Data Transfer Objects](../Data-Transfer-Objects.md) (DTO) of the application layer. It does exists to separate interface & implementation of the application layer. In this way, the interface project can be shared to the clients as a contract package.
This project mainly contains [application service](../Application-Services.md) **interfaces** and [Data Transfer Objects](../Data-Transfer-Objects.md) (DTO) of the application layer. It exists to separate the interface & implementation of the application layer. In this way, the interface project can be shared to the clients as a contract package.
An `IBookAppService` interface and a `BookCreationDto` class are good candidates for this project.
@ -130,7 +130,7 @@ This is the integration project for the EF Core. It defines the `DbContext` and
#### .DbMigrator Project
This is a console application which simplifies to execute database migrations on development and production environments. When you run this application, it;
This is a console application that simplifies the execution of database migrations on development and production environments. When you run this application, it:
* Creates the database if necessary.
* Applies the pending database migrations.
@ -140,24 +140,24 @@ This is a console application which simplifies to execute database migrations on
Especially, seeding initial data is important at this point. ABP has a modular data seed infrastructure. See [its documentation](../Data-Seeding.md) for more about the data seeding.
While creating database & applying migrations seems only necessary for relational databases, this projects comes even if you choose a NoSQL database provider (like MongoDB). In that case, it still seeds initial data which is necessary for the application.
While creating database & applying migrations seem only necessary for relational databases, this project comes even if you choose a NoSQL database provider (like MongoDB). In that case, it still seeds the initial data which is necessary for the application.
* Depends on the `.EntityFrameworkCore` project (for EF Core) since it needs to access to the migrations.
* Depends on the `.Application.Contracts` project to be able to access permission definitions, because initial data seeder grants all permissions for the admin role by default.
* Depends on the `.Application.Contracts` project to be able to access permission definitions, because the initial data seeder grants all permissions to the admin role by default.
#### .HttpApi Project
This project is used to define your API Controllers.
Most of time you don't need to manually define API Controllers since ABP's [Auto API Controllers](../API/Auto-API-Controllers.md) feature creates them automagically based on your application layer. However, in case of you need to write API controllers, this is the best place to do it.
Most of the time you don't need to manually define API Controllers since ABP's [Auto API Controllers](../API/Auto-API-Controllers.md) feature creates them automagically based on your application layer. However, in case of you need to write API controllers, this is the best place to do it.
* Depends on the `.Application.Contracts` project to be able to inject the application service interfaces.
#### .HttpApi.Client Project
This is a project that defines C# client proxies to use the HTTP APIs of the solution. You can share this library to 3rd-party clients, so they can easily consume your HTTP APIs in their Dotnet applications (For other type of applications, they can still use your APIs, either manually or using a tool in their own platform)
This is a project that defines C# client proxies to use the HTTP APIs of the solution. You can share this library to 3rd-party clients, so they can easily consume your HTTP APIs in their Dotnet applications (For other types of applications, they can still use your APIs, either manually or using a tool in their own platform)
Most of time you don't need to manually create C# client proxies, thanks to ABP's [Dynamic C# API Clients](../API/Dynamic-CSharp-API-Clients.md) feature.
Most of the time you don't need to manually create C# client proxies, thanks to ABP's [Dynamic C# API Clients](../API/Dynamic-CSharp-API-Clients.md) feature.
`.HttpApi.Client.ConsoleTestApp` project is a console application created to demonstrate the usage of the client proxies.
@ -169,17 +169,17 @@ Most of time you don't need to manually create C# client proxies, thanks to ABP'
This project contains the User Interface (UI) of the application if you are using ASP.NET Core MVC UI. It contains Razor pages, JavaScript files, CSS files, images and so on...
This project contains the main `appsettings.json` file that contains the connection string and other configuration of the application.
This project contains the main `appsettings.json` file that contains the connection string and other configurations of the application.
* Depends on the `.HttpApi` since UI layer needs to use APIs and application service interfaces of the solution.
* Depends on the `.HttpApi` project since the UI layer needs to use APIs and the application service interfaces of the solution.
> If you check the source code of the `.Web.csproj` file, you will see the references to the `.Application` and the `.EntityFrameworkCore` projects.
>
> These references are actually not needed while coding your UI layer, because UI layer normally doesn't depend on the EF Core or the Application layer's implementation. This startup templates are ready for the tiered deployment, where API layer is hosted in a separate server than the UI layer.
> These references are actually not needed while coding your UI layer, because the UI layer normally doesn't depend on the EF Core or the Application layer's implementation. These startup templates are ready for tiered deployment, where the API layer is hosted on a separate server than the UI layer.
>
> However, if you don't choose the `--tiered` option, these references will be in the .Web project to be able to host the Web, API and application layers in a single application endpoint.
>
> This gives you to ability to use domain entities & repositories in your presentation layer. However, this is considered as a bad practice according to the DDD.
> This gives you the ability to use domain entities & repositories in your presentation layer. However, this is considered as a bad practice according to DDD.
#### Test Projects
@ -195,46 +195,46 @@ In addition, `.HttpApi.Client.ConsoleTestApp` is a console application (not an a
Test projects are prepared for integration testing;
* It is fully integrated to ABP framework and all services in your application.
* It is fully integrated into the ABP framework and all services in your application.
* It uses SQLite in-memory database for EF Core. For MongoDB, it uses the [Mongo2Go](https://github.com/Mongo2Go/Mongo2Go) library.
* Authorization is disabled, so any application service can be easily used in tests.
You can still create unit tests for your classes which will be harder to write (because you will need to prepare mock/fake objects), but faster to run (because it only tests a single class and skips all initialization process).
You can still create unit tests for your classes which will be harder to write (because you will need to prepare mock/fake objects), but faster to run (because it only tests a single class and skips all the initialization processes).
#### How to Run?
Set `.Web` as the startup project and run the application. Default username is `admin` and password is `1q2w3E*`.
Set `.Web` as the startup project and run the application. The default username is `admin` and the password is `1q2w3E*`.
See [Getting Started With the ASP.NET Core MVC Template](../Getting-Started-AspNetCore-MVC-Template.md) for more information.
### Tiered Structure
If you have selected the ASP.NET Core UI and specified the `--tiered` option, the solution created will be a tiered solution. The purpose of the tiered structure is to be able to **deploy Web application and HTTP API to different servers**:
If you have selected the ASP.NET Core UI and specified the `--tiered` option, the solution created will be a tiered solution. The purpose of the tiered structure is to be able to **deploy Web applications and HTTP API to different servers**:
![bookstore-visual-studio-solution-v3](../images/tiered-solution-servers.png)
* Browser runs your UI by executing HTML, CSS & JavaScript.
* Web servers hosts static UI files (CSS, JavaScript, image... etc.) & dynamic components (e.g. Razor pages). It performs HTTP requests to the API server to execute the business logic of the application.
* API Server hosts the HTTP APIs which then use application & domain layers of the application to perform the business logic.
* Web servers host static UI files (CSS, JavaScript, image... etc.) & dynamic components (e.g. Razor pages). It performs HTTP requests to the API server to execute the business logic of the application.
* The API Server hosts the HTTP APIs which then use the application & domain layers of the application to perform the business logic.
* Finally, database server hosts your database.
So, the resulting solution allows a 4-tiered deployment, by comparing to 3-tiered deployment of the default structure explained before.
> Unless you actually need to such a 4-tiered deployment, its suggested to go with the default structure which is simpler to develop, deploy and maintain.
> Unless you actually need such a 4-tiered deployment, it's suggested to go with the default structure which is simpler to develop, deploy and maintain.
The solution structure is shown below:
![bookstore-visual-studio-solution-v3](../images/bookstore-visual-studio-solution-tiered.png)
As different from the default structure, two new projects come into play: `.IdentityServer` & `.HttpApi.Host`.
As different from the default structure, two new projects come into play: `.AuthServer` & `.HttpApi.Host`.
#### .IdentityServer Project
#### .AuthServer Project
This project is used as an authentication server for other projects. `.Web` project uses OpenId Connect Authentication to get identity and access tokens for the current user from the IdentityServer. Then uses the access token to call the HTTP API server. HTTP API server uses bearer token authentication to obtain claims from the access token to authorize the current user.
This project is used as an authentication server for other projects. `.Web` project uses OpenId Connect Authentication to get identity and access tokens for the current user from the AuthServer. Then uses the access token to call the HTTP API server. HTTP API server uses bearer token authentication to obtain claims from the access token to authorize the current user.
![tiered-solution-applications](../images/tiered-solution-applications.png)
ABP uses the open source [IdentityServer4](https://identityserver.io/) framework for the authentication between applications. See [IdentityServer4 documentation](http://docs.identityserver.io) for details about the IdentityServer4 and OpenID Connect protocol.
ABP uses the open source [OpenIddcit](https://github.com/openiddict/openiddict-core) framework for the authentication between applications. See [OpenIddcit documentation](https://documentation.openiddict.com/) for details about the OpenIddict and OpenID Connect protocol.
It has its own `appsettings.json` that contains database connection and other configurations.
@ -246,17 +246,17 @@ This project is an application that hosts the API of the solution. It has its ow
Just like the default structure, this project contains the User Interface (UI) of the application. It contains razor pages, JavaScript files, style files, images and so on...
This project contains an `appsettings.json` file, but this time it does not have a connection string because it never connects to the database. Instead, it mainly contains endpoint of the remote API server and the authentication server.
This project contains an `appsettings.json` file, but this time it does not have a connection string because it never connects to the database. Instead, it mainly contains the endpoint of the remote API server and the authentication server.
#### Pre-requirements
* [Redis](https://redis.io/): The applications use Redis as as distributed cache. So, you need to have Redis installed & running.
* [Redis](https://redis.io/): The applications use Redis as a distributed cache. So, you need to have Redis installed & running.
#### How to Run?
You should run the application with the given order:
* First, run the `.IdentityServer` since other applications depends on it.
* First, run the `.AuthServer` since other applications depend on it.
* Then run the `.HttpApi.Host` since it is used by the `.Web` application.
* Finally, you can run the `.Web` project and login to the application (using `admin` as the username and `1q2w3E*` as the password).
@ -286,9 +286,9 @@ Angular application module structure:
#### AppModule
`AppModule` is the root module of the application. Some of ABP modules and some essential modules imported to the `AppModule`.
`AppModule` is the root module of the application. Some of the ABP modules and some essential modules are imported to `AppModule`.
ABP Config modules also have imported to `AppModule`  for initially requirements of lazy-loadable ABP modules.
ABP Config modules have also been imported to `AppModule` for initial requirements of the lazy-loadable ABP modules.
#### AppRoutingModule
@ -315,22 +315,22 @@ You should add `routes` property in the `data` object to add a link on the menu
```
In the above example;
* If the user is not logged in, AuthGuard blocks access and redirects to the login page.
* PermissionGuard checks the user's permission with `requiredPolicy` property of the `rotues` object. If the user is not authorized to access the page, the 403 page appears.
* `name` property of `routes` is the menu link label. A localization key can be defined .
* `iconClass` property of `routes` object is the menu link icon class.
* `requiredPolicy` property of `routes` object is the required policy key to access the page.
* PermissionGuard checks the user's permission with the `requiredPolicy` property of the `routes` object. If the user is not authorized to access the page, the 403 page appears.
* The `name` property of `routes` is the menu link label. A localization key can be defined.
* The `iconClass` property of the `routes` object is the menu link icon class.
* The `requiredPolicy` property of the `routes` object is the required policy key to access the page.
After the above `routes` definition, if the user is authorized, the dashboard link will appear on the menu.
#### Shared Module
The modules that may be required for all modules have imported to the `SharedModule`. You should import the `SharedModule` to all modules.
The modules that may be required for all modules have been imported to the `SharedModule`. You should import `SharedModule` to all modules.
See the [Sharing Modules](https://angular.io/guide/sharing-ngmodules) document.
#### Environments
The files under the `src/environments` folder has the essential configuration of the application.
The files under the `src/environments` folder have the essential configuration of the application.
#### Home Module
@ -338,11 +338,11 @@ Home module is an example lazy-loadable module that loads on the root address of
#### Styles
The required style files added to `styles` array in the `angular.json`. `AppComponent` loads some style files lazily via `LazyLoadService` after the main bundle is loaded to shorten the first rendering time.
The required style files are added to the `styles` array in `angular.json`. `AppComponent` loads some style files lazily via `LazyLoadService` after the main bundle is loaded to shorten the first rendering time.
#### Testing
You should create your tests in the same folder as the file file you want to test.
You should create your tests in the same folder as the file you want to test.
See the [testing document](https://angular.io/guide/testing).
@ -356,7 +356,7 @@ See the [testing document](https://angular.io/guide/testing).
### React Native
if `-m react-native` option is spesified in new project command, the solution includes the [React Native](https://reactnative.dev/) application in the `react-native` folder.
If the `-m react-native` option is specified in the new project command, the solution includes the [React Native](https://reactnative.dev/) application in the `react-native` folder.
The server-side is similar to the solution described above. `*.HttpApi.Host` project serves the API, so the React Native application consumes it.
@ -366,17 +366,17 @@ React Native application folder structure as like below:
![react-native-folder-structure](../images/react-native-folder-structure.png)
* `App.js` is bootstrap component of the application.
* `Environment.js` file has the essential configuration of the application. `prod` and `dev` configurations defined in this file.
* `App.js` is the bootstrap component of the application.
* `Environment.js` file has the essential configuration of the application. `prod` and `dev` configurations are defined in this file.
* [Contexts](https://reactjs.org/docs/context.html) are created in the `src/contexts` folder.
* [Higher order components](https://reactjs.org/docs/higher-order-components.html) are created in the`src/hocs` folder.
* [Custom hooks](https://reactjs.org/docs/hooks-custom.html#extracting-a-custom-hook) are created in the`src/hooks`.
* [Higher order components](https://reactjs.org/docs/higher-order-components.html) are created in the `src/hocs` folder.
* [Custom hooks](https://reactjs.org/docs/hooks-custom.html#extracting-a-custom-hook) are created in `src/hooks`.
* [Axios interceptors](https://github.com/axios/axios#interceptors) are created in the `src/interceptors` folder.
* Utility functions are exported from `src/utils` folder.
#### Components
Components that can be used on all screens are created in the `src/components` folder. All components have created as a function that able to use [hooks](https://reactjs.org/docs/hooks-intro.html).
Components that can be used on all screens are created in the `src/components` folder. All components have been created as a function that is able to use [hooks](https://reactjs.org/docs/hooks-intro.html).
#### Screens
@ -388,13 +388,13 @@ Each screen is used in a navigator in the `src/navigators` folder.
#### Navigation
[React Navigation](https://reactnavigation.org/) is used as a navigation library. Navigators are created in the `src/navigators`. A [drawer](https://reactnavigation.org/docs/drawer-based-navigation/) navigator and several [stack](https://reactnavigation.org/docs/hello-react-navigation/#installing-the-stack-navigator-library) navigators have created in this folder. See the [above diagram](#screens) for navigation structure.
[React Navigation](https://reactnavigation.org/) is used as a navigation library. Navigators are created in the `src/navigators`. A [drawer](https://reactnavigation.org/docs/drawer-based-navigation/) navigator and several [stack](https://reactnavigation.org/docs/hello-react-navigation/#installing-the-stack-navigator-library) navigators have been created in this folder. See the [above diagram](#screens) for the navigation structure.
#### State Management
[Redux](https://redux.js.org/) is used as state management library. [Redux Toolkit](https://redux-toolkit.js.org/) library is used as a toolset for efficient Redux development.
[Redux](https://redux.js.org/) is used as a state management library. [Redux Toolkit](https://redux-toolkit.js.org/) library is used as a toolset for efficient Redux development.
Actions, reducers, sagas, selectors are created in the `src/store` folder. Store folder as like below:
Actions, reducers, sagas and selectors are created in the `src/store` folder. Store folder is as below:
![react-native-store-folder](../images/react-native-store-folder.png)
@ -426,11 +426,11 @@ See the [Testing Overview](https://reactjs.org/docs/testing.html) document.
* [Native Base](https://nativebase.io/) is used as UI components library.
* [React Navigation](https://reactnavigation.org/) is used as navigation library.
* [Axios](https://github.com/axios/axios) is used as HTTP client library.
* [Axios](https://github.com/axios/axios) is used as an HTTP client library.
* [Redux](https://redux.js.org/) is used as state management library.
* [Redux Toolkit](https://redux-toolkit.js.org/) library is used as a toolset for efficient Redux development.
* [Redux-Saga](https://redux-saga.js.org/) is used to manage asynchronous processes.
* [Redux Persist](https://github.com/rt2zz/redux-persist) is used as state persistance.
* [Redux Persist](https://github.com/rt2zz/redux-persist) is used as state persistence.
* [Reselect](https://github.com/reduxjs/reselect) is used to create memoized selectors.
* [i18n-js](https://github.com/fnando/i18n-js) is used as i18n library.
* [expo-font](https://docs.expo.io/versions/latest/sdk/font/) library allows loading fonts easily.

8
docs/en/Startup-Templates/Module.md

@ -139,7 +139,7 @@ Set `host/YourProjectName.Web.Unified` as the startup project, run `Update-Datab
In this scenario, there are three applications;
* `.IdentityServer` application is an authentication server used by other applications. It has its own `appsettings.json` that contains database connection and other configurations.
* `.AuthServer` application is an authentication server used by other applications. It has its own `appsettings.json` that contains database connection and other configurations.
* `.HttpApi.Host` hosts the HTTP API of the module. It has its own `appsettings.json` that contains database connections and other configurations.
* `.Web.Host` host the UI of the module. This project contains an `appsettings.json` file, but it does not have a connection string because it never connects to the database. Instead, it mainly contains endpoint of the remote API server and the authentication server.
@ -147,7 +147,7 @@ The diagram below shows the relation of the applications:
![tiered-solution-applications](../images/tiered-solution-applications.png)
`.Web.Host` project uses OpenId Connect Authentication to get identity and access tokens for the current user from the `.IdentityServer`. Then uses the access token to call the `.HttpApi.Host`. HTTP API server uses bearer token authentication to obtain claims from the access token to authorize the current user.
`.Web.Host` project uses OpenId Connect Authentication to get identity and access tokens for the current user from the `.AuthServer`. Then uses the access token to call the `.HttpApi.Host`. HTTP API server uses bearer token authentication to obtain claims from the access token to authorize the current user.
##### Pre-requirements
@ -157,7 +157,7 @@ The diagram below shows the relation of the applications:
You should run the application with the given order:
- First, run the `.IdentityServer` since other applications depends on it.
- First, run the `.AuthServer` since other applications depends on it.
- Then run the `.HttpApi.Host` since it is used by the `.Web.Host` application.
- Finally, you can run the `.Web.Host` project and login to the application using `admin` as the username and `1q2w3E*` as the password.
@ -195,7 +195,7 @@ The module you will develop depends on two of these ABP packages: _@abp/ng.core_
Once all dependencies are installed, follow the steps below to serve your development app:
1. Make sure `.IdentityServer` and `*.HttpApi.Host` projects are up and running.
1. Make sure `.AuthServer` and `*.HttpApi.Host` projects are up and running.
2. Open your terminal at the root folder, i.e. `angular`.
3. Run `yarn start` or `npm start`.

2
docs/en/Themes/LeptonXLite/angular.md

@ -79,4 +79,4 @@ To change the logos and brand color of `LeptonX`, simply add the following CSS t
### Server Side
In order to migrate to LeptonX on your server side projects (Host and/or IdentityServer projects), please follow the [Server Side Migration](mvc.md) document.
In order to migrate to LeptonX on your server side projects (Host and/or AuthServer projects), please follow the [Server Side Migration](mvc.md) document.

37
docs/en/Themes/LeptonXLite/blazor.md

@ -16,19 +16,25 @@ LeptonX Lite has implementation for the ABP Framework Blazor WebAssembly & Blazo
## Installation
{{if UI == "Blazor"}}
- Complete the [MVC Razor Pages Installation](mvc.md#installation) for the **HttpApi.Host** application first. _If the solution is tiered/micro-service, complete the MVC steps for all MVC applications such as **HttpApi.Host** and if identity server is separated, install to the **IdentityServer**_.
- Complete the [MVC Razor Pages Installation](mvc.md#installation) for the **HttpApi.Host** application first. _If the solution is tiered/micro-service, complete the MVC steps for all MVC applications such as **HttpApi.Host** and if identity server is separated, install to the **OpenIddict**_.
- Add **Volo.Abp.AspNetCore.Components.WebAssembly.LeptonXLiteTheme** package to your **Blazor WebAssembly** application with the following command:
- Add **Volo.Abp.AspNetCore.Components.WebAssembly.LeptonXLiteTheme** package to your **Blazor WebAssembly** application.
```bash
dotnet add package Volo.Abp.AspNetCore.Components.WebAssembly.LeptonXLiteTheme
dotnet add package Volo.Abp.AspNetCore.Components.WebAssembly.LeptonXLiteTheme --prerelease
```
- Remove **Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme** reference from the project since it's not necessary after switching to LeptonX Lite.
- Remove the old theme from the **DependsOn** attribute in your module class and add the **AbpAspNetCoreComponentsWebAssemblyLeptonXLiteThemeModule** type to the **DependsOn** attribute.
```diff
[DependsOn(
// Remove BasicTheme module from DependsOn attribute
- typeof(AbpAspNetCoreComponentsWebAssemblyBasicThemeModule),
+ typeof(AbpAspNetCoreComponentsWebAssemblyLeptonXLiteThemeModule)
// Add LeptonX Lite module to DependsOn attribute
+ typeof(AbpAspNetCoreComponentsWebAssemblyLeptonXLiteThemeModule),
)]
```
@ -46,26 +52,35 @@ builder.RootComponents.Add<App>("#ApplicationContainer");
{{if UI == "BlazorServer"}}
- Complete the [MVC Razor Pages Installation](mvc.md#installation) first. _If the solution is tiered/micro-service, complete the MVC steps for all MVC applications such as **HttpApi.Host** and **IdentityServer**_.
- Complete the [MVC Razor Pages Installation](mvc.md#installation) first. _If the solution is tiered/micro-service, complete the MVC steps for all MVC applications such as **HttpApi.Host** and **AuthServer**_.
- Add **Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme** package to your **Blazor server** application with the following command:
- Add **Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme** package to your **Blazor server** application.
```bash
dotnet add package Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme
dotnet add package Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme --prerelease
```
- Remove old theme from the **DependsOn** attribute in your module class and add the **AbpAspNetCoreComponentsWebAssemblyLeptonXLiteThemeModule** type to the **DependsOn** attribute.
- Remove **Volo.Abp.AspNetCore.Components.Server.BasicTheme** reference from the project since it's not necessary after switching to LeptonX Lite.
- Remove old theme from the **DependsOn** attribute in your module class and add the **AbpAspNetCoreComponentsServerLeptonXLiteThemeModule** type to the **DependsOn** attribute.
```diff
[DependsOn(
// Remove BasicTheme module from DependsOn attribute
- typeof(AbpAspNetCoreComponentsServerBasicThemeModule),
// Add LeptonX Lite module to DependsOn attribute
+ typeof(AbpAspNetCoreComponentsServerLeptonXLiteThemeModule)
)]
```
- Update AbpBundlingOptions
- Replace `BlazorBasicThemeBundles` with `BlazorLeptonXLiteThemeBundles` in `AbpBundlingOptions`:
```diff
options.StyleBundles.Configure(
// Remove following line
- BlazorBasicThemeBundles.Styles.Global,
// Add following line instead
+ BlazorLeptonXLiteThemeBundles.Styles.Global,
bundle =>
{
@ -84,12 +99,16 @@ builder.RootComponents.Add<App>("#ApplicationContainer");
```
- Then replace script & style bundles as following:
```diff
// Remove following line
- <abp-style-bundle name="@BlazorBasicThemeBundles.Styles.Global" />
// Add following line instead
+ <abp-style-bundle name="@BlazorLeptonXLiteThemeBundles.Styles.Global" />
```
```diff
// Remove following line
- <abp-script-bundle name="@BlazorBasicThemeBundles.Scripts.Global" />
// Add following line instead
+ <abp-script-bundle name="@BlazorLeptonXLiteThemeBundles.Scripts.Global" />
```

13
docs/en/Themes/LeptonXLite/mvc.md

@ -10,25 +10,32 @@ LeptonX Lite has implementation for the ABP Framework Razor Pages. It's a simpli
- Add **Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite** package to your **Web** application.
```bash
abp add-package Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite
dotnet add package Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite --prerelease
```
- Remove **Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic** reference from the project since it's not necessary after switching to LeptonX Lite.
- Make sure the old theme is removed and LeptonX is added in your Module class.
```diff
[DependsOn(
// Remove BasicTheme module from DependsOn attribute
- typeof(AbpAspNetCoreMvcUiBasicThemeModule),
+ typeof(AbpAspNetCoreMvcUiLeptonXLiteThemeModule)
// Add LeptonX Lite module to DependsOn attribute
+ typeof(AbpAspNetCoreMvcUiLeptonXLiteThemeModule),
)]
```
- Update AbpBundlingOptions
- Replace `BasicThemeBundles` with `LeptonXLiteThemeBundles` in AbpBundlingOptions
```diff
Configure<AbpBundlingOptions>(options =>
{
options.StyleBundles.Configure(
// Remove following line
- BasicThemeBundles.Styles.Global,
// Add following line instead
+ LeptonXLiteThemeBundles.Styles.Global
bundle =>
{

15
docs/en/Tutorials/Todo/Index.md

@ -17,6 +17,7 @@ You can find the source code of the completed application [here](https://github.
## Pre-Requirements
* An IDE (e.g. [Visual Studio](https://visualstudio.microsoft.com/vs/)) that supports [.NET 6.0+](https://dotnet.microsoft.com/download/dotnet) development.
* [Node v14.x](https://nodejs.org/)
{{if DB=="Mongo"}}
@ -24,12 +25,6 @@ You can find the source code of the completed application [here](https://github.
{{end}}
{{if UI=="NG"}}
* [Node v14.x](https://nodejs.org/)
{{end}}
## Creating a New Solution
We will use the [ABP CLI](../../CLI.md) to create new solutions with the ABP Framework. You can run the following command in a command-line terminal to install it:
@ -96,13 +91,7 @@ Ensure that the `TodoApp.HttpApi.Host` project is the startup project, then run
You can explore and test your HTTP API with this UI. If it works, we can run the Angular client application.
First, run the following command to restore the NPM packages;
````bash
npm install
````
It will take some time to install all the packages. Then you can run the application using the following command:
You can run the application using the following command:
````bash
npm start

14
docs/en/Tutorials/Todo/Overall.md

@ -0,0 +1,14 @@
# Quick Start: Overall
**Welcome to the ABP Framework**. This is a single-part, quick-start tutorial to build a simple application. Start with this tutorial if you want to quickly understand how ABP Framework works.
## Select the Solution Architecture
This tutorial has multiple versions. Please select the one best fits for you:
* **[Single-Layer Solution](Single-Layer/Index.md)**: Creates a single-project solution. Recommended for building an application with a **simpler and easy to understand** architecture.
* **[Layered Solution Architecture](Index.md)**: A fully layered (multiple projects) solution based on [Domain Driven Design](../../Domain-Driven-Design.md) practices. Recommended for long-term projects that need a **maintainable and extensible** codebase.
## See Also
* Check the [Web Application Development Tutorial](../Part-1.md) to see a real-life web application development in a layered architecture.

755
docs/en/Tutorials/Todo/Single-Layer/Index.md

@ -0,0 +1,755 @@
# Quick Start
````json
//[doc-params]
{
"UI": ["MVC", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"]
}
````
This is a single-part quick-start tutorial to build a simple todo application with the ABP Framework. Here's a screenshot from the final application:
![todo-list](../todo-list.png)
You can find the source code of the completed application [here](https://github.com/abpframework/abp-samples/tree/master/TodoApp-SingleLayer).
## Pre-Requirements
* An IDE (e.g. [Visual Studio](https://visualstudio.microsoft.com/vs/)) that supports [.NET 6.0+](https://dotnet.microsoft.com/download/dotnet) development.
* [Node v14.x](https://nodejs.org/)
{{if DB=="Mongo"}}
* [MongoDB Server 4.0+](https://docs.mongodb.com/manual/administration/install-community/)
{{end}}
## Creating a New Solution
In this tutorial, we will use the [ABP CLI](../../../CLI.md) to create the sample application with the ABP Framework. You can run the following command in a command-line terminal to install the **ABP CLI**, if you haven't installed it yet:
````bash
dotnet tool install -g Volo.Abp.Cli
````
Then create an empty folder, open a command-line terminal and execute the following command in the terminal:
````bash
abp new TodoApp -t app-nolayers{{if UI=="BlazorServer"}} -u blazor-server{{else if UI=="NG"}} -u angular{{end}}{{if DB=="Mongo"}} -d mongodb{{end}}
````
{{if UI=="NG"}}
This will create a new solution, named *TodoApp*, with `angular` and `aspnet-core` folders. Once the solution is ready, open the solution (in the `aspnet-core` folder) with your favorite IDE.
{{else}}
This will create a new solution with a single project, named *TodoApp*. Once the solution is ready, open it in your favorite IDE.
{{end}}
### Create the Database
You can run the following command in the root directory of your project (in the same folder of the `.csproj` file) to create the database and seed the initial data:
```bash
dotnet run --migrate-database
```
This command will create the database and seed the initial data for you. Then you can run the application.
### Run the Application
{{if UI=="MVC" || UI=="BlazorServer"}}
It is good to run the application before starting the development. Running the application is pretty straight-forward, you can run the application with any IDE that supports .NET or by running the `dotnet run` CLI command in the directory of your project:
{{else if UI=="NG"}}
It is good to run the application before starting the development. The solution has two main applications:
* `TodoApp` (in the .NET solution) hosts the server-side HTTP API, so the Angular application can consume it. (server-side application)
* `angular` folder contains the Angular application. (client-side application)
Firstly, run the `TodoApp` project in your favorite IDE (or run the `dotnet run` CLI command on your project directory) to see the server-side HTTP API on [Swagger UI](https://swagger.io/tools/swagger-ui/):
![todo-swagger-ui-initial](../todo-swagger-ui-initial.png)
You can explore and test your HTTP API with this UI. If it works, then we can run the Angular client application.
You can run the application using the following (or `yarn start`) command:
````bash
npm start
````
This command takes time, but eventually runs and opens the application in your default browser:
{{end}}
![todo-ui-initial](../todo-ui-initial.png)
You can click on the *Login* button and use `admin` as the username and `1q2w3E*` as the password to login to the application.
All right. We can start coding!
## Defining the Entity
This application will have a single [entity](../../../Entities.md) and we can start by creating it. So, create a new `TodoItem` class under the `Entities` folder of the project:
````csharp
using Volo.Abp.Domain.Entities;
namespace TodoApp.Entities;
public class TodoItem : BasicAggregateRoot<Guid>
{
public string Text { get; set; }
}
````
`BasicAggregateRoot` is the simplest base class to create root entities, and `Guid` is the primary key (`Id`) of the entity here.
## Database Integration
{{if DB=="EF"}}
Next step is to setup the [Entity Framework Core](../../../Entity-Framework-Core.md) configuration.
### Mapping Configuration
Open the `TodoAppDbContext` class (in the `Data` folder) and add a new `DbSet` property to this class:
````csharp
public DbSet<TodoItem> TodoItems { get; set; }
````
Then navigate to the `OnModelCreating` method in the same class and add the following mapping code for the `TodoItem ` entity:
````csharp
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.ConfigurePermissionManagement();
...
/* Configure your own tables/entities inside here */
builder.Entity<TodoItem>(b =>
{
b.ToTable("TodoItems");
});
}
````
We've mapped the `TodoItem` entity to the `TodoItems` table in the database. The next step is to create a migration and apply the changes to the database.
### Code First Migrations
The startup solution is configured to use Entity Framework Core [Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations). Since we've changed the database mapping configuration, we should create a new migration and apply changes to the database.
Open a command-line terminal in the root directory of your project and type the following command:
````bash
dotnet ef migrations add Added_TodoItem
````
This will add a new migration class to the project. You should see the new migration in the `Migrations` folder:
![todo-efcore-migration](todo-efcore-migration-single-layer.png)
Then, you can apply changes to the database using the following command, in the same command-line terminal:
````bash
dotnet ef database update
````
{{else if DB=="Mongo"}}
The next step is to setup the [MongoDB](../../../MongoDB.md) configuration. Open the `TodoAppDbContext` class (under the **Data** folder) in your project and make the following changes:
1. Add a new property to the class:
````csharp
public IMongoCollection<TodoItem> TodoItems => Collection<TodoItem>();
````
2. Add the following code inside the `CreateModel` method:
````csharp
modelBuilder.Entity<TodoItem>(b =>
{
b.CollectionName = "TodoItems";
});
````
{{end}}
After the database integrations, now we can start to create application service methods and implement our use-cases.
## Creating the Application Service
An [application service](../../../Application-Services.md) is used to perform the use cases of the application. We need to perform the following use cases in this application:
* Get the list of the todo items
* Create a new todo item
* Delete an existing todo item
Before starting to implement these use cases, first we need to create a DTO class that will be used in the application service.
### Creating the Data Transfer Object (DTO)
[Application services](../../../Application-Services.md) typically get and return DTOs ([Data Transfer Objects](../../../Data-Transfer-Objects.md)) instead of entities. So, create a new `TodoItemDto` class under the `Services/Dtos` folder:
```csharp
namespace TodoApp.Services.Dtos;
public class TodoItemDto
{
public Guid Id { get; set; }
public string Text { get; set; }
}
```
This is a very simple DTO class that has the same properties as the `TodoItem` entity. Now, we are ready to implement our use-cases.
### The Application Service Implementation
Create a `TodoAppService` class under the `Services` folder of your project, as shown below:
```csharp
using TodoApp.Entities;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace TodoApp.Services;
public class TodoAppService : ApplicationService
{
private readonly IRepository<TodoItem, Guid> _todoItemRepository;
public TodoAppService(IRepository<TodoItem, Guid> todoItemRepository)
{
_todoItemRepository = todoItemRepository;
}
// TODO: Implement the methods here...
}
```
This class inherits from the `ApplicationService` class of the ABP Framework and implements our use-cases. ABP provides default generic [repositories](../../../Repositories.md) for the entities. We can use them to perform the fundamental database operations. This class [injects](../../../Dependency-Injection.md) `IRepository<TodoItem, Guid>`, which is the default repository for the `TodoItem` entity. We will use it to implement our use cases.
#### Getting the Todo Items
Let's start by implementing the `GetListAsync` method, which is used to get a list of todo items:
````csharp
public async Task<List<TodoItemDto>> GetListAsync()
{
var items = await _todoItemRepository.GetListAsync();
return items
.Select(item => new TodoItemDto
{
Id = item.Id,
Text = item.Text
}).ToList();
}
````
We are simply getting the `TodoItem` list from the repository, mapping them to the `TodoItemDto` objects and returning as the result.
#### Creating a New Todo Item
The next method is `CreateAsync` and we can implement it as shown below:
````csharp
public async Task<TodoItemDto> CreateAsync(string text)
{
var todoItem = await _todoItemRepository.InsertAsync(
new TodoItem {Text = text}
);
return new TodoItemDto
{
Id = todoItem.Id,
Text = todoItem.Text
};
}
````
The repository's `InsertAsync` method inserts the given `TodoItem` to the database and returns the same `TodoItem` object. It also sets the `Id`, so we can use it on the returning object. We are simply returning a `TodoItemDto` by creating from the new `TodoItem` entity.
#### Deleting a Todo Item
Finally, we can implement the `DeleteAsync` as the following code block:
````csharp
public async Task DeleteAsync(Guid id)
{
await _todoItemRepository.DeleteAsync(id);
}
````
The application service is ready to be used from the UI layer. So, let's implement it.
## User Interface
It is time to show the todo items on the UI! Before starting to write the code, it would be good to remember what we are trying to build. Here's a sample screenshot from the final UI:
![todo-list](../todo-list.png)
{{if UI=="MVC"}}
### Index.cshtml.cs
Open the `Index.cshtml.cs` file in the `Pages` folder and replace the content with the following code block:
```csharp
using TodoApp.Services;
using TodoApp.Services.Dtos;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
namespace TodoApp.Pages;
public class IndexModel : AbpPageModel
{
public List<TodoItemDto> TodoItems { get; set; }
private readonly TodoAppService _todoAppService;
public IndexModel(TodoAppService todoAppService)
{
_todoAppService = todoAppService;
}
public async Task OnGetAsync()
{
TodoItems = await _todoAppService.GetListAsync();
}
}
```
This class uses `TodoAppService` to get the list of todo items and assign the `TodoItems` property. We will use it to render the todo items on the razor page.
### Index.cshtml
Open the `Index.cshtml` file in the `Pages` folder and replace it with the following content:
```xml
@page
@model TodoApp.Pages.IndexModel
@section styles {
<abp-style src="/Pages/Index.cshtml.css" />
}
@section scripts {
<abp-script src="/Pages/Index.cshtml.js" />
}
<div class="container">
<abp-card>
<abp-card-header>
<abp-card-title>
TODO LIST
</abp-card-title>
</abp-card-header>
<abp-card-body>
<!-- FORM FOR NEW TODO ITEMS -->
<form id="NewItemForm" class="row row-cols-lg-auto g-3 align-items-center">
<div class="col-12">
<div class="input-group">
<input id="NewItemText" type="text" class="form-control" placeholder="enter text...">
</div>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
@foreach (var todoItem in Model.TodoItems)
{
<li data-id="@todoItem.Id">
<i class="fa fa-trash-o"></i> @todoItem.Text
</li>
}
</ul>
</abp-card-body>
</abp-card>
</div>
```
We are using ABP's [card tag helper](../../../UI/AspNetCore/Tag-Helpers/Cards.md) to create a simple card view. You could directly use the standard bootstrap HTML structure, however the ABP [tag helpers](../../../UI/AspNetCore/Tag-Helpers/Index.md) make it much easier and type safe.
This page imports a CSS and a JavaScript file, so we should also create them.
### Index.cshtml.js
Open the `Index.cshtml.js` file in the `Pages` folder and replace with the following content:
````js
$(function () {
// DELETING ITEMS /////////////////////////////////////////
$('#TodoList').on('click', 'li i', function(){
var $li = $(this).parent();
var id = $li.attr('data-id');
todoApp.services.todo.delete(id).then(function(){
$li.remove();
abp.notify.info('Deleted the todo item.');
});
});
// CREATING NEW ITEMS /////////////////////////////////////
$('#NewItemForm').submit(function(e){
e.preventDefault();
var todoText = $('#NewItemText').val();
todoApp.services.todo.create(todoText).then(function(result){
$('<li data-id="' + result.id + '">')
.html('<i class="fa fa-trash-o"></i> ' + result.text)
.appendTo($('#TodoList'));
$('#NewItemText').val('');
});
});
});
````
In the first part, we subscribed to the click events of the trash icons near the todo items, deleted the related item on the server and showed a notification on the UI. Also, we removed the deleted item from the DOM, so we wouldn't need to refresh the page.
In the second part, we created a new todo item on the server. If it succeeded, we would then manipulate the DOM to insert a new `<li>` element to the todo list. This way, we wouldn't need to refresh the whole page after creating a new todo item.
The interesting part here is how we communicate with the server. See the *Dynamic JavaScript Proxies & Auto API Controllers* section to understand how it works. But now, let's continue and complete the application.
### Index.cshtml.css
As for the final touch, open the `Index.cshtml.css` file in the `Pages` folder and replace with the following content:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
This is a simple styling for the todo page. We believe that you can do much better :)
Now, you can run the application again and see the result.
### Dynamic JavaScript Proxies & Auto API Controllers
In the `Index.cshtml.js` file, we've used the `todoApp.services.todo.delete(...)` and `todoApp.services.todo.create(...)` functions to communicate with the server. These functions are dynamically created by the ABP Framework, thanks to the [Dynamic JavaScript Client Proxy](../../../UI/AspNetCore/Dynamic-JavaScript-Proxies.md) system. They perform HTTP API calls to the server and return a promise, so you can register a callback to the `then` function as we've done above.
> `services` keyword comes from the namespace (`namespace TodoApp.Services;`). It's a naming convention.
However, you may notice that we haven't created any API Controllers, so how does the server handle these requests? This question brings us to the [Auto API Controller](../../../API/Auto-API-Controllers.md) feature of the ABP Framework. It automatically converts the application services to **API Controllers** by convention.
If you open [Swagger UI](https://swagger.io/tools/swagger-ui/) by entering the `/swagger` URL in your application, you can see the Todo API:
![todo-api](../todo-api.png)
{{else if UI=="BlazorServer"}}
### Index.razor.cs
Open the `Index.razor.cs` file in the `Pages` folder and replace the content with the following code block:
```csharp
using Microsoft.AspNetCore.Components;
using TodoApp.Services;
using TodoApp.Services.Dtos;
namespace TodoApp.Pages;
public partial class Index
{
[Inject]
private TodoAppService TodoAppService { get; set; }
private List<TodoItemDto> TodoItems { get; set; } = new List<TodoItemDto>();
private string NewTodoText { get; set; }
protected override async Task OnInitializedAsync()
{
TodoItems = await TodoAppService.GetListAsync();
}
private async Task Create()
{
var result = await TodoAppService.CreateAsync(NewTodoText);
TodoItems.Add(result);
NewTodoText = null;
}
private async Task Delete(TodoItemDto todoItem)
{
await TodoAppService.DeleteAsync(todoItem.Id);
await Notify.Info("Deleted the todo item.");
TodoItems.Remove(todoItem);
}
}
```
This class uses the `TodoAppService` to get the list of todo items. It manipulates the `TodoItems` list after create and delete operations. This way, we don't need to refresh the whole todo list from the server.
### Index.razor
Open the `Index.razor` file in the `Pages` folder and replace the content with the following code block:
```xml
@page "/"
@inherits TodoAppComponentBase
<div class="container">
<Card>
<CardHeader>
<CardTitle>
TODO LIST
</CardTitle>
</CardHeader>
<CardBody>
<!-- FORM FOR NEW TODO ITEMS -->
<form id="NewItemForm" @onsubmit:preventDefault @onsubmit="() => Create()" class="row row-cols-lg-auto g-3 align-items-center">
<div class="col-12">
<div class="input-group">
<input name="NewTodoText" type="text" @bind-value="@NewTodoText" class="form-control" placeholder="enter text..." />
</div>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
@foreach (var todoItem in TodoItems)
{
<li data-id="@todoItem.Id">
<i class="far fa-trash-alt"
@onclick="() => Delete(todoItem)"></i>
@todoItem.Text
</li>
}
</ul>
</CardBody>
</Card>
</div>
```
### Index.razor.css
As the final touch, open the `Index.razor.css` file in the `Pages` folder and replace it with the following content:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
This is a simple styling for the todo page. We believe that you can do much better :)
Now, you can run the application again to see the result.
{{else if UI=="NG"}}
### Service Proxy Generation
ABP provides a handy feature to automatically create client-side services to easily consume HTTP APIs provided by the server.
You first need to run the `TodoApp` project since the proxy generator reads API definitions from the server application.
Once you run the `TodoApp` project (**Swagger API Definition** will be shown), open a command-line terminal in the directory of `angular` folder and run the following command:
```bash
abp generate-proxy -t ng
```
If everything goes well, it should generate an output as shown below:
```bash
CREATE src/app/proxy/generate-proxy.json (182755 bytes)
CREATE src/app/proxy/README.md (1000 bytes)
CREATE src/app/proxy/services/todo.service.ts (833 bytes)
CREATE src/app/proxy/services/dtos/models.ts (71 bytes)
CREATE src/app/proxy/services/dtos/index.ts (26 bytes)
CREATE src/app/proxy/services/index.ts (81 bytes)
CREATE src/app/proxy/index.ts (61 bytes)
```
Then, we can use the `TodoService` to use the server-side HTTP APIs, as we'll do in the next section.
### home.component.ts
Open the `/angular/src/app/home/home.component.ts` file and replace its content with the following code block:
```ts
import { ToasterService } from "@abp/ng.theme.shared";
import { Component, OnInit } from '@angular/core';
import { TodoItemDto } from "@proxy/services/dtos";
import { TodoService } from "@proxy/services";
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss'],
})
export class HomeComponent implements OnInit {
todoItems: TodoItemDto[];
newTodoText: string;
constructor(
private todoService: TodoService,
private toasterService: ToasterService)
{ }
ngOnInit(): void {
this.todoService.getList().subscribe(response => {
this.todoItems = response;
});
}
create(): void{
this.todoService.create(this.newTodoText).subscribe((result) => {
this.todoItems = this.todoItems.concat(result);
this.newTodoText = null;
});
}
delete(id: string): void {
this.todoService.delete(id).subscribe(() => {
this.todoItems = this.todoItems.filter(item => item.id !== id);
this.toasterService.info('Deleted the todo item.');
});
}
}
```
We've used `TodoService` to get the list of todo items and assigned the returning value to the `todoItems` array. We've also added `create` and `delete` methods. These methods will be used on the view side.
### home.component.html
Open the `/angular/src/app/home/home.component.html` file and replace its content with the following code block:
````html
<div class="container">
<div class="card">
<div class="card-header">
<div class="card-title">TODO LIST</div>
</div>
<div class="card-body">
<!-- FORM FOR NEW TODO ITEMS -->
<form class="row row-cols-lg-auto g-3 align-items-center" (ngSubmit)="create()">
<div class="col-12">
<div class="input-group">
<input name="NewTodoText" type="text" [(ngModel)]="newTodoText" class="form-control" placeholder="enter text..." />
</div>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
<li *ngFor="let todoItem of todoItems">
<i class="fa fa-trash-o" (click)="delete(todoItem.id)"></i> {%{{{ todoItem.text }}}%}
</li>
</ul>
</div>
</div>
</div>
````
### home.component.scss
As the final touch, open the `/angular/src/app/home/home.component.scss` file and replace its content with the following code block:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
This is a simple styling for the todo page. We believe that you can do much better :)
Now, you can run the application again to see the result.
{{end}}
## Conclusion
In this tutorial, we've built a very simple application to warm up with the ABP Framework.
## Source Code
You can find the source code of the completed application [here](https://github.com/abpframework/abp-samples/tree/master/TodoApp-SingleLayer).
## See Also
* Check the [Web Application Development Tutorial](../../Part-1.md) to see a real-life web application development in a layered architecture using the [Application Startup Template](../../../Startup-Templates/Application.md).

BIN
docs/en/Tutorials/Todo/Single-Layer/todo-efcore-migration-single-layer.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

2
docs/en/UI/Angular/Account-Module.md

@ -110,7 +110,7 @@ export const environment = {
// other options removed for sake of brevity
oAuthConfig: {
issuer: 'https://localhost:44305', // IdentityServer url
issuer: 'https://localhost:44305', // AuthServer url
clientId: 'MyProjectName_App',
dummyClientSecret: '1q2w3e*',
scope: 'offline_access MyProjectName',

29
docs/en/UI/Angular/DateTime-Format-Pipe.md

@ -0,0 +1,29 @@
# DateTime Format Pipes
You can format date by Date pipe of angular.
Example
```html
<span> {{today | date 'dd/mm/yy'}}</span>
```
ShortDate, ShortTime and ShortDateTime format data like angular's data pipe but easier. Also the pipes get format from config service by culture.
# ShortDate Pipe
```html
<span> {{today | shortDatePipe }}</span>
```
# ShortTime Pipe
```html
<span> {{today | shortTimePipe }}</span>
```
# ShortDateTime Pipe
```html
<span> {{today | shortDateTimePipe }}</span>
```

47
docs/en/UI/Angular/GlobalFeatures.md

@ -0,0 +1,47 @@
# Angular: Global Features API
The `ConfigStateService.getGlobalFeatures` API allows you to get the enabled features of the [Global Features](../../Global-Features.md) on the client side.
> This document only explains the JavaScript API. See the [Global Features](../../Global-Features.md) document to understand the ABP Global Features system.
## Usage
````js
import { ConfigStateService } from '@abp/ng.core';
import { Component, OnInit } from '@angular/core';
@Component({
/* class metadata here */
})
class DemoComponent implements OnInit {
constructor(private config: ConfigStateService) {}
ngOnInit(): void {
// Gets all enabled global features.
const getGlobalFeatures = this.config.getGlobalFeatures();
//Example result is: `{ enabledFeatures: [ 'Shopping.Payment', 'Ecommerce.Subscription' ] }`
// or
this.config.getGlobalFeatures$().subscribe(getGlobalFeatures => {
// use getGlobalFeatures here
})
// Check the global feature is enabled
this.config.getGlobalFeatureIsEnabled('Ecommerce.Subscription')
//Example result is `true`
this.config.getGlobalFeatureIsEnabled('My.Subscription')
//Example result is `false`
// or
this.config.getGlobalFeatureIsEnabled$('Ecommerce.Subscription').subscribe((isEnabled:boolean) => {
// use isEnabled here
})
}
}

44
docs/en/UI/Angular/Loading-Directive.md

@ -0,0 +1,44 @@
# Loading Directive
You may want to block a part of the UI and show a spinner for a while; the `LoadingDirective` directive makes this for you. `LoadingDirective` has been exposed by the `@abp/ng.theme.shared` package.
## Getting Started
In order to use the `LoadingDirective` in an HTML template, the **`ThemeSharedModule`** should be imported into your module like this:
```js
// ...
import { ThemeSharedModule } from '@abp/ng.theme.shared';
@NgModule({
//...
imports: [..., ThemeSharedModule],
})
export class MyFeatureModule {}
```
## Usage
The `LoadingDirective` is easy to use. The directive's selector is **`abpLoading`**. By adding the `abpLoading` attribute to an HTML element, you can activate the `LoadingDirectiveective` for the HTML element when the value is true.
See an example usage:
```html
<div [abpLoading]="true">
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Laboriosam commodi quae aspernatur,
corporis velit et suscipit id consequuntur amet minima expedita cum reiciendis dolorum
cupiditate? Voluptas eaque voluptatum odio deleniti quo vel illum nemo accusamus nulla ratione
impedit dolorum expedita necessitatibus fugiat ullam beatae, optio eum cupiditate ducimus
architecto.
</div>
```
The `abpLoading` attribute has been added to the `<div>` element that contains very a long text inside to activate the `LoadingDirective`.
See the result:
![Loading directive result](./images/abp-loading.png)

2
docs/en/UI/Angular/Multi-Tenancy.md

@ -119,7 +119,7 @@ After the configuration above, if your app runs on the `mytenant1.mydomain.com`,
After this replacement, the app will use the following URLs:
- `https://mytenant1.ids.mydomain.com` as IdentityServer URL.
- `https://mytenant1.ids.mydomain.com` as AuthServer URL.
- `https://mytenant1.api.mydomain.com` as default URL.
- `https://mytenant1.identity.mydomain.com` as `AbpIdentity` remote endpoint URL.

BIN
docs/en/UI/Angular/images/abp-loading.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

2
docs/en/UI/AspNetCore/Branding.md

@ -21,7 +21,7 @@ namespace MyProject.Web
{
public override string AppName => "Book Store";
public override string LogoUrl => "logo.png";
public override string LogoUrl => "/logo.png";
}
}
````

24
docs/en/UI/AspNetCore/JavaScript-API/GlobalFeatures.md

@ -0,0 +1,24 @@
# ASP.NET Core MVC / Razor Pages UI: JavaScript Global Features API
`abp.globalFeatures` API allows you to get the enabled features of the [Global Features](../../../Global-Features.md) in the client side.
> This document only explains the JavaScript API. See the [Global Features](../../../Global-Features.md) document to understand the ABP Global Features system.
## Usage
````js
//Gets all enabled global features.
> abp.globalFeatures.enabledFeatures
[ 'Shopping.Payment', 'Ecommerce.Subscription' ]
//Check the global feature is enabled
> abp.globalFeatures.isEnabled('Ecommerce.Subscription')
true
> abp.globalFeatures.isEnabled('My.Subscription')
false
````

1
docs/en/UI/AspNetCore/JavaScript-API/Index.md

@ -10,6 +10,7 @@ ABP provides a set of JavaScript APIs for ASP.NET Core MVC / Razor Pages applica
* [DOM](DOM.md)
* [Events](Events.md)
* [Features](Features.md)
* [Global Features](GlobalFeatures.md)
* [Localization](Localization.md)
* [Logging](Logging.md)
* [ResourceLoader](ResourceLoader.md)

8
docs/en/UI/AspNetCore/Theming.md

@ -122,9 +122,13 @@ The empty layout provides an empty page. It typically includes the following par
## Implementing a Theme
### The Easy Way
### The Easiest Way
The easiest way to create a new theme is to copy the [Basic Theme Source Code](https://github.com/abpframework/abp/blob/dev/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic) and customize it. Once you get a copy of the theme in your solution, remove the `Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic` NuGet package and reference to the local project.
The easiest way of creating a new theme is adding [Basic Theme Source Code](https://github.com/abpframework/abp/tree/dev/modules/basic-theme) module with source codes and customizing it.
```bash
abp add-package Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic --with-source-code --add-to-solution-file
```
### The ITheme Interface

22
docs/en/UI/Blazor/Authentication.md

@ -1,11 +1,27 @@
# Blazor UI: Authentication
The [application startup template](../../Startup-Templates/Application.md) is properly configured to use OpenId Connect to authenticate the user through the server side login form;
````json
//[doc-params]
{
"UI": ["Blazor", "BlazorServer"]
}
````
The [application startup template](../../Startup-Templates/Application.md) is properly configured to use OpenId Connect to authenticate the user;
{{if UI == "BlazorServer"}}
The Blazor Server application UI is actually a hybrid application that is combined with the MVC UI, and uses the login page provided by the MVC UI. When users enter a page that requires login, they are redirected to the `/Account/Login` page. Once they complete the login process, they are returned back to the application's UI. The login page also contains features like registration, password recovery, etc.
{{end}}
{{if UI == "Blazor"}}
* When the Blazor application needs to authenticate, it is redirected to the server side.
* Users can enter username & password to login if they already have an account. If not, they can use the register form to create a new user. They can also use forgot password and other features. The server side uses IdentityServer4 to handle the authentication.
* Users can enter username & password to login if they already have an account. If not, they can use the register form to create a new user. They can also use forgot password and other features. The server side uses OpenIddict to handle the authentication.
* Finally, they are redirected back to the Blazor application to complete the login process.
This is a typical and recommended approach to implement authentication in Single-Page Applications. The client side configuration is done in the startup template, so you can change it.
See the [Blazor Security document](https://docs.microsoft.com/en-us/aspnet/core/blazor/security) to understand and customize the authentication process.
See the [Blazor Security document](https://docs.microsoft.com/en-us/aspnet/core/blazor/security) to understand and customize the authentication process.
{{end}}

71
docs/en/UI/Blazor/Basic-Theme.md

@ -1,5 +1,12 @@
# Blazor UI: Basic Theme
````json
//[doc-params]
{
"UI": ["Blazor", "BlazorServer"]
}
````
The Basic Theme is a theme implementation for the Blazor UI. It is a minimalist theme that doesn't add any styling on top of the plain [Bootstrap](https://getbootstrap.com/). You can take the Basic Theme as the **base theme** and build your own theme or styling on top of it. See the *Customization* section.
> If you are looking for a professional, enterprise ready theme, you can check the [Lepton Theme](https://commercial.abp.io/themes), which is a part of the [ABP Commercial](https://commercial.abp.io/).
@ -10,16 +17,46 @@ The Basic Theme is a theme implementation for the Blazor UI. It is a minimalist
**This theme is already installed** when you create a new solution using the [startup templates](../../Startup-Templates/Index.md). If you need to manually install it, follow the steps below:
{{if UI == "Blazor"}}
* Install the [Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme) NuGet package to your web project.
* Add `AbpAspNetCoreComponentsWebAssemblyBasicThemeModule` into the `[DependsOn(...)]` attribute for your [module class](../../Module-Development-Basics.md) in the your Blazor UI project.
* Use `Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic.App` as the root component of your application in the `ConfigureServices` method of your module:
````csharp
var builder = context.Services.GetSingletonInstance<WebAssemblyHostBuilder>();
builder.RootComponents.Add<App>("#ApplicationContainer");
````
```csharp
var builder = context.Services.GetSingletonInstance<WebAssemblyHostBuilder>();
builder.RootComponents.Add<App>("#ApplicationContainer");
```
`#ApplicationContainer` is a selector (like `<div id="ApplicationContainer">Loading...</div>`) in the `index.html`.
* Execute `abp bundle` command under blazor project once.
{{end}}
{{if UI == "BlazorServer"}}
* Make sure [AspNetCore Basic Theme](../AspNetCore/Basic-Theme.md) installation steps are completed.
* Install the [Volo.Abp.AspNetCore.Components.Server.BasicTheme](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Components.Server.BasicTheme) NuGet package to your web project.
* Add `AbpAspNetCoreComponentsServerBasicThemeModule` into the `[DependsOn(...)]` attribute for your [module class](../../Module-Development-Basics.md) in the your Blazor UI project.
* Perform following changes in `Pages/_Host.cshtml` file
* Add usings at the top of the page.
```html
@using Volo.Abp.AspNetCore.Components.Server.BasicTheme.Bundling
@using Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic
```
* Add Basic theme style bundles between `<head>` tags.
```html
<abp-style-bundle name="@BlazorBasicThemeBundles.Styles.Global" />
```
* Add `App` component of Basic Theme in the body section of page.
```html
<component type="typeof(App)" render-mode="Server" />
```
`#ApplicationContainer` is a selector (like `<div id="ApplicationContainer">Loading...</div>`) in the `index.html`.
{{end}}
## The Layout
@ -52,15 +89,37 @@ See the [Customization / Overriding Components](Customization-Overriding-Compone
You can run the following [ABP CLI](../../CLI.md) command in **Blazor WebAssembly** project directory to copy the source code to your solution:
{{if UI == "Blazor"}}
`abp add-package Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme --with-source-code --add-to-solution-file`
Then, navigate to downloaded `Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme` project directory and run:
`abp add-package Volo.Abp.AspNetCore.Components.Web.BasicTheme --with-source-code --add-to-solution-file`
{{end}}
{{if UI == "BlazorServer"}}
`abp add-package Volo.Abp.AspNetCore.Components.Server.BasicTheme --with-source-code --add-to-solution-file`
Then, navigate to downloaded `Volo.Abp.AspNetCore.Components.Server.BasicTheme` project directory and run:
`abp add-package Volo.Abp.AspNetCore.Components.Web.BasicTheme --with-source-code --add-to-solution-file`
{{end}}
----
Or, you can download the [source code](https://github.com/abpframework/abp/blob/dev/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme) of the Basic Theme, manually copy the project content into your solution, re-arrange the package/module dependencies (see the Installation section above to understand how it was installed to the project) and freely customize the theme based on your application requirements.
Or, you can download the source code of the Basic Theme, manually copy the project content into your solution, re-arrange the package/module dependencies (see the Installation section above to understand how it was installed to the project) and freely customize the theme based on your application requirements.
{{if UI == "Blazor"}}
- [Basic Theme Source Code](https://github.com/abpframework/abp/blob/dev/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme)
{{end}}
{{if UI == "BlazorServer"}}
- [Basic Theme Source Code](https://github.com/abpframework/abp/blob/dev/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme)
{{end}}
## See Also

27
docs/en/UI/Blazor/Customization-Overriding-Components.md

@ -1,5 +1,12 @@
# Blazor UI: Customization / Overriding Components
````json
//[doc-params]
{
"UI": ["Blazor", "BlazorServer"]
}
````
This document explains how to override the user interface of a depended [application module](../../Modules/Index.md) or [theme](Theming.md) for Blazor applications.
## Overriding a Razor Component
@ -26,9 +33,16 @@ The next step is to create a razor component, like `MyBranding.razor`, in your a
The content of the `MyBranding.razor` is shown below:
````html
@using Volo.Abp.DependencyInjection
{{if UI == "BlazorServer"}}
@using Volo.Abp.AspNetCore.Components.Server.BasicTheme.Themes.Basic
{{end}}
{{if UI == "Blazor"}}
@using Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic
{{end}}
@inherits Branding
@attribute [ExposeServices(typeof(Branding))]
@attribute [Dependency(ReplaceServices = true)]
@ -39,7 +53,7 @@ The content of the `MyBranding.razor` is shown below:
Let's explain the code:
* `@inherits Branding` line inherits the Branding component defined by the [Basic Theme](Basic-Theme.md) (in the `Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic` namespace).
* `@inherits Branding` line inherits the Branding component defined by the [Basic Theme](Basic-Theme.md) (in the {{if UI == "BlazorServer"}}`Volo.Abp.AspNetCore.Components.Server.BasicTheme.Themes.Basic`{{end}} {{if UI == "Blazor"}}`Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic`{{end}} namespace).
* `@attribute [ExposeServices(typeof(Branding))]` registers this service (component) to [dependency injection](../../Dependency-Injection.md) for the `Branding` service (component).
* `@attribute [Dependency(ReplaceServices = true)]` replaces the `Branding` class (component) with this new `MyBranding` class (component).
* The rest of the code is related the content and styling of the component.
@ -57,7 +71,12 @@ If you prefer to use code-behind file for the C# code of your component, you can
**MyBlazor.razor**
````html
{{if UI == "BlazorServer"}}
@using Volo.Abp.AspNetCore.Components.Server.BasicTheme.Themes.Basic
{{end}}
{{if UI == "Blazor"}}
@using Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic
{{end}}
@inherits Branding
<a href="/">
<img src="bookstore-logo.png" width="250" height="60"/>
@ -67,7 +86,13 @@ If you prefer to use code-behind file for the C# code of your component, you can
**MyBlazor.razor.cs**
````csharp
{{if UI == "BlazorServer"}}
using Volo.Abp.AspNetCore.Components.Server.BasicTheme.Themes.Basic;
{{end}}
{{if UI == "Blazor"}}
using Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic;
{{end}}
using Volo.Abp.DependencyInjection;
namespace MyProject.Blazor.Components

40
docs/en/UI/Blazor/Error-Handling.md

@ -1,5 +1,12 @@
# Blazor UI: Error Handling
````json
//[doc-params]
{
"UI": ["Blazor", "BlazorServer"]
}
````
Blazor, by default, shows a yellow line at the bottom of the page if any unhandled exception occurs. However, this is not useful in a real application.
ABP provides an automatic error handling system for the Blazor UI.
@ -16,6 +23,8 @@ There are different type of `Exception` classes handled differently by the ABP F
`UserFriendlyException` is a special type of exception. You can directly show a error message dialog to the user by throwing such an exception.
{{if UI == "BlazorServer"}}
> For Blazor Server, exceptions must be handled manually. Otherwise it crashes the whole application. Auto Exception Handling is not possible with Blazor Server right now, please follow [this issue](https://github.com/abpframework/abp/issues/8195) to see progress. In meantime, you can use try-catch blocks and call the `HandleErrorAsync` method of ABP to handle errors manually, which shows an error dialog for you.
**Example**
@ -28,13 +37,6 @@ There are different type of `Exception` classes handled differently by the ABP F
@code
{
//for Blazor WASM
private void TestException()
{
throw new UserFriendlyException("A user friendly error message!");
}
//for Blazor Server
private async Task TestException()
{
try
@ -49,6 +51,28 @@ There are different type of `Exception` classes handled differently by the ABP F
}
````
{{end}}
{{if UI == "Blazor"}}
**Example**
````csharp
@page "/"
@using Volo.Abp
<Button Clicked="TestException">Throw test exception</Button>
@code
{
private void TestException()
{
throw new UserFriendlyException("A user friendly error message!");
}
}
````
{{end}}
ABP automatically handle the exception and show an error message to the user:
![blazor-user-friendly-exception](../../images/blazor-user-friendly-exception.png)
@ -75,4 +99,4 @@ Errors (like Validation, Authorization and User Friendly Errors) sent by the ser
## See Also
* [Exception Handling System](../../Exception-Handling.md)
* [Exception Handling System](../../Exception-Handling.md)

31
docs/en/UI/Blazor/Page-Layout.md

@ -13,6 +13,37 @@ Title is used to render page title in the PageHeader.
}
```
## MenuItemName
Indicates current selected menu item name. Menu item name should match a unique menu item name defined using the [Navigation / Menu system](../Blazor/Navigation-Menu.md). In this case, it is expected from the theme to make the menu item "active" in the main menu.
```csharp
@inject PageLayout PageLayout
@code {
protected override async Task OnInitializedAsync()
{
PageLayout.MenuItemName = "MyProjectName.Products";
}
}
```
Menu item name can be set on runtime too.
```html
@inject PageLayout PageLayout
<Button Clicked="SetCategoriesMenuAsSelected">Change Menu</Button>
@code{
protected void SetCategoriesMenuAsSelected()
{
PageLayout.MenuItemName = "MyProjectName.Categories";
}
}
```
> Be aware, The [Basic Theme](../Blazor/Basic-Theme.md) currently doesn't support the selected menu item since it is not applicable to the top menu.
## BreadCrumbs
BreadCrumbItems are used to render breadcrumbs in the PageHeader.
```csharp

64
docs/en/UI/Blazor/Theming.md

@ -1,5 +1,12 @@
# Blazor UI: Theming
````json
//[doc-params]
{
"UI": ["Blazor", "BlazorServer"]
}
````
## Introduction
ABP Framework provides a complete **UI Theming** system with the following goals:
@ -16,17 +23,28 @@ In order to accomplish these goals, ABP Framework;
### Current Themes
Currently, two themes are **officially provided**:
Currently, three themes are **officially provided**:
* The [Basic Theme](Basic-Theme.md) is the minimalist theme with the plain Bootstrap style. It is **open source and free**.
* The [Lepton Theme](https://commercial.abp.io/themes) is a **commercial** theme developed by the core ABP team and is a part of the [ABP Commercial](https://commercial.abp.io/) license.
* The [LeptonX Theme](https://x.leptontheme.com/) is a theme that has a [commercial](https://docs.abp.io/en/commercial/latest/themes/lepton-x/commercial/blazor) and a [lite](../../Themes/LeptonXLite/blazor.md) version.
## Overall
### The Base Libraries
{{if UI == "Blazor"}}
All the themes must depend on the [Volo.Abp.AspNetCore.Components.WebAssembly.Theming](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Components.WebAssembly.Theming) NuGet package, so they are indirectly depending on the following libraries:
{{end}}
{{if UI == "BlazorServer"}}
All the themes must depend on the [Volo.Abp.AspNetCore.Components.Server.Theming](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Components.Server.Theming) NuGet package, so they are indirectly depending on the following libraries:
{{end}}
* [Twitter Bootstrap](https://getbootstrap.com/) as the fundamental HTML/CSS framework.
* [Blazorise](https://github.com/stsrki/Blazorise) as a component library that supports the Bootstrap and adds extra components like Data Grid and Tree.
* [FontAwesome](https://fontawesome.com/) as the fundamental CSS font library.
@ -61,9 +79,21 @@ The application layout typically includes the following parts;
A theme is simply a Razor Class Library.
### The Easy Way
### The Easiest Way
The easiest way to create a new theme is to copy the [Basic Theme Source Code](https://github.com/abpframework/abp/blob/dev/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme) and customize it. Once you get a copy of the theme in your solution, remove the `Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme` NuGet package and reference to the local project.
The easiest way of creating a new theme is adding [Basic Theme Source Code](https://github.com/abpframework/abp/tree/dev/modules/basic-theme) module with source codes and customizing it.
{{if UI == "Blazor"}}
```bash
abp add-package Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme --with-source-code --add-to-solution-file
```
{{end}}
{{if UI == "BlazorServer"}}
```bash
abp add-package Volo.Abp.AspNetCore.Components.Server.BasicTheme --with-source-code --add-to-solution-file
```
{{end}}
### Global Styles / Scripts
@ -165,6 +195,9 @@ Configure<AbpToolbarOptions>(options =>
Language Selection toolbar item is generally a dropdown that is used to switch between languages. `ILanguageProvider` is used to get the list of available languages and `CultureInfo.CurrentUICulture` is used to learn the current language.
{{if UI == "Blazor"}}
Local Storage is used to get and set the current language with the `Abp.SelectedLanguage` key.
**Example: Get the currently selected language**
@ -192,6 +225,31 @@ The theme should reload the page after changing the language:
await JsRuntime.InvokeVoidAsync("location.reload");
````
{{end}}
{{if UI == "BlazorServer"}}
Localization works on Server side in Blazor Server. So, regular AspNetCore localization middleware is used.
**Example: Get the currently selected language**
````csharp
var selectedLanguageName = CultureInfo.CurrentCulture.Name;
````
**Example: Set the selected language**
````csharp
// Get current url.
var relativeUrl = NavigationManager.Uri.RemovePreFix(NavigationManager.BaseUri).EnsureStartsWith('/');
// Redirect to ABP language switch endpoint.
NavigationManager.NavigateTo(
$"/Abp/Languages/Switch?culture={newLanguage.CultureName}&uiCulture={newLanguage.UiCultureName}&returnUrl={relativeUrl}",
forceLoad: true
);
````
{{end}}
##### User Menu
User menu includes links related to the user account. `IMenuManager` is used just like the Main Menu, but this time with `StandardMenus.User` parameter like shown below:

19
docs/en/UI/Blazor/Toolbars.md

@ -34,23 +34,16 @@ This sample simply shows a message. In real life, you probably want to call an H
Now, we can create a class implementing the `IToolbarContributor` interface:
````csharp
using System.Threading.Tasks;
using MyCompanyName.MyProjectName.Blazor.Components;
using Volo.Abp.AspNetCore.Components.WebAssembly.Theming.Toolbars;
namespace MyCompanyName.MyProjectName.Blazor
public class MyToolbarContributor : IToolbarContributor
{
public class MyToolbarContributor : IToolbarContributor
public Task ConfigureToolbarAsync(IToolbarConfigurationContext context)
{
public Task ConfigureToolbarAsync(IToolbarConfigurationContext context)
if (context.Toolbar.Name == StandardToolbars.Main)
{
if (context.Toolbar.Name == StandardToolbars.Main)
{
context.Toolbar.Items.Insert(0, new ToolbarItem(typeof(Notification)));
}
return Task.CompletedTask;
context.Toolbar.Items.Insert(0, new ToolbarItem(typeof(Notification)));
}
return Task.CompletedTask;
}
}
````

61
docs/en/docs-nav.json

@ -2,7 +2,17 @@
"items": [
{
"text": "Quick Start",
"path": "Tutorials/Todo/Index.md"
"path": "Tutorials/Todo/Overall.md",
"items": [
{
"text": "With single-layer solution",
"path": "Tutorials/Todo/Single-Layer/Index.md"
},
{
"text": "With layered architecture",
"path": "Tutorials/Todo/Index.md"
}
]
},
{
"text": "Getting Started",
@ -118,6 +128,10 @@
"text": "Application",
"path": "Startup-Templates/Application.md"
},
{
"text": "Application (Single Layer)",
"path": "Startup-Templates/Application-Single-Layer.md"
},
{
"text": "Module",
"path": "Startup-Templates/Module.md"
@ -822,7 +836,7 @@
"path": "UI/Blazor/Basic-Theme.md"
},
{
"text": "The Basic Theme",
"text": "LeptonX Lite",
"path": "Themes/LeptonXLite/blazor.md"
},
{
@ -975,6 +989,10 @@
"text": "Features",
"path": "UI/Angular/Features.md"
},
{
"text": "Global Features",
"path": "UI/Angular/GlobalFeatures.md"
},
{
"text": "Permission Management",
"path": "UI/Angular/Permission-Management.md"
@ -1028,6 +1046,10 @@
"text": "Confirmation Popup",
"path": "UI/Angular/Confirmation-Service.md"
},
{
"text": "Loading Directive",
"path": "UI/Angular/Loading-Directive.md"
},
{
"text": "Toast Overlay",
"path": "UI/Angular/Toaster-Service.md"
@ -1097,10 +1119,10 @@
{
"text": "Extensions",
"items": [
{
{
"text": "Overall",
"path": "UI/Angular/Extensions-Overall.md"
},
},
{
"text": "Entity Action Extensions",
"path": "UI/Angular/Entity-Action-Extensions.md"
@ -1116,6 +1138,10 @@
{
"text": "Dynamic Form Extensions",
"path": "UI/Angular/Dynamic-Form-Extensions.md"
},
{
"text": "Date, time and datetime format pipes",
"path": "UI/Angular/DateTime-Format-Pipe.md"
}
]
}
@ -1285,6 +1311,10 @@
{
"text": "IdentityServer",
"path": "Modules/IdentityServer.md"
},
{
"text": "OpenIddict",
"path": "Modules/OpenIddict.md"
},
{
"text": "Permission Management",
@ -1312,11 +1342,32 @@
"path": "Samples/Index.md"
},
{
"text": "Microservice Demo",
"text": "eShopOnAbp",
"path": "https://github.com/abpframework/eShopOnAbp"
},
{
"text": "EventHub",
"path": "https://github.com/abpframework/eventhub"
},
{
"text": "Microservice Demo (legacy)",
"path": "Samples/Microservice-Demo.md"
}
]
},
{
"text": "Books",
"items": [
{
"text": "Mastering ABP Framework",
"path": "https://abp.io/books/mastering-abp-framework"
},
{
"text": "Implementing Domain Driven Design",
"path": "https://abp.io/books/implementing-domain-driven-design"
}
]
},
{
"text": "Release Information",
"items": [

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

Loading…
Cancel
Save