Browse Source

Merge branch 'dev' into luisPignataro/Traslate

pull/3321/head
Luis Pignataro 7 years ago
parent
commit
17c002ddb0
  1. 11
      .github/labeler.yml
  2. 21
      .github/workflows/labeler.yml
  3. 2
      README.md
  4. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalization.csproj
  5. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs
  6. 13
      abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hant.json
  7. 60
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hant.json
  8. 31
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hant.json
  9. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/zh-Hant.json
  10. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  11. 30
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json
  12. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/zh-Hant.json
  13. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/zh-Hant.json
  14. 159
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json
  15. 40
      build-all-release.ps1
  16. 40
      build-all.ps1
  17. 16
      build/build-all-release.ps1
  18. 16
      build/build-all.ps1
  19. 34
      build/common.ps1
  20. 16
      build/test-all.ps1
  21. 2
      common.props
  22. 35
      docs/cs/Best-Practices/PostgreSQL-Integration.md
  23. 22
      docs/cs/CLI.md
  24. 39
      docs/cs/Entity-Framework-Core-PostgreSQL.md
  25. 2
      docs/cs/Getting-Started-Angular-Template.md
  26. 113
      docs/cs/Getting-Started-AspNetCore-Application.md
  27. 10
      docs/cs/Index.md
  28. 80
      docs/cs/docs-nav.json
  29. BIN
      docs/cs/images/authorization-new-permission-ui-hierarcy.png
  30. BIN
      docs/cs/images/authorization-new-permission-ui-localized.png
  31. BIN
      docs/cs/images/authorization-new-permission-ui.png
  32. BIN
      docs/cs/images/create-aspnet-core-application.png
  33. BIN
      docs/cs/images/create-new-aspnet-core-application-v2.png
  34. BIN
      docs/cs/images/docs-section-ui.png
  35. BIN
      docs/cs/images/select-empty-web-application-v2.png
  36. 3
      docs/en/Ambient-Context-Pattern.md
  37. 371
      docs/en/Audit-Logging.md
  38. 42
      docs/en/Background-Jobs-Hangfire.md
  39. 7
      docs/en/Best-Practices/Entity-Framework-Core-Integration.md
  40. 2
      docs/en/Best-Practices/Index.md
  41. 73
      docs/en/Best-Practices/PostgreSQL-Integration.md
  42. 164
      docs/en/Blog-Posts/2020-01-15 v2_0_Release/Post.md
  43. BIN
      docs/en/Blog-Posts/2020-01-15 v2_0_Release/abp-commercial-demo.png
  44. BIN
      docs/en/Blog-Posts/2020-01-15 v2_0_Release/abp-io-abpcommercial-release.png
  45. BIN
      docs/en/Blog-Posts/2020-01-15 v2_0_Release/lepton-theme-material.png
  46. BIN
      docs/en/Blog-Posts/2020-01-15 v2_0_Release/ndc-2020-volosoft-booth-wall.png
  47. BIN
      docs/en/Blog-Posts/2020-01-15 v2_0_Release/ndc-london-volosoft.png
  48. 18
      docs/en/CLI.md
  49. 91
      docs/en/Connection-Strings.md
  50. 29
      docs/en/Contribution/Localization-Text-Files.md
  51. 12
      docs/en/Data-Access.md
  52. 18
      docs/en/Dependency-Injection.md
  53. 173
      docs/en/Entities.md
  54. 58
      docs/en/Entity-Framework-Core-MySQL.md
  55. 90
      docs/en/Entity-Framework-Core-Other-DBMS.md
  56. 41
      docs/en/Entity-Framework-Core-PostgreSQL.md
  57. 41
      docs/en/Entity-Framework-Core-SQLite.md
  58. 46
      docs/en/Entity-Framework-Core.md
  59. 58
      docs/en/FluentValidation.md
  60. 5
      docs/en/Logging.md
  61. 7
      docs/en/Modules/Audit-Logging.md
  62. 3
      docs/en/Modules/Blogging.md
  63. 111
      docs/en/Modules/Docs.md
  64. 3
      docs/en/Modules/IdentityServer.md
  65. 22
      docs/en/Modules/Index.md
  66. 4
      docs/en/Modules/Setting-Management.md
  67. 116
      docs/en/Options.md
  68. 53
      docs/en/Settings.md
  69. 2
      docs/en/Tutorials/Angular/Part-I.md
  70. 4
      docs/en/Tutorials/AspNetCore-Mvc/Part-I.md
  71. 3
      docs/en/Tutorials/AspNetCore-Mvc/Part-II.md
  72. 159
      docs/en/Validation.md
  73. 3
      docs/en/Virtual-File-System.md
  74. 65
      docs/en/docs-nav.json
  75. BIN
      docs/en/images/auditlog-object-diagram.png
  76. BIN
      docs/en/images/docs-section-ui.png
  77. 3
      docs/pt-BR/Tutorials/AspNetCore-Mvc/Part-II.md
  78. 2
      docs/pt-BR/docs-nav.json
  79. 7
      docs/zh-Hans/Best-Practices/Entity-Framework-Core-Integration.md
  80. 164
      docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/Post.md
  81. BIN
      docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/abp-commercial-demo.png
  82. BIN
      docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/lepton-theme-material.png
  83. BIN
      docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/ndc-2020-volosoft-booth-wall.png
  84. BIN
      docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/ndc-london-volosoft.png
  85. 64
      docs/zh-Hans/Connection-Strings.md
  86. 0
      docs/zh-Hans/Entity-Framework-Core-PostgreSQL.md
  87. 59
      docs/zh-Hans/FluentValidation.md
  88. 5
      docs/zh-Hans/Logging.md
  89. 85
      docs/zh-Hans/Modules/Setting-Management.md
  90. 51
      docs/zh-Hans/Settings.md
  91. 10
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md
  92. 3
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md
  93. 164
      docs/zh-Hans/Validation.md
  94. 3
      docs/zh-Hans/Virtual-File-System.md
  95. 11
      docs/zh-Hans/docs-nav.json
  96. 16
      framework/Volo.Abp.sln
  97. 4
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs
  98. 6
      framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction.cs
  99. 8
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs
  100. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs

11
.github/labeler.yml

@ -1,4 +1,15 @@
ui-angular:
- npm/ng-packs/*
- npm/ng-packs/**/*
- npm/ng-packs/**/**/*
- npm/ng-packs/**/**/**/*
- npm/ng-packs/**/**/**/**/*
- npm/ng-packs/**/**/**/**/**/*
- templates/app/angular/*
- templates/app/angular/**/*
- templates/app/angular/**/**/*
- templates/app/angular/**/**/**/*
- templates/module/angular/*
- templates/module/angular/**/*
- templates/module/angular/**/**/*
- templates/module/angular/**/**/**/*

21
.github/workflows/labeler.yml

@ -1,17 +1,12 @@
name: "Pull Request Labeler"
name: Pull request labeler
on:
pull_request:
paths:
- npm/ng-packs/**/*
- templates/app/angular/**/*
- templates/module/angular/**/*
branches:
- master
- dev
schedule:
- cron: '0 12 */1 * *'
jobs:
labeler:
runs-on: ubuntu-18.04
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v2
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
- uses: paulfantom/periodic-labeler@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}

2
README.md

@ -27,6 +27,8 @@ Framework solution is located under the `framework` folder. It has no external d
[Modules](modules/) and [Templates](templates/) have their own solutions and have **local references** to the framework and each other.
Visual Studio can not work properly with the local references out of the solution folder. When you open a module/sample solution in the Visual Studio, you may get some errors related to the dependencies. In this case, run the `dotnet restore` on the command prompt for the related solution's folder. You need to run it after you first open the solution or change a dependency.
### Contribution
ABP is an open source platform. Check [the contribution guide](docs/en/Contribution/Index.md) if you want to contribute to the project.

2
abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalization.csproj

@ -5,7 +5,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\framework\src\Volo.Abp.Localization\Volo.Abp.Localization.csproj" />
<ProjectReference Include="..\..\..\framework\src\Volo.Abp.Validation\Volo.Abp.Validation.csproj" />
</ItemGroup>
<ItemGroup>

5
abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalizationModule.cs

@ -8,13 +8,14 @@ using AbpIoLocalization.Support.Localization;
using AbpIoLocalization.Www;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Localization.Resources.AbpValidation;
using Volo.Abp.Modularity;
using Volo.Abp.Validation;
using Volo.Abp.Validation.Localization;
using Volo.Abp.VirtualFileSystem;
namespace AbpIoLocalization
{
[DependsOn(typeof(AbpLocalizationModule))]
[DependsOn(typeof(AbpValidationModule))]
public class AbpIoLocalizationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)

13
abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hant.json

@ -0,0 +1,13 @@
{
"culture": "zh-Hant",
"texts": {
"Account": "帳號",
"Welcome": "歡迎",
"UseOneOfTheFollowingLinksToContinue": "使用下面的連結繼續",
"FrameworkHomePage": "框架首頁",
"FrameworkDocumentation": "框架文件",
"OfficialBlog": "官方部落格",
"CommercialHomePage": "商業版首頁",
"CommercialSupportWebSite": "商業版支援網站"
}
}

60
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hant.json

@ -0,0 +1,60 @@
{
"culture": "zh-Hant",
"texts": {
"Permission:NpmPackages": "NPM套件",
"Permission:NugetPackages": "Nuget套件",
"Permission:Maintenance": "維護",
"Permission:Maintain": "維護",
"Permission:ClearCaches": "清除快取",
"Permission:Modules": "模組",
"Permission:Packages": "套件",
"Permission:Edit": "編輯",
"Permission:Delete": "刪除",
"Permission:Create": "建立",
"Menu:Packages": "套件",
"NpmPackageDeletionWarningMessage": "該NPM套件將會被刪除. 你確定嗎?",
"NugetPackageDeletionWarningMessage": "該Nuget套件將會被刪除. 你確定嗎?",
"ModuleDeletionWarningMessage": "該模組將會被刪除. 你確定嗎?",
"Name": "名稱",
"DisplayName": "顯示名稱",
"ShortDescription": "簡述",
"NameFilter": "名稱",
"CreationTime": "建立時間",
"IsPro": "是否為專業版",
"EfCoreConfigureMethodName": "設定方法",
"IsProFilter": "是否為專業版",
"ApplicationType": "應用程式類型",
"Target": "目標",
"TargetFilter": "目標",
"ModuleClass": "模組分類",
"NugetPackageTarget.DomainShared": "Domain Shared",
"NugetPackageTarget.Domain": "Domain",
"NugetPackageTarget.Application": "Application",
"NugetPackageTarget.ApplicationContracts": "Application Contracts",
"NugetPackageTarget.HttpApi": "Http Api",
"NugetPackageTarget.HttpApiClient": "Http Api Client",
"NugetPackageTarget.Web": "Web",
"NugetPackageTarget.EntityFrameworkCore": "EntityFramework Core",
"NugetPackageTarget.MongoDB": "MongoDB",
"Edit": "編輯",
"Delete": "刪除",
"Refresh": "刷新",
"NpmPackages": "NPM套件",
"NugetPackages": "Nuget套件",
"NpmPackageCount": "NPM套件數量",
"NugetPackageCount": "Nuget套件數量",
"Module": "模組",
"ModuleInfo": "模組信息",
"CreateANpmPackage": "建立NPM套件",
"CreateAModule": "建立模組",
"CreateANugetPackage": "建立Nuget套件",
"AddNew": "建立",
"PackageAlreadyExist{0}": "\"{0}\"已經被添加.",
"ClearCache": "清除快取",
"SuccessfullyCleared": "清除成功",
"Menu:NpmPackages": "NPM套件",
"Menu:Modules": "模組",
"Menu:Maintenance": "維護",
"Menu:NugetPackages": "Nuget套件"
}
}

31
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hant.json

@ -0,0 +1,31 @@
{
"culture": "zh-Hant",
"texts": {
"Volo.AbpIo.Domain:010004": "超過最大成員數!",
"Volo.AbpIo.Domain:010005": "超過最大擁有者數!",
"Volo.AbpIo.Domain:010006": "使用者已經是該組織的擁有者!",
"Volo.AbpIo.Domain:010007": "該使用者已經是該組織的開發者!",
"Volo.AbpIo.Domain:010008": "允許的開發者數量不能低於當前開發者數量!",
"Volo.AbpIo.Domain:010009": "允許的開發者數量不能小於零!",
"Volo.AbpIo.Domain:010010": "超出了最大mac地址數!",
"Volo.AbpIo.Domain:010011": "個人許可不允許超過1個開發者!",
"Volo.AbpIo.Domain:010012": "許可過期後許可不可延長1個月!",
"Volo.AbpIo.Domain:020001": "不能刪除該NPM套件因為\"{NugetPackages}\"Nuget套件依賴此套件.",
"Volo.AbpIo.Domain:020002": "不能刪除該NPM套件因為\"{Modules}\"模組正在使用此套件.",
"Volo.AbpIo.Domain:020003": "不能刪除該NPM套件因為\"{Modules}\"模組正在使用此套件並且\"{NugetPackages}\"Nuget套件依賴此套件.",
"Volo.AbpIo.Domain:020004": "不能刪除該Nuget套件因為\"{Modules}\"模組正在使用此套件.",
"WantToLearn?": "想學習嗎?",
"ReadyToGetStarted?": "準備開始了嗎?",
"JoinOurCommunity": "加入我們的社群",
"GetStartedUpper": "開始",
"ForkMeOnGitHub": "Fork me on GitHub",
"Features": "功能",
"GetStarted": "開始",
"Documents": "文件",
"Community": "社群",
"ContributionGuide": "貢獻指南",
"Blog": "部落格",
"Commercial": "商業版",
"SeeDocuments": "查看文件"
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/zh-Hant.json

@ -0,0 +1,5 @@
{
"culture": "zh-Hant",
"texts": {
}
}

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

@ -25,6 +25,7 @@
"Volo.AbpIo.Commercial:010004": "Can not find the specified user! The user must have already registered.",
"MyOrganizations": "My organizations",
"ApiKey": "API key",
"UserNameNotFound": "There is no user with username {0}"
"UserNameNotFound": "There is no user with username {0}",
"SuccessfullyAddedToNewsletter": "Thanks you for subscribing to our newsletter!"
}
}

30
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json

@ -0,0 +1,30 @@
{
"culture": "zh-Hant",
"texts": {
"OrganizationManagement": "組織管理",
"OrganizationList": "組織列表",
"Volo.AbpIo.Commercial:010003": "您不是該組織的擁有者!",
"OrganizationNotFoundMessage": "找不到任何組織!",
"DeveloperCount": "開發者數量",
"Owners": "擁有者",
"AddMember": "加入成員",
"AddOwner": "加入擁有者",
"AddDeveloper": "加入開發者",
"UserName": "使用者名稱",
"Name": "名稱",
"EmailAddress": "電子信箱地址",
"Developers": "開發者",
"LicenseType": "許可證類型",
"Manage": "管理",
"StartDate": "開始日期",
"EndDate": "結束日期",
"Modules": "模組",
"LicenseExtendMessage": "您的許可已經延長至{0}",
"LicenseUpgradeMessage": "您的許可已升級為{0}",
"LicenseAddDeveloperMessage": "{0}個開發者已加入到您的許可",
"Volo.AbpIo.Commercial:010004": "不能找到指定的使用者! 使用者必須已經註冊.",
"MyOrganizations": "我的組織",
"ApiKey": "API key",
"UserNameNotFound": "沒有使用者名稱為{0}的使用者"
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/zh-Hant.json

@ -0,0 +1,5 @@
{
"culture": "zh-Hant",
"texts": {
}
}

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

@ -0,0 +1,5 @@
{
"culture": "zh-Hant",
"texts": {
}
}

159
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json

@ -0,0 +1,159 @@
{
"culture": "zh-Hant",
"texts": {
"GetStarted": "開始",
"Create": "建立",
"NewProject": "新專案",
"DirectDownload": "直接下載",
"ProjectName": "專案名稱",
"ProjectType": "專案類型",
"DatabaseProvider": "資料庫提供者",
"NTier": "N層",
"IncludeUserInterface": "包含使用者介面",
"CreateNow": "現在建立",
"TheStartupProject": "起始專案",
"Tutorial": "教學",
"UsingCLI": "使用CLI",
"SeeDetails": "看詳細",
"AbpShortDescription": "ABP是用於建立現代Web應用程式的完整架構和強大的基礎設施! 遵循最佳實作和約定,為您提供SOLID開發經驗.",
"SourceCodeUpper": "原始碼",
"LatestReleaseLogs": "最新發佈日誌",
"Infrastructure": "基礎設施",
"Architecture": "架構",
"Modular": "模組化",
"DontRepeatYourself": "不要重複工作",
"DeveloperFocused": "專注於開發者",
"FullStackApplicationInfrastructure": "全端應用程式基礎設施",
"DomainDrivenDesign": "領域驅動設計",
"DomainDrivenDesignExplanation": "依據DDD模式和準則進行設計和開發. 為您的應用程式提供分層模型.",
"Authorization": "授權",
"AuthorizationExplanation": "具有使用者,角色和細膩度權限系統的高級授權. 建立於Microsoft Identity套件上.",
"MultiTenancy": "多租戶",
"MultiTenancyExplanationShort": "SaaS應用程式變得簡單! 從資料庫到UI的多租戶整合.",
"CrossCuttingConcerns": "橫切關注點",
"CrossCuttingConcernsExplanationShort": "完整的基礎架構,用於授權,驗證,異常處理,快取,稽核日誌,交易管理等.",
"BuiltInBundlingMinification": "內建Bundling & Minification",
"BuiltInBundlingMinificationExplanation": "無須使用外部工具進行Bundling & Minification. ABP提供了一種更簡單,動態,功能強大,模組化和內建的方式!",
"VirtualFileSystem": "虛擬文件系統",
"VirtualFileSystemExplanation": "將檢視,腳本,樣式,圖片...嵌入到套件/類別庫中,並在不同的應用程式中重複使用.",
"Theming": "主題",
"ThemingExplanationShort": "使用和訂製基於bootstrap的標準UI主題,或建立自己的主題.",
"BootstrapTagHelpersDynamicForms": "Bootstrap Tag Helpers和動態表單",
"BootstrapTagHelpersDynamicFormsExplanation": "內建的背景作業系統可以整合到Hangfire,RabbitMQ或您喜歡的任何工具中.", //TODO explanation doesn't match.
"HTTPAPIsDynamicProxies": "HTTP APIs和動態代理",
"HTTPAPIsDynamicProxiesExplanation": "自動將應用程式服務公開為REST樣式的HTTP API,並與動態JavaScript和C#代理一起使用.",
"CompleteArchitectureInfo": "現在架構用來建立可維護的軟體解決方案.",
"DomainDrivenDesignBasedLayeringModelExplanation": "幫助您實現基於DDD的分層架構並建構可維護的程式碼.",
"DomainDrivenDesignBasedLayeringModelExplanationCont": "提供啟動模板,抽象,基礎類別,服務,文件和指南以幫助您開發基於DDD模式和準則的應用程式.",
"MicroserviceCompatibleModelExplanation": "核心框架和預先建構模組在設計時就考慮了微服務架構.",
"MicroserviceCompatibleModelExplanationCont": "提供基礎結構,整合,範例和文件,以更輕鬆地實現微服務解決方案,而如果您要使用整體應用程式,也不會帶來額外的複雜性.",
"ModularInfo": "ABP提供了完整的模組化系統,使您能夠開發可重複使用的應用程式模組.",
"PreBuiltModulesThemes": "預先建構模組和主題",
"PreBuiltModulesThemesExplanation": "開源和商業模組和主題已準備好在您的業務應用程式中使用.",
"NuGetNPMPackages": "NuGet和NPM套件",
"NuGetNPMPackagesExplanation": "作為NuGet和NPM套件發佈.易於安裝和升級.",
"ExtensibleReplaceable": "可擴展/可替換",
"ExtensibleReplaceableExplanation": "所有服務和模組在設計時都考慮了可擴展性.您可以替換服務,頁面,樣式,組件...",
"CrossCuttingConcernsExplanation2": "保持原始碼整潔,專注於您自己的業務邏輯.",
"CrossCuttingConcernsExplanation3": "不要浪費時間一次又一次地實作共通用的應用程式需求.",
"AuthenticationAuthorization": "認證與授權",
"ExceptionHandling": "異常處理",
"Validation": "驗證",
"DatabaseConnection": "資料庫連接",
"TransactionManagement": "交易管理",
"AuditLogging": "稽核日誌",
"Caching": "快取",
"Multitenancy": "多租戶",
"DataFiltering": "資料過濾",
"ConventionOverConfiguration": "習慣優於設定",
"ConventionOverConfigurationExplanation": "預設情況下,ABP使用最小或零設定實現共通用的應用程式.",
"ConventionOverConfigurationExplanationList1": "自動註冊已知服務以進行依賴注入.",
"ConventionOverConfigurationExplanationList2": "通過命名習慣將應用程式服務公開為HTTP API.",
"ConventionOverConfigurationExplanationList3": "為C#和JavaScript建立動態HTTP客戶端代理.",
"ConventionOverConfigurationExplanationList4": "為您的實體提供預設Repository.",
"ConventionOverConfigurationExplanationList5": "根據Web請求或應用程式服務方法管理工作單元.",
"ConventionOverConfigurationExplanationList6": "為實體發佈建立,更新和刪除事件.",
"BaseClasses": "基礎類別",
"BaseClassesExplanation": "共通用應用程式模式的預先建構基礎類別.",
"DeveloperFocusedExplanation": "ABP是為了開發者",
"DeveloperFocusedExplanationCont": "它旨在簡化您的日常軟體開發,同時又不限制您在需要時進行底層工作。",
"SeeAllFeatures": "瀏覽所有功能",
"CLI_CommandLineInterface": "CLI (命令列介面)",
"CLI_CommandLineInterfaceExplanation": "CLI會自動建立新專案並將模組添加到您的應用程式.",
"StartupTemplates": "起始模板",
"StartupTemplatesExplanation": "各種起始模板為您提供了完整設定的解結方案,以快速啟動您的開發.",
"BasedOnFamiliarTools": "基於熟悉的工具",
"BasedOnFamiliarToolsExplanation": "建立在您已經知道的主流工具上並與其整合.學習曲線低,適應性強,舒適的開發.",
"ORMIndependent": "ORM獨立",
"ORMIndependentExplanation": "核心框架獨立於ORM/資料庫,並且可以與任何資料庫一起使用.Entity Framework Core和MongoDB提供者已經可用.",
"Features": "功能",
"ABPCLI": "ABP CLI",
"Modularity": "模組化",
"BootstrapTagHelpers": "Bootstrap Tag Helpers",
"DynamicForms": "動態表單",
"BundlingMinification": "Bundling & Minification",
"BackgroundJobs": "背景作業",
"DDDInfrastructure": "DDD基礎設施",
"DomainDrivenDesignInfrastructure": "Domain Driven Design基礎設施",
"AutoRESTAPIs": "自動REST APIs",
"DynamicClientProxies": "動態客戶端代理",
"DistributedEventBus": "分散式事件匯流排",
"DistributedEventBusWithRabbitMQIntegration": "具有RabbitMQ整合的分散式事件匯流排",
"TestInfrastructure": "測試基礎設施",
"AuditLoggingEntityHistories": "稽核日誌和實體歷史",
"ObjectToObjectMapping": "物件對應",
"EmailSMSAbstractions": "電子郵件和簡訊抽象",
"EmailSMSAbstractionsWithTemplatingSupport": "具有模板支援的電子郵件和簡訊抽象",
"Localization": "本地化",
"SettingManagement": "設定管理",
"ExtensionMethods": "擴充方法",
"ExtensionMethodsHelpers": "擴充方法和助手",
"AspectOrientedProgramming": "切面導向設計",
"DependencyInjection": "依賴注入",
"DependencyInjectionByConventions": "依照習慣的依賴注入",
"ABPCLIExplanation": "ABP CLI(命令列介面)是用於對ABP解決方案執行常見操作的命令列工具.",
"ModularityExplanation": "ABP提供了一個完整的基礎設施來建構您自己的應用程式模組,這些模組可能具有實體,服務,資料庫整合,API,UI組件等.", //TODO: strong "your own application modules",-
"MultiTenancyExplanation": "ABP框建不僅支援開發多租戶應用程式,而且使您的程式碼幾乎無須知道多租戶.",
"MultiTenancyExplanation2": "可以自動確定當前租戶,將不同租戶的資料互相隔離.",
"MultiTenancyExplanation3": "支援單一資料庫,或每個租戶單獨資料庫或者混合方式.",
"MultiTenancyExplanation4": "您專注於業務邏輯,並讓該框架為您處理多租戶.",
"BootstrapTagHelpersExplanation": "與其手動撰寫重複細節的bootstrap組件,不如使用ABP的tag helper來簡化它並利用自動完成.您當然也可以在需要時直接使用Bootstrap.",
"DynamicFormsExplanation": "動態表單和tag helpers可以利用C#類別做為模型來建立完整的表單.",
"AuthenticationAuthorizationExplanation": "整合到ASP.NET Core Identity和IdentityServer4的豐富身份驗證和授權選項.提供可擴展且詳細的權限系統.",
"CrossCuttingConcernsExplanation": "部要重複資幾一次又一次地實作所有這寫常見的東西.專注於您的業務邏輯,並讓ABP按照習慣自動執行.",
"DatabaseConnectionTransactionManagement": "資料庫連接和交易管理",
"CorrelationIdTracking": "關聯ID追蹤",
"BundlingMinificationExplanation": "ABP提供了一個簡單,動態,功能強大,模組化的內建Bundling & Minification系統.",
"VirtualFileSystemnExplanation": "虛擬文件系統使管理文件系統(硬碟)上不存在的文件成為可能.它主要用於將(js,css,image,cshtml...)文件嵌入到組件(Assembly)中,並在運行時像實體文件一樣使用他們.",
"ThemingExplanation": "主題系統允許通過基於最新的Bootstrap框架定義一組通用基礎類別庫和佈局來獨立開發應用程式和模組主題.",
"DomainDrivenDesignInfrastructureExplanation": "基於領域驅動設計模式和準則建構分層應用程式的完整基礎設施;",
"Specification": "規範",
"Repository": "倉儲",
"DomainService": "領域服務",
"ValueObject": "值對象",
"ApplicationService": "應用服務",
"DataTransferObject": "資料傳輸對象",
"AggregateRootEntity": "聚合根, 實體",
"AutoRESTAPIsExplanation": "ABP可以依照習慣自動將您的應用服務設定為API控制器.",
"DynamicClientProxiesExplanation": "從JavaScript和C#客戶端輕鬆使用您的API.",
"DistributedEventBusWithRabbitMQIntegrationExplanation": "使用帶有RabbitMQ整合的內建分散式事件匯流排,可以輕鬆發佈和使用分散式事件.",
"TestInfrastructureExplanation": "框架已經考慮了單元和整合測試.為您提供基礎類別,使其更容易.起始模板已預先設定用於測試.",
"AuditLoggingEntityHistoriesExplanation": "針對關鍵業務應用的內建稽核日誌紀錄.請求,服務,方法級別的稽核日誌紀錄以及具有屬性級別詳細資訊的實體歷史紀錄.",
"EmailSMSAbstractionsWithTemplatingSupportExplanation": "IEmailSender和ISmsSender抽象使您的應用程式邏輯與基礎設施解耦.先進的電子郵件模板系統允許建立和在地化電子郵件模板,並在需要實輕鬆使用.",
"LocalizationExplanation": "在地化系統允許在純JSON文件中建立資源,並使用它們來在地化UI.它支援繼承,擴展和JavaScript整合等高級方案,同時與AspNet Core的在地化系統完全兼容.",
"SettingManagementExplanation": "定義應用程式的設定,並根據當前設定,租戶和使用者在運行時獲取值.",
"ExtensionMethodsHelpersExplanation": "即使式瑣碎的程式碼部分,也不要重複.標準類型的擴展方法和助手使您的程式碼更加清晰和易於撰寫.",
"AspectOrientedProgrammingExplanation": "提供合適的基礎設施來建立動態代理並實現切面導向設計.攔截任何類別,並在每次方法執行之前和之後執行程式碼.",
"DependencyInjectionByConventionsExplanation": "無須手動註冊類別以進行依賴注入.按照習慣自動註冊常用服務類型.對於其他類型的服務,您可以使用介面和屬性來使其變得更輕鬆.",
"DataFilteringExplanation": "定義和使用資料過濾器,這些過濾器在您從資料庫中查詢實體時會自動應用.當您實現簡單的介面時,可立即使用軟刪除功能和多租戶過濾器.",
"PublishEvents": "發佈事件",
"HandleEvents": "處理事件",
"AndMore": "更多...",
"Code": "編碼",
"Result": "結果",
"SeeTheDocumentForMoreInformation": "查看<a href=\"{1}\">{0} 文件</a>獲得更多訊息",
"IndexPageHeroSection": "<span class=\"third-line shine2\"><strong>asp.net core的</strong></span><span class=\"first-line shine\"><strong>開源</strong></span><span class=\"second-line text-uppercase\">Web應用程式<br />框架 </span>",
"UiFramework": "UI框架",
"EmailAddress": "電子信箱地址"
}
}

40
build-all-release.ps1

@ -1,40 +0,0 @@
# COMMON PATHS
$rootFolder = (Get-Item -Path "./" -Verbose).FullName
# List of solutions
$solutionPaths = (
"framework",
"modules/users",
"modules/permission-management",
"modules/setting-management",
"modules/feature-management",
"modules/identity",
"modules/identityserver",
"modules/tenant-management",
"modules/account",
"modules/docs",
"modules/blogging",
"modules/audit-logging",
"modules/background-jobs",
"modules/client-simulation",
"templates/module/aspnet-core",
"templates/app/aspnet-core",
"abp_io/AbpIoLocalization"
)
# Build all solutions
foreach ($solutionPath in $solutionPaths) {
$solutionAbsPath = (Join-Path $rootFolder $solutionPath)
Set-Location $solutionAbsPath
dotnet build --configuration Release
if (-Not $?) {
Write-Host ("Build failed for the solution: " + $solutionPath)
Set-Location $rootFolder
exit $LASTEXITCODE
}
}
Set-Location $rootFolder

40
build-all.ps1

@ -1,40 +0,0 @@
# COMMON PATHS
$rootFolder = (Get-Item -Path "./" -Verbose).FullName
# List of solutions
$solutionPaths = (
"framework",
"modules/users",
"modules/permission-management",
"modules/setting-management",
"modules/feature-management",
"modules/identity",
"modules/identityserver",
"modules/tenant-management",
"modules/account",
"modules/docs",
"modules/blogging",
"modules/audit-logging",
"modules/background-jobs",
"modules/client-simulation",
"templates/module/aspnet-core",
"templates/app/aspnet-core",
"abp_io/AbpIoLocalization"
)
# Build all solutions
foreach ($solutionPath in $solutionPaths) {
$solutionAbsPath = (Join-Path $rootFolder $solutionPath)
Set-Location $solutionAbsPath
dotnet build
if (-Not $?) {
Write-Host ("Build failed for the solution: " + $solutionPath)
Set-Location $rootFolder
exit $LASTEXITCODE
}
}
Set-Location $rootFolder

16
build/build-all-release.ps1

@ -0,0 +1,16 @@
. ".\common.ps1"
# Build all solutions
foreach ($solutionPath in $solutionPaths) {
$solutionAbsPath = (Join-Path $rootFolder $solutionPath)
Set-Location $solutionAbsPath
dotnet build --configuration Release
if (-Not $?) {
Write-Host ("Build failed for the solution: " + $solutionPath)
Set-Location $rootFolder
exit $LASTEXITCODE
}
}
Set-Location $rootFolder

16
build/build-all.ps1

@ -0,0 +1,16 @@
. ".\common.ps1"
# Build all solutions
foreach ($solutionPath in $solutionPaths) {
$solutionAbsPath = (Join-Path $rootFolder $solutionPath)
Set-Location $solutionAbsPath
dotnet build
if (-Not $?) {
Write-Host ("Build failed for the solution: " + $solutionPath)
Set-Location $rootFolder
exit $LASTEXITCODE
}
}
Set-Location $rootFolder

34
build/common.ps1

@ -0,0 +1,34 @@
# COMMON PATHS
$rootFolder = (Get-Item -Path "./" -Verbose).FullName
# List of solutions
$solutionPaths = (
"../framework",
"../modules/users",
"../modules/permission-management",
"../modules/setting-management",
"../modules/feature-management",
"../modules/identity",
"../modules/identityserver",
"../modules/tenant-management",
"../modules/account",
"../modules/docs",
"../modules/blogging",
"../modules/audit-logging",
"../modules/background-jobs",
"../modules/client-simulation",
"../templates/module/aspnet-core",
"../templates/app/aspnet-core",
"../samples/BasicAspNetCoreApplication",
"../samples/BasicConsoleApplication",
"../samples/BookStore",
"../samples/BookStore-Angular-MongoDb/aspnet-core",
"../samples/BookStore-Modular/modules/book-management",
"../samples/BookStore-Modular/application",
"../samples/DashboardDemo",
"../samples/MicroserviceDemo",
"../samples/RabbitMqEventBus",
"../abp_io/AbpIoLocalization"
)

16
build/test-all.ps1

@ -0,0 +1,16 @@
. ".\common.ps1"
# Test all solutions
foreach ($solutionPath in $solutionPaths) {
$solutionAbsPath = (Join-Path $rootFolder $solutionPath)
Set-Location $solutionAbsPath
dotnet test --no-build --no-restore
if (-Not $?) {
Write-Host ("Test failed for the solution: " + $solutionPath)
Set-Location $rootFolder
exit $LASTEXITCODE
}
}
Set-Location $rootFolder

2
common.props

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>1.1.1</Version>
<Version>2.1.0</Version>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>https://abp.io</PackageProjectUrl>

35
docs/cs/Best-Practices/PostgreSQL-Integration.md

@ -1,35 +0,0 @@
## Entity Framework Core PostgreSQL integrace
> Podívejte se na [Entity Framework Core integrační dokument](../Entity-Framework-Core.md) pro základy integrace EF Core.
### Aktualizace projektu EntityFrameworkCore
- V projektu `Acme.BookStore.EntityFrameworkCore` nahraďte balík `Volo.Abp.EntityFrameworkCore.SqlServer` za `Volo.Abp.EntityFrameworkCore.PostgreSql`
- Aktualizace pro použití PostgreSQL v `BookStoreEntityFrameworkCoreModule`
- Nahraďte `AbpEntityFrameworkCoreSqlServerModule` za `AbpEntityFrameworkCorePostgreSqlModule`
- Nahraďte `options.UseSqlServer()` za `options.UsePostgreSql()`
- V jiných projektech aktualizujte PostgreSQL connection string v nezbytných `appsettings.json` souborech
#### Odstranění stávajících migrací
Smažte všechny stavající migrační soubory (včetně `DbContextModelSnapshot`)
![postgresql-delete-initial-migrations](images/postgresql-delete-initial-migrations.png)
#### Znovu vygenerujte počáteční migraci & aktualizujte databázi
Nastavte správný spouštěcí projekt (obvykle web projekt),
Otevřete **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), zvolte `Acme.BookStore.EntityFrameworkCore.DbMigrations` jako **Default project** a proveďte následující příkaz:
Proveďte příkaz `Add-Migration`:
````
PM> Add-Migration Initial
````
Poté proveďte příkaz `Update-Database` k aktualizaci schématu databáze:
````
PM> Update-Database
````
![postgresql-update-database](images/postgresql-update-database.png)

22
docs/cs/CLI.md

@ -46,11 +46,13 @@ abp new Acme.BookStore
* `--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.
* `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.
* `--database-provider` nebo `-d`: Určuje poskytovatele databáze. Výchozí poskytovatel je `ef`. Dostupní poskytovatelé:
* `ef`: Entity Framework Core.
* `mongodb`: MongoDB.
* `module`: [Šablona modulu](Startup-Templates/Module.md). Dodatečné možnosti:
* `--no-ui`: Určuje nezahrnutí uživatelského rozhraní. Umožňuje vytvořit moduly pouze pro služby (a.k.a. mikroslužby - bez uživatelského rozhraní).
* `--no-ui`: Určuje nezahrnutí uživatelského rozhraní. Umožňuje vytvořit moduly pouze pro služby (a.k.a. mikroslužby - bez uživatelského rozhraní).
* `--output-folder` nebo `-o`: Určuje výstupní složku. Výchozí hodnota je aktuální adresář.
* `--version` nebo `-v`: Určuje verzi ABP & šablony. Může to být [štítek vydání](https://github.com/abpframework/abp/releases) nebo [název větve](https://github.com/abpframework/abp/branches). Pokud není uvedeno, používá nejnovější vydání. Většinou budete chtít použít nejnovější verzi.
@ -127,6 +129,24 @@ abp update [možnosti]
* `--npm`: Aktualizuje pouze balíčky NPM.
* `--nuget`: Aktualizuje pouze balíčky NuGet.
### login
Některé funkce CLI vyžadují přihlášení k platformě abp.io. Chcete-li se přihlásit pomocí svého uživatelského jména, napište
```bash
abp login <username>
```
Všimněte si, že nové přihlášení s již aktivní relací ukončí předchozí relaci a vytvoří novou.
### logout
Odhlásí vás odebráním tokenu relace z počítače.
```
abp logout
```
### help
Vypíše základní informace k používání CLI.

39
docs/cs/Entity-Framework-Core-PostgreSQL.md

@ -0,0 +1,39 @@
# Přepnutí na EF Core PostgreSQL providera
Tento dokument vysvětluje, jak přepnout na poskytovatele databáze **PostgreSQL** pro **[spouštěcí šablonu aplikace](Startup-Templates/Application.md)**, která je dodávána s předem nakonfigurovaným SQL poskytovatelem.
## Výměna balíku Volo.Abp.EntityFrameworkCore.SqlServer
Projekt `.EntityFrameworkCore` v řešení závisí na NuGet balíku [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer). Odstraňte tento balík a přidejte stejnou verzi balíku [Volo.Abp.EntityFrameworkCore.PostgreSql](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.PostgreSql).
## Nahrazení závislosti modulu
Najděte třídu ***YourProjectName*EntityFrameworkCoreModule** v projektu `.EntityFrameworkCore`, odstraňte `typeof(AbpEntityFrameworkCoreSqlServerModule)` z atributu `DependsOn`, přidejte `typeof(AbpEntityFrameworkCorePostgreSqlModule)` (také nahraďte `using Volo.Abp.EntityFrameworkCore.SqlServer;` za `using Volo.Abp.EntityFrameworkCore.PostgreSql;`).
## UsePostgreSql()
Najděte volání `UseSqlServer()` v *YourProjectName*EntityFrameworkCoreModule.cs uvnitř projektu `.EntityFrameworkCore` a nahraďte za `UsePostgreSql()`.
Najděte volání `UseSqlServer()` v *YourProjectName*MigrationsDbContextFactory.cs uvnitř projektu `.EntityFrameworkCore.DbMigrations` a nahraďte za `UseNpgsql()`.
> V závislosti na struktuře řešení můžete najít více volání `UseSqlServer()`, které je třeba změnit.
## Změna connection stringů
PostgreSql connection stringy se od těch pro SQL Server liší. Je proto potřeba zkontrolovat všechny soubory `appsettings.json` v řešení a connection stringy v nich nahradit. Podívejte se na [connectionstrings.com](https://www.connectionstrings.com/postgresql/) pro více detailů o možnostech PostgreSql connection stringů.
Typicky je potřeba změnit `appsettings.json` v projektech `.DbMigrator` a `.Web` projects, ale to záleží na vaší struktuře řešení.
## Regenerace migrací
Startovací šablona používá [Entity Framework Core Code First migrace](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core migrace závisí na zvoleném DBMS poskytovateli. Tudíž změna DBMS poskytovatele způsobí selhání migrace.
* Smažte složku Migrations v projektu `.EntityFrameworkCore.DbMigrations` and znovu sestavte řešení.
* Spusťte `Add-Migration "Initial"` v Package Manager Console (je nutné zvolit `.DbMigrator` (nebo `.Web`) projekt jako startovací projekt v Solution Explorer a zvolit projekt `.EntityFrameworkCore.DbMigrations` jako výchozí v Package Manager Console).
Tímto vytvoříte migraci databáze se všemi nakonfigurovanými databázovými objekty (tabulkami).
Spusťte projekt `.DbMigrator` k vytvoření databáze a vložení počátečních dat.
## Spuštění aplikace
Vše je připraveno. Stačí už jen spustit aplikaci a užívat si kódování.

2
docs/cs/Getting-Started-Angular-Template.md

@ -75,7 +75,7 @@ Zmáčkněte F5 (nebo Ctrl+F5) ke spuštění aplikace. Výstup by měl být pod
#### Použití příkazu EF Core Update-Database
Ef Core máš příkaz `Update-Database`, který v případě potřeby vytvoří databázi a aplikuje čekající migrace. Klikněte pravým na projekt `.Web` a zvolte **Set as StartUp Project**:
Ef Core máš příkaz `Update-Database`, který v případě potřeby vytvoří databázi a aplikuje čekající migrace. Klikněte pravým na projekt `.HttpApi.Host` a zvolte **Set as StartUp Project**:
![set-as-startup-project](images/set-as-startup-project.png)

113
docs/cs/Getting-Started-AspNetCore-Application.md

@ -4,15 +4,17 @@ Tento tutoriál vysvětluje jak začít s ABP z ničeho s minimem závislostí.
## Tvorba nového projektu
1. Vytvořte novou prázdnou AspNet Core Web aplikaci ve Visual Studio:
1. Vytvořte novou AspNet Core Web aplikaci ve Visual Studio 2019 (16.3.0+):
![](images/create-new-aspnet-core-application.png)
![](images/create-new-aspnet-core-application-v2.png)
2. Zvolte prázdnou šablonu
2. Nakonfigurujte váš nový projekt:
![](images/select-empty-web-application.png)
![](images/select-empty-web-application-v2.png)
Můžete zvolit i jinou šablonu, ale pro demonstraci je lepší čístý projekt.
3. Potvrďte kliknutím na tlačítko vytvořit
![create-aspnet-core-application](images/create-aspnet-core-application.png)
## Instalace Volo.Abp.AspNetCore.Mvc balíku
@ -28,10 +30,8 @@ ABP je modulární framework a proto vyžaduje **spouštěcí (kořenový) modul
````C#
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Volo.Abp;
using Volo.Abp.AspNetCore.Modularity;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;
@ -40,7 +40,8 @@ namespace BasicAspNetCoreApplication
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
public class AppModule : AbpModule
{
public override void OnApplicationInitialization(ApplicationInitializationContext context)
public override void OnApplicationInitialization(
ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
@ -49,8 +50,14 @@ namespace BasicAspNetCoreApplication
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseMvcWithDefaultRoute();
app.UseStaticFiles();
app.UseRouting();
app.UseMvcWithDefaultRouteAndArea();
}
}
}
@ -58,7 +65,7 @@ namespace BasicAspNetCoreApplication
``AppModule`` je dobrý název pro spouštěcí modul aplikace.
ABP balíky definují modulové třídy a modul může mít závislost na jiný modul. V kódu výše, náš ``AppModule`` má závislost na ``AbpAspNetCoreMvcModule`` (definován v balíku Volo.Abp.AspNetCore.Mvc). Je běžné přidat ``DependsOn`` atribute po instalaci nového ABP NuGet balíku.
ABP balíky definují modulové třídy a modul může mít závislost na jiném. V kódu výše, ``AppModule`` má závislost na ``AbpAspNetCoreMvcModule`` (definován v balíku [Volo.Abp.AspNetCore.Mvc](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Mvc)). Je běžné přidat ``DependsOn`` atribute po instalaci nového ABP NuGet balíku.
Místo třídy Startup, konfigurujeme ASP.NET Core pipeline v této modulové třídě.
@ -67,7 +74,6 @@ Místo třídy Startup, konfigurujeme ASP.NET Core pipeline v této modulové t
V dalším kroku upravíme Startup třídu k integraci ABP modulového systému:
````C#
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
@ -75,11 +81,9 @@ namespace BasicAspNetCoreApplication
{
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
public void ConfigureServices(IServiceCollection services)
{
services.AddApplication<AppModule>();
return services.BuildServiceProviderFromFactory();
}
public void Configure(IApplicationBuilder app)
@ -88,41 +92,19 @@ namespace BasicAspNetCoreApplication
}
}
}
````
Změnili jsme metodu ``ConfigureServices`` aby vracela ``IServiceProvider`` místo ``void``. Tato změna nám dovoluje nahradit AspNet Core vkládání závislostí za jiný framework (více v sekci Autofac integrace níže). ``services.AddApplication<AppModule>()`` přidává všechny služby definované ve všech modulech počínaje ``AppModule``.
``services.AddApplication<AppModule>()`` přidává všechny služby definované ve všech modulech počínaje od ``AppModule``.
Volání ``app.InitializeApplication()`` v metodě ``Configure`` inicializuje a spustí aplikaci.
``app.InitializeApplication()`` v metodě ``Configure`` inicializuje a spustí aplikaci.
## Ahoj světe!
## Spusťte aplikaci!
Aplikace výše zatím nic nedělá. Pojďme proto vytvořit MVC controller, který už něco dělá:
````C#
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
namespace BasicAspNetCoreApplication.Controllers
{
public class HomeController : AbpController
{
public IActionResult Index()
{
return Content("Hello World!");
}
}
}
````
Jakmile spustíte aplikaci, uvidíte na stránce zprávu "Hello World!".
Odvození ``HomeController`` od ``AbpController`` místo standardní třídy ``Controller``. Toto není vyžadováno, ale třída ``AbpController`` má užitečné základní vlastnosti a metody, které usnadňují vývoj.
To je vše! Spusťte aplikaci, bude fungovat podle očekávání.
## Použití Autofac jako frameworku pro vkládání závislostí
Ačkoliv je AspNet Core systém pro vkládání závíslostí (DI) skvělý pro základní požadavky, Autofac poskytuje pokročilé funkce jako injekce vlastností nebo záchyt metod, které jsou v ABP užity k provádění pokročilých funkcí frameworku.
Ačkoliv je AspNet Core systém pro vkládání závíslostí (DI) dostatečný pro základní požadavky, [Autofac](https://autofac.org/) poskytuje pokročilé funkce jako injekce vlastností nebo záchyt metod, které jsou v ABP užity k provádění pokročilých funkcí frameworku.
Nahrazení AspNet Core DI systému za Autofac a integrace s ABP je snadná.
@ -143,40 +125,29 @@ public class AppModule : AbpModule
}
````
3. Změníme řádek ``services.AddApplication<AppModule>();`` v třídě ``Startup`` následovně:
````C#
services.AddApplication<AppModule>(options =>
{
options.UseAutofac(); // Integrace s Autofac
});
````
4. Upravíme `Program.cs` aby nepoužíval metodu `WebHost.CreateDefaultBuilder()` jelikož ta používá výchozí DI kontejner:
3. Upravíme `Program.cs` aby používal Autofac:
````csharp
public class Program
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace BasicAspNetCoreApplication
{
public static void Main(string[] args)
public class Program
{
/*
https://github.com/aspnet/AspNetCore/issues/4206#issuecomment-445612167
CurrentDirectoryHelpers exists in: \framework\src\Volo.Abp.AspNetCore.Mvc\Microsoft\AspNetCore\InProcess\CurrentDirectoryHelpers.cs
Will remove CurrentDirectoryHelpers.cs when upgrade to ASP.NET Core 3.0.
*/
CurrentDirectoryHelpers.SetCurrentDirectory();
BuildWebHostInternal(args).Run();
}
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IWebHost BuildWebHostInternal(string[] args) =>
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIIS()
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseAutofac(); // Přidejte tento řádek
}
}
````

10
docs/cs/Index.md

@ -4,18 +4,12 @@ ABP je **open source aplikační framework** se zaměřením na vývoj webových
K procházení dokumentace využijte navigační nabídky vlevo.
## Stav projektu
ABP je **novou generací** open source frameworku [ASP.NET Boilerplate](https://aspnetboilerplate.com/). V současné době je v náhledové fázi a není připraven k ostrému nasazení. Na dokumentaci se stále pracuje a ještě zdaleka není dokončena.
Pro aplikace na krátkodobé a ostré nasazení je doporučeno použít [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework, který je bohatý na funkce, vyspělý, aktivně udržovaný a aktuální.
## Začínáme
Nejsnazší cestou jak začít nový projekt s ABP je užití startovací šablony:
* [ASP.NET Core MVC (Razor Pages) UI Šablona](Getting-Started-AspNetCore-MVC-Template.md)
* [Angular UI Šablona](Getting-Started-Angular-Template.md)
* [ASP.NET Core MVC (Razor Pages) UI Počáteční Šablona](Getting-Started-AspNetCore-MVC-Template.md)
* [Angular UI Počáteční Šablona](Getting-Started-Angular-Template.md)
Pokud chcete začít od nuly (s prázdným projektem) tak manuálně nainstalujte ABP Framework s pomocí následujících tutoriálů:

80
docs/cs/docs-nav.json

@ -56,6 +56,14 @@
{
"text": "Základy",
"items": [
{
"text": "Konfigurace",
"path": "Configuration.md"
},
{
"text": "Možnosti",
"path": "Options.md"
},
{
"text": "Vkládání závislostí",
"path": "Dependency-Injection.md",
@ -79,19 +87,29 @@
"path": "Exception-Handling.md"
},
{
"text": "Validace"
"text": "Validace",
"path": "Validation.md",
"items": [
{
"text": "FluentValidation integrace",
"path": "FluentValidation.md"
}
]
},
{
"text": "Autorizace"
"text": "Autorizace",
"path": "Authorization.md"
},
{
"text": "Ukládání do mezipaměti"
"text": "Ukládání do mezipaměti",
"path": "Caching.md"
},
{
"text": "Audit"
},
{
"text": "Správa nastavení"
"text": "Nastavení",
"path": "Settings.md"
}
]
},
@ -114,6 +132,14 @@
{
"text": "Služby",
"items": [
{
"text": "Současný uživatel",
"path": "CurrentUser.md"
},
{
"text": "Mapování objekt na objekt",
"path": "Object-To-Object-Mapping.md"
},
{
"text": "Serializace objektu"
},
@ -242,24 +268,46 @@
},
{
"text": "Přístup k datům",
"path": "Data-Access.md",
"items": [
{
"text": "Entity Framework Core integrace",
"path": "Entity-Framework-Core.md",
"text": "Connection stringy",
"path": "Connection-Strings.md"
},
{
"text": "Poskytovatelé databází",
"items": [
{
"text": "PostgreSQL integrace",
"path": "Best-Practices/PostgreSQL-Integration.md"
"text": "Entity Framework Core",
"path": "Entity-Framework-Core.md",
"items": [
{
"text": "Přepnutí na MySQL",
"path": "Entity-Framework-Core-MySQL.md"
},
{
"text": "Přepnutí na PostgreSQL",
"path": "Entity-Framework-Core-PostgreSQL.md"
},
{
"text": "Přepnutí na SQLite",
"path": "Entity-Framework-Core-SQLite.md"
},
{
"text": "Přepnutí na jiný DBMS",
"path": "Entity-Framework-Core-Other-DBMS.md"
}
]
},
{
"text": "MongoDB",
"path": "MongoDB.md"
},
{
"text": "Dapper",
"path": "Dapper.md"
}
]
},
{
"text": "MongoDB integrace",
"path": "MongoDB.md"
},
{
"text": "Dapper integrace",
"path": "Dapper.md"
}
]
},

BIN
docs/cs/images/authorization-new-permission-ui-hierarcy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
docs/cs/images/authorization-new-permission-ui-localized.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
docs/cs/images/authorization-new-permission-ui.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
docs/cs/images/create-aspnet-core-application.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
docs/cs/images/create-new-aspnet-core-application-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

BIN
docs/cs/images/docs-section-ui.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

BIN
docs/cs/images/select-empty-web-application-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

3
docs/en/Ambient-Context-Pattern.md

@ -0,0 +1,3 @@
## Ambient Context Pattern
TODO

371
docs/en/Audit-Logging.md

@ -1,3 +1,372 @@
# Audit Logging
TODO
[Wikipedia](https://en.wikipedia.org/wiki/Audit_trail): "*An audit trail (also called **audit log**) is a security-relevant chronological record, set of records, and/or destination and source of records that provide documentary evidence of the sequence of activities that have affected at any time a specific operation, procedure, or event*".
ABP Framework provides an **extensible audit logging system** that automates the audit logging by **convention** and provides **configuration** points to control the level of the audit logs.
An **audit log object** (see the Audit Log Object section below) is typically created & saved per web request. It includes;
* **Request & response details** (like URL, Http method, Browser info, HTTP status code... etc.).
* **Performed actions** (controller actions and application service method calls with their parameters).
* **Entity changes** occurred in the web request.
* **Exception** information (if there was an error while executing the request).
* **Request duration** (to measure the performance of the application).
> [Startup templates](Startup-Templates/Index.md) are configured for the audit logging system which is suitable for most of the applications. Use this document for a detailed control over the audit log system.
### Database Provider Support
* Fully supported by the [Entity Framework Core](Entity-Framework-Core.md) provider.
* Entity change logging is not supported by the [MongoDB](MongoDB.md) provider. Other features work as expected.
## UseAuditing()
`UseAuditing()` middleware should be added to the ASP.NET Core request pipeline in order to create and save the audit logs. If you've created your applications using [the startup templates](Startup-Templates/Index.md), it is already added.
## AbpAuditingOptions
`AbpAuditingOptions` is the main [options object](Options.md) to configure the audit log system. You can configure it in the `ConfigureServices` method of your [module](Module-Development-Basics.md):
````csharp
Configure<AbpAuditingOptions>(options =>
{
options.IsEnabled = false; //Disables the auditing system
});
````
Here, a list of the options you can configure:
* `IsEnabled` (default: `true`): A root switch to enable or disable the auditing system. Other options is not used if this value is `false`.
* `HideErrors` (default: `true`): Audit log system hides and write regular [logs](Logging.md) if any error occurs while saving the audit log objects. If saving the audit logs is critical for your system, set this to `false` to throw exception in case of hiding the errors.
* `IsEnabledForAnonymousUsers` (default: `true`): If you want to write audit logs only for the authenticated users, set this to `false`. If you save audit logs for anonymous users, you will see `null` for `UserId` values for these users.
* `IsEnabledForGetRequests` (default: `false`): HTTP GET requests should not make any change in the database normally and audit log system doesn't save audit log objects for GET request. Set this to `true` to enable it also for the GET requests.
* `ApplicationName`: If multiple applications saving audit logs into a single database, set this property to your application name, so you can distinguish the logs of different applications.
* `IgnoredTypes`: A list of `Type`s to be ignored for audit logging. If this is an entity type, changes for this type of entities will not be saved. This list is also used while serializing the action parameters.
* `EntityHistorySelectors`: A list of selectors those are used to determine if an entity type is selected for saving the entity change. See the section below for details.
* `Contributors`: A list of `AuditLogContributor` implementations. A contributor is a way of extending the audit log system. See the "Audit Log Contributors" section below.
### Entity History Selectors
Saving all changes of all your entities would require a lot of database space. For this reason, **audit log system doesn't save any change for the entities unless you explicitly configure it**.
To save all changes of all entities, simply use the `AddAllEntities()` extension method.
````csharp
Configure<AbpAuditingOptions>(options =>
{
options.EntityHistorySelectors.AddAllEntities();
});
````
`options.EntityHistorySelectors` actually a list of type predicate. You can write a lambda expression to define your filter.
The example selector below does the same of the `AddAllEntities()` extension method defined above:
````csharp
Configure<AbpAuditingOptions>(options =>
{
options.EntityHistorySelectors.Add(
new NamedTypeSelector(
"MySelectorName",
type =>
{
if (typeof(IEntity).IsAssignableFrom(type))
{
return true;
}
else
{
return false;
}
}
)
);
});
````
The condition `typeof(IEntity).IsAssignableFrom(type)` will be `true` for any class implements the `IEntity` interface (this is technically all the entities in your application). You can conditionally check and return `true` or `false` based on your preference.
`options.EntityHistorySelectors` is a flexible and dynamic way of selecting the entities for audit logging. Another way is to use the `Audited` and `DisableAuditing` attributes per entity.
## Enabling/Disabling Audit Logging for Services
### Enable/Disable for Controllers & Actions
All the controller actions are logged by default (see `IsEnabledForGetRequests` above for GET requests).
You can use the `[DisableAuditing]` to disable it for a specific controller type:
````csharp
[DisableAuditing]
public class HomeController : AbpController
{
//...
}
````
Use `[DisableAuditing]` for any action to control it in the action level:
````csharp
public class HomeController : AbpController
{
[DisableAuditing]
public async Task<ActionResult> Home()
{
//...
}
public async Task<ActionResult> OtherActionLogged()
{
//...
}
}
````
### Enable/Disable for Application Services & Methods
[Application service](Application-Services.md) method calls also included into the audit log by default. You can use the `[DisableAuditing]` in service or method level.
#### Enable/Disable for Other Services
Action audit logging can be enabled for any type of class (registered to and resolved from the [dependency injection](Dependency-Injection.md)) while it is only enabled for the controllers and the application services by default.
Use `[Audited]` and `[DisableAuditing]` for any class or method that need to be audit logged. In addition, your class can (directly or inherently) implement the `IAuditingEnabled` interface to enable the audit logging for that class by default.
### Enable/Disable for Entities & Properties
An entity is ignored on entity change audit logging in the following cases;
* If you add an entity type to the `AbpAuditingOptions.IgnoredTypes` (as explained before), it is completely ignored in the audit logging system.
* If the object is not an [entity](Entities.md) (not implements `IEntity` directly or inherently - All entities implement this interface by default).
* If entity type is not public.
Otherwise, you can use `Audited` to enable entity change audit logging for an entity:
````csharp
[Audited]
public class MyEntity : Entity<Guid>
{
//...
}
````
Or disable it for an entity:
````csharp
[DisableAuditing]
public class MyEntity : Entity<Guid>
{
//...
}
````
Disabling audit logging can be necessary only if the entity is being selected by the `AbpAuditingOptions.EntityHistorySelectors` that explained before.
You can disable auditing only some properties of your entities for a detailed control over the audit logging:
````csharp
[Audited]
public class MyUser : Entity<Guid>
{
public string Name { get; set; }
public string Email { get; set; }
[DisableAuditing] //Ignore the Passoword on audit logging
public string Password { get; set; }
}
````
Audit log system will save changes for the `MyUser` entity while it ignores the `Password` property which can be dangerous to save for security purposes.
In some cases, you may want to save a few properties but ignore all others. Writing `[DisableAuditing]` for all the other properties would be tedious. In such cases, use `[Audited]` only for the desired properties and mark the entity with the `[DisableAuditing]` attribute:
````csharp
[DisableAuditing]
public class MyUser : Entity<Guid>
{
[Audited] //Only log the Name change
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
````
## IAuditingStore
`IAuditingStore` is an interface that is used to save the audit log objects (explained below) by the ABP Framework. If you need to save the audit log objects to a custom data store, you can implement the `IAuditingStore` in your own application and replace using the [dependency injection system](Dependency-Injection.md).
`SimpleLogAuditingStore` is used if no audit store was registered. It simply writes the audit object to the standard [logging system](Logging.md).
[The Audit Logging Module](Modules/Audit-Logging.md) has been configured in [the startup templates](Startup-Templates/Index.md) saves audit log objects to a database (it supports multiple database providers). So, most of the times you don't care about how `IAuditingStore` was implemented and used.
## Audit Log Object
An **audit log object** is created for each **web request** by default. An audit log object can be represented by the following relation diagram:
![**auditlog-object-diagram**](images/auditlog-object-diagram.png)
* **AuditLogInfo**: The root object with the following properties:
* `ApplicationName`: When you save audit logs of different applications to the same database, this property is used to distinguish the logs of the applications.
* `UserId`: Id of the current user, if the user has logged in.
* `UserName`: User name of the current user, if the user has logged in (this value is here to not depend on the identity module/system for lookup).
* `TenantId`: Id of the current tenant, for a multi-tenant application.
* `TenantName`: Name of the current tenant, for a multi-tenant application.
* `ExecutionTime`: The time when this audit log object has been created.
* `ExecutionDuration`: Total execution duration of the request, in milliseconds. This can be used to observe the performance of the application.
* `ClientId`: Id of the current client, if the client has been authenticated. A client is generally a 3rd-party application using the system over an HTTP API.
* `ClientName`: Name of the current client, if available.
* `ClientIpAddress`: IP address of the client/user device.
* `CorrelationId`: Current [Correlation Id](CorrelationId.md). Correlation Id is used to relate the audit logs written by different applications (or microservices) in a single logical operation.
* `BrowserInfo`: Browser name/version info of the current user, if available.
* `HttpMethod`: HTTP method of the current request (GET, POST, PUT, DELETE... etc.).
* `HttpStatusCode`: HTTP response status code for this request.
* `Url`: URL of the request.
* **AuditLogActionInfo**: An audit log action is typically a controller action or an [application service](Application-Services.md) method call during the web request. One audit log may contain multiple actions. An action object has the following properties:
* `ServiceName`: Name of the executed controller/service.
* `MethodName`: Name of the executed method of the controller/service.
* `Parameters`: A JSON formatted text representing the parameters passed to the method.
* `ExecutionTime`: The time when this method was executed.
* `ExecutionDuration`: Duration of the method execution, in milliseconds. This can be used to observe the performance of the method.
* **EntityChangeInfo**: Represents a change of an entity in this web request. An audit log may contain zero or more entity changes. An entity change has the following properties:
* `ChangeTime`: The time when the entity was changed.
* `ChangeType`: An enum with the following fields: `Created` (0), `Updated` (1) and `Deleted` (2).
* `EntityId`: Id of the entity that was changed.
* `EntityTenantId`: Id of the tenant this entity belongs to.
* `EntityTypeFullName`: Type (class) name of the entity with full namespace (like *Acme.BookStore.Book* for the Book entity).
* **EntityPropertyChangeInfo**: Represents a change of a property of an entity. An entity change info (explained above) may contain one or more property change with the following properties:
* `NewValue`: New value of the property. It is `null` if the entity was deleted.
* `OriginalValue`: Old/original value before the change. It is `null` if the entity was newly created.
* `PropertyName`: The name of the property on the entity class.
* `PropertyTypeFullName`: Type (class) name of the property with full namespace.
* **Exception**: An audit log object may contain zero or more exception. In this way, you can get a report of the failed requests.
* **Comment**: An arbitrary string value to add custom messages to the audit log entry. An audit log object may contain zero or more comments.
In addition to the standard properties explained above, `AuditLogInfo`, `AuditLogActionInfo` and `EntityChangeInfo` objects implement the `IHasExtraProperties` interface, so you can add custom properties to these objects.
## Audit Log Contributors
You can extend the auditing system by creating a class that is derived from the `AuditLogContributor` class which defines the `PreContribute` and the `PostContribute` methods.
The only pre-built contributor is the `AspNetCoreAuditLogContributor` class which sets the related properties for an HTTP request.
A contributor can set properties and collections of the `AuditLogInfo` class to add more information.
Example:
````csharp
public class MyAuditLogContributor : AuditLogContributor
{
public override void PreContribute(AuditLogContributionContext context)
{
var currentUser = context.ServiceProvider.GetRequiredService<ICurrentUser>();
context.AuditInfo.SetProperty(
"MyCustomClaimValue",
currentUser.FindClaimValue("MyCustomClaim")
);
}
public override void PostContribute(AuditLogContributionContext context)
{
context.AuditInfo.Comments.Add("Some comment...");
}
}
````
* `context.ServiceProvider` can be used to resolve services from the [dependency injection](Dependency-Injection.md).
* `context.AuditInfo` can be used to access to the current audit log object to manipulate it.
After creating such a contributor, you must add it to the `AbpAuditingOptions.Contributors` list:
````csharp
Configure<AbpAuditingOptions>(options =>
{
options.Contributors.Add(new MyAuditLogContributor());
});
````
## IAuditLogScope & IAuditingManager
This section explains the `IAuditLogScope` & `IAuditingManager` services for advanced use cases.
An **audit log scope** is an [ambient scope](Ambient-Context-Pattern.md) that **builds** and **saves** an audit log object (explained before). By default, an audit log scope is created for a web request by the Audit Log Middleware (see `UseAuditing()` section above).
### Access to the Current Audit Log Scope
Audit log contributors, was explained above, is a global way of manipulating the audit log object. It is good if you can get a value from a service.
If you need to manipulate the audit log object in an arbitrary point of your application, you can access to the current audit log scope and get the current audit log object (independent of how the scope is managed). Example:
````csharp
public class MyService : ITransientDependency
{
private readonly IAuditingManager _auditingManager;
public MyService(IAuditingManager auditingManager)
{
_auditingManager = auditingManager;
}
public async Task DoItAsync()
{
var currentAuditLogScope = _auditingManager.Current;
if (currentAuditLogScope != null)
{
currentAuditLogScope.Log.Comments.Add(
"Executed the MyService.DoItAsync method :)"
);
currentAuditLogScope.Log.SetProperty("MyCustomProperty", 42);
}
}
}
````
Always check if `_auditingManager.Current` is null or not, because it is controlled in an outer scope and you can't know if an audit log scope was created before calling your method.
### Manually Create an Audit Log Scope
You rarely need to create a manual audit log scope, but if you need, you can create an audit log scope using the `IAuditingManager` as like in the following example:
````csharp
public class MyService : ITransientDependency
{
private readonly IAuditingManager _auditingManager;
public MyService(IAuditingManager auditingManager)
{
_auditingManager = auditingManager;
}
public async Task DoItAsync()
{
using (var auditingScope = _auditingManager.BeginScope())
{
try
{
//Call other services...
}
catch (Exception ex)
{
//Add exceptions
_auditingManager.Current.Log.Exceptions.Add(ex);
}
finally
{
//Always save the log
await auditingScope.SaveAsync();
}
}
}
}
````
You can call other services, they may call others, they may change entities and so on. All these interactions are saved as a single audit log object in the finally block.
## The Audit Logging Module
The Audit Logging Module basically implements the `IAuditingStore` to save the audit log objects to a database. It supports multiple database providers. This module is added to the startup templates by default.
See [the Audit Logging Module document](Modules/Audit-Logging.md) for more about it.

42
docs/en/Background-Jobs-Hangfire.md

@ -1,3 +1,43 @@
# Hangfire Background Job Manager
TODO
[Hangfire](https://www.hangfire.io/) is an advanced background job manager. You can integrate Hangfire with the ABP Framework to use it instead of the [default background job manager](Background-Jobs.md). In this way, you can use the same background job API for Hangfire and your code will be independent of Hangfire. If you like, you can directly use Hangfire's API, too.
> See the [background jobs document](Background-Jobs.md) to learn how to use the background job system. This document only shows how to install and configure the Hangfire integration.
## Installation
It is suggested to use the [ABP CLI](CLI.md) to install this package.
### Using the ABP CLI
Open a command line window in the folder of the project (.csproj file) and type the following command:
````bash
abp add-package Volo.Abp.BackgroundJobs.HangFire
````
### Manual Installation
If you want to manually install;
1. Add the [Volo.Abp.BackgroundJobs.HangFire](https://www.nuget.org/packages/Volo.Abp.BackgroundJobs.HangFire) NuGet package to your project:
````
Install-Package Volo.Abp.BackgroundJobs.HangFire
````
2. Add the `AbpBackgroundJobsHangfireModule` to the dependency list of your module:
````csharp
[DependsOn(
//...other dependencies
typeof(AbpBackgroundJobsHangfireModule) //Add the new module dependency
)]
public class YourModule : AbpModule
{
}
````
## Configuration
TODO...

7
docs/en/Best-Practices/Entity-Framework-Core-Integration.md

@ -174,12 +174,12 @@ public static IQueryable<IdentityUser> IncludeDetails(
* **Do** use the `IncludeDetails` extension method in the repository methods just like used in the example code above (see FindByNormalizedUserNameAsync).
- **Do** override `IncludeDetails` method of the repository for aggregates root which have **sub collections**. Example:
- **Do** override `WithDetails` method of the repository for aggregates root which have **sub collections**. Example:
````C#
protected override IQueryable<IdentityUser> IncludeDetails(IQueryable<IdentityUser> queryable)
public override IQueryable<IdentityUser> WithDetails()
{
return queryable.IncludeDetails(); //uses the extension method defined above
return GetQueryable().IncludeDetails(); // Uses the extension method defined above
}
````
@ -206,4 +206,3 @@ public class AbpIdentityEntityFrameworkCoreModule : AbpModule
}
}
````

2
docs/en/Best-Practices/Index.md

@ -23,5 +23,5 @@ Also, this guide is mostly usable for general **application development**.
* [Data Transfer Objects](Data-Transfer-Objects.md)
* Data Access
* [Entity Framework Core Integration](Entity-Framework-Core-Integration.md)
* [MongoDB Integration](MongoDB-Integration.md)
* [MongoDB Integration](MongoDB-Integration.md)

73
docs/en/Best-Practices/PostgreSQL-Integration.md

@ -1,73 +0,0 @@
## Entity Framework Core PostgreSQL Integration
> See [Entity Framework Core Integration document](../Entity-Framework-Core.md) for the basics of the EF Core integration.
### EntityFrameworkCore Project Update
- In `Acme.BookStore.EntityFrameworkCore` project replace package `Volo.Abp.EntityFrameworkCore.SqlServer` with `Volo.Abp.EntityFrameworkCore.PostgreSql`
- Update to use PostgreSQL in `BookStoreEntityFrameworkCoreModule`
- Replace the `AbpEntityFrameworkCoreSqlServerModule` with the `AbpEntityFrameworkCorePostgreSqlModule`
- Replace the `options.UseSqlServer()` with the `options.UsePostgreSql()`
- In other projects update the PostgreSQL connection string in necessary `appsettings.json` files
- more info of [PostgreSQL connection strings](https://www.connectionstrings.com/postgresql/),You need to pay attention to `Npgsql` in this document
### EntityFrameworkCore.DbMigrations Project Update
- Update to use PostgreSQL in `XXXMigrationsDbContextFactory`
- Replace the `new DbContextOptionsBuilder<XXXMigrationsDbContext>().UseSqlServer()` with the `new DbContextOptionsBuilder<XXXMigrationsDbContext>().UseNpgsql()`
### Delete Existing Migrations
Delete all existing migration files (including `DbContextModelSnapshot`)
![postgresql-delete-initial-migrations](images/postgresql-delete-initial-migrations.png)
### Regenerate Initial Migration
Set the correct startup project (usually a web project)
![set-as-startup-project](../images/set-as-startup-project.png)
Open the **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), select the `.EntityFrameworkCore.DbMigrations` as the **Default project** and execute the following command:
Run `Add-Migration` command.
````
PM> Add-Migration Initial
````
### Update the Database
You have two options to create the database.
#### Using the DbMigrator Application
The solution contains a console application (named `Acme.BookStore.DbMigrator` in this sample) that can create database, apply migrations and seed initial data. It is useful on development as well as on production environment.
> `.DbMigrator` project has its own `appsettings.json`. So, if you have changed the connection string above, you should also change this one.
Right click to the `.DbMigrator` project and select **Set as StartUp Project**:
![set-as-startup-project](../images/set-as-startup-project.png)
Hit F5 (or Ctrl+F5) to run the application. It will have an output like shown below:
![set-as-startup-project](../images/db-migrator-app.png)
#### Using EF Core Update-Database Command
Ef Core has `Update-Database` command which creates database if necessary and applies pending migrations.
Set the correct startup project (usually a web project)
![set-as-startup-project](../images/set-as-startup-project.png)
Open the **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), select the `.EntityFrameworkCore.DbMigrations` as the **Default project** and execute the following command:
````
PM> Update-Database
````
This will create a new database based on the configured connection string.
![postgresql-update-database](images/postgresql-update-database.png)
> Using the `.DbMigrator` tool is the suggested way, because it also seeds the initial data to be able to properly run the web application.

164
docs/en/Blog-Posts/2020-01-15 v2_0_Release/Post.md

@ -0,0 +1,164 @@
# ABP Framework v2.0 and the ABP Commercial
ABP Framework v2.0 has been released in this week. This post explains why we have released an **early major version** and what is changed with version 2.0.
In addition to the v2.0 release, we are excited to announce the **ABP Commercial**, which is a set of professional modules, tools, themes, and services built on top of the open-source ABP framework.
## ABP Framework v2.0
### Why 2.0 instead of 1.2?
It was planned to release v1.2 after the [v1.1.2](https://github.com/abpframework/abp/releases/tag/1.1.2) release. However, [it is reported](https://github.com/abpframework/abp/issues/2026) that v1.x has some **performance** and **stability** issues on Linux, especially when you deploy your application to **Linux** containers with **low CPU and memory** resources.
We have investigated the problem deeply and have seen that the root cause of the problem was related to the implementation of **intercepting `async` methods**. Besides, there were some **`async` over `sync`** usages that effected the thread pool optimization.
Finally, we **solved all the problems** with the great help of the **community**. But we also had some important **design decisions** which cause some **breaking changes** and we had to change the major version number of the framework because of the [semantic versioning](https://semver.org/).
Most of the applications won't be affected by [the breaking changes](https://github.com/abpframework/abp/releases), or it will be trivial to make these necessary changes.
### Breaking Changes
#### Removed Some Sync APIs
Some of the interceptors are required to use `async` APIs. When they intercept `sync` methods, they need to call `async` over `sync`. This eventually ends up with `async` over `sync` problem. That's why we have [removed some sync APIs](https://github.com/abpframework/abp/pull/2464).
**`Async` over `sync`** pattern is a classical problem of `C#` when you need to **call an `async` method inside a `sync` method**. While there are some workarounds to this problem, they all have **disadvantages** and it is suggested to **not write** such code at all. You can find many documents related to this topic on the web.
To avoid this problem, we have removed:
- `sync` [repository](https://docs.abp.io/en/abp/latest/Repositories) methods (like `insert`, `update`, etc...),
- `sync` APIs of the [unit of work](https://docs.abp.io/en/abp/latest/Unit-Of-Work),
- `sync` APIs of the [background jobs](https://docs.abp.io/en/abp/latest/Background-Jobs),
- `sync` APIs of the [audit logging](https://docs.abp.io/en/abp/latest/Audit-Logging),
- some other rarely used `sync` APIs.
If you get any compile error, just use the `async` versions of these APIs.
#### Always Async!
Beginning from the v2.0, the ABP framework assumes that you are writing your application code `async` first. Otherwise, some framework functionalities may not properly work.
It is suggested to write `async` to all your [application services](https://docs.abp.io/en/abp/latest/Application-Services), [repository methods](https://docs.abp.io/en/abp/latest/Repositories), controller actions, page handlers.
Even if your application service method doesn't need to be `async` , set it as `async` , because interceptors perform `async` operations (for authorization, unit of work, etc...). You can return `Task.Completed` from a method that doesn't make an `async` call.
Example:
````csharp
public Task<int> GetValueAsync()
{
//this method doesn't make any async call.
return Task.CompletedTask(42);
}
````
The example above normally doesn't need to be `async` because it doesn't perform an `async` call. However, making it `async` helps the ABP framework to run interceptors without `async` over sync calls.
This rule doesn't force you to write every method `async` . This would not be good and would be tedious. It is only needed for the intercepted services (especially for [application services](https://docs.abp.io/en/abp/latest/Application-Services) and [repository methods](https://docs.abp.io/en/abp/latest/Repositories))
#### Other Breaking Changes
See [the release notes](https://github.com/abpframework/abp/releases/tag/2.0.0) for the other breaking changes. Most of them will not affect your application code.
### New Features
This release also contains some new features and tens of enhancements:
- [#2597](https://github.com/abpframework/abp/pull/2597) New `Volo.Abp.AspNetCore.Serilog` package.
- [#2526](https://github.com/abpframework/abp/issues/2526) Client-side validation for the dynamic `C#` client proxies.
- [#2374](https://github.com/abpframework/abp/issues/2374) `Async` background jobs.
- [#265](https://github.com/abpframework/abp/issues/265) Managing the application shutdown.
- [#2472](https://github.com/abpframework/abp/issues/2472) Implemented `DeviceFlowCodes` and `TokenCleanupService` for the `IdentityServer` module.
See [the release notes](https://github.com/abpframework/abp/releases/tag/2.0.0) for the complete list of features, enhancements and bug fixes.
### Documentation
We have completed some missing documentation with the v2.0 release. In the following weeks, we will mostly focus on the documentation and tutorials.
## ABP Commercial
[ABP Commercial](https://commercial.abp.io/) is a set of professional **modules, tools, themes, and services** built on top of the open-source ABP framework.
- It provides [professional modules](https://commercial.abp.io/modules) in addition to the ABP Framework's free & [open source modules](https://docs.abp.io/en/abp/latest/Modules/Index).
- It includes a beautiful a [UI theme](https://commercial.abp.io/themes) with 5 different styles.
- It provides the [ABP Suite](https://commercial.abp.io/tools/suite); A tool to assist your development to make you more productive. It currently can create full-stack CRUD pages in a few seconds by configuring your entity properties. More functionalities will be added over time.
- [Premium support](https://commercial.abp.io/support) for enterprise companies.
In addition to these standard set of features, we will provide customer basis services. See the [commercial.abp.io](https://commercial.abp.io/) web site for other details.
### ABP Framework vs the ABP Commercial
The ABP Commercial **is not a paid version** of the ABP Framework. You can consider it as **set of additional benefits** for professional companies. You can use it to save your time and develop your product faster.
ABP Framework is **open source & free** and will always be like that!
As a principle, we build the main infrastructure as open-source and sell additional pre-built application features, themes, and tools. The main idea similar to the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) & the [ASP.NET Zero](https://aspnetzero.com/) products.
Buying a commercial license saves your significant time and effort and you can focus on your own business, besides you get dedicated and high priority support. Also, you will be supporting the ABP core team since we are spending most of our time to develop, maintain and support the open-source ABP Framework.
With the introduction of the ABP Commercial, now ABP becomes a platform. We call it as the **ABP.IO Platform** which consists of the open source ABP Framework and the ABP Commercial.
### Demo
If you are wondering how exactly looks like the ABP Commercial application startup template, you can easily [create a demo](https://commercial.abp.io/demo) and see it in action. The demo includes all the pre-built modules and the theme.
Here, a screenshot from the IdentityServer management module UI:
![abp-commercial-demo](abp-commercial-demo.png)
This is another screenshot from a demo application using the material design style of the theme:
![lepton-theme-material](lepton-theme-material.png)
### Pricing
You can build **unlimited projects/products**, sell to **unlimited customers**, host **unlimited servers** without any restriction. Pricing is mostly based on the **developer count**, **support level** and **source code** requirement. There are three main packages;
- **Team license**: Includes all the modules, themes and tools. Allows developing your product with up to 3 developers. You can buy additional developer licenses.
- **Business license**: Allows downloading the source code of all the modules and the themes. Also, it includes 5 developer licenses by default. You can buy additional developer licenses.
- **Enterprise license**: Provides unlimited and private support in addition to the benefits of the business license.
See the [pricing page](https://commercial.abp.io/pricing) for details. In addition to the standard packages, we are also providing custom services and custom licensing. [Contact us](https://commercial.abp.io/contact) if you have any questions.
#### License Comparison
The license price changes based on your developer count, support level and source-code access.
##### The Source-Code
Team license doesn't include the source-code of the pre-built modules & themes. It uses all these modules as **NuGet & NPM packages**. In this way, you can easily **get new features and bug fixes** by just updating the package dependencies. But you can't access their source-code. So you don't have the possibility to embed a module's source code into your application and freely change the source-code.
Pre-built modules provide some level of **customization** and **extensibility** and allow you to override services, UI parts and so on. We are working on to make them much more customizable and extensible. If you don't need to make major changes in the pre-built modules, the team license will be ideal for you, because it is cheaper and allows you to easily get new features and bug fixes.
Business and Enterprise licenses allow you to **download the source-code** of any module or the theme when you need it. They also use the same startup template with the team license, so all modules are used as `NuGet` & `NPM` packages by default. But in case of need, you can remove the package dependencies for a module and embed its source-code into your own solution to completely customize it. In this case, upgrading the module will not be as easy as before when a new version is available. You don't have to upgrade it, surely! But if you want, you should do it yourself using some merge tool or Git branch system.
#### License Lifetime
ABP Commercial license is **perpetual**, which means you can **use it forever** and continue to develop your applications.
However, the following services are covered for one year:
- Premium **support** ends after one year. You can continue to get community support.
- You can not get **updates** of the modules & the themes after one year. You can continue to use the last obtained version. You can even get bug fixes and enhancements for your current major version.
- You can use the **ABP Suite** tool for one year.
If you want to continue to get these benefits, you can extend your license period. Renewing price is 20% less than the regular price.
## NDC London 2020
Just like the [previous year](https://medium.com/volosoft/impressions-of-ndc-london-2019-f8f391bb7a9c), we are a partner of the famous software development conference: [NDC London](https://ndc-london.com/)! In the previous year, we were there with the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) & [ASP.NET Zero](https://aspnetzero.com/) theme:
![ndc-london-volosoft](ndc-london-volosoft.png)
This year, we will be focusing on the **ABP.IO Platform** (The Open Source ABP Framework and the ABP Commercial). Our booth wall will be like that:
![ndc-london-volosoft](ndc-2020-volosoft-booth-wall.png)
If you attend to the conference, remember to visit our booth. We would be glad to talk about the ABP platform features, goals and software development in general.
### Would you like to meet the ABP Team?
If you are in London and want to have a coffee with us, we will be available at February 1st afternoon. [@hibrahimkalkan](https://twitter.com/hibrahimkalkan) and [@ismcagdas](https://twitter.com/ismcagdas) will be there.
Just write to info@abp.io if you want to meet :)

BIN
docs/en/Blog-Posts/2020-01-15 v2_0_Release/abp-commercial-demo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

BIN
docs/en/Blog-Posts/2020-01-15 v2_0_Release/abp-io-abpcommercial-release.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
docs/en/Blog-Posts/2020-01-15 v2_0_Release/lepton-theme-material.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

BIN
docs/en/Blog-Posts/2020-01-15 v2_0_Release/ndc-2020-volosoft-booth-wall.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

BIN
docs/en/Blog-Posts/2020-01-15 v2_0_Release/ndc-london-volosoft.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

18
docs/en/CLI.md

@ -128,6 +128,24 @@ abp update [options]
* `--npm`: Only updates NPM packages.
* `--nuget`: Only updates NuGet packages.
### login
Some features of the CLI requires to be logged in to abp.io platform. To login with your username write
```bash
abp login <username>
```
Notice that, a new login with an already active session, will kill the previous session and creates a new one.
### logout
Logs you out by removing the session token from your computer.
```
abp logout
```
### help
Writes basic usage information of the CLI.

91
docs/en/Connection-Strings.md

@ -1,11 +1,88 @@
# Data Access
# Connection Strings
ABP framework was designed as database agnostic, it can work any type of data source by the help of the [repository](Repositories.md) and [unit of work](Unit-Of-Work.md) abstractions.
ABP Framework is designed to be [modular](Module-Development-Basics.md), [microservice compatible](Microservice-Architecture.md) and [multi-tenancy](Multi-Tenancy.md) aware. Connection string management is also designed to support these scenarios;
However, currently the following providers are implements:
* Allows to set separate connection strings for every module, so every module can have its own physical database. Modules even might be configured to use different DBMSs.
* Allows to set separate connection string and use a separate database per tenant (in a SaaS application).
* [Entity Framework Core](Entity-Framework-Core.md) (works with [various DBMS and providers](https://docs.microsoft.com/en-us/ef/core/providers/?tabs=dotnet-core-cli).)
* [MongoDB](MongoDB.md)
* [Dapper](Dapper.md)
It also supports hybrid scenarios;
More providers might be added in the next releases.
* Allows to group modules into databases (all modules into a single shared database, 2 modules to database A, 3 modules to database B, 1 module to database C and rest of the modules to database D... etc.)
* Allows to group tenants into databases, just like the modules.
* Allows to separate databases per tenant per module (which might be harder to maintain for you because of too many databases, but the ABP framework supports it).
All the [pre-built application modules](Modules/Index.md) are designed to be compatible these scenarios.
## Configure the Connection Strings
See the following configuration:
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=MyMainDb;Trusted_Connection=True;",
"AbpIdentityServer": "Server=localhost;Database=MyIdsDb;Trusted_Connection=True;",
"AbpPermissionManagement": "Server=localhost;Database=MyPermissionDb;Trusted_Connection=True;"
}
````
> ABP uses the `IConfiguration` service to get the application configuration. While the simplest way to write configuration into the `appsettings.json` file, it is not limited to this file. You can use environment variables, user secrets, Azure Key Vault... etc. See the [configuration](Configuration.md) document for more.
This configuration defines three different connection strings:
* `MyMainDb` (the `Default` connection string) is the main connection string of the application. If you don't specify a connection string for a module, it fallbacks to the `Default` connection string. The [application startup template](Startup-Templates/Application.md) is configured to use a single connection string, so all the modules uses a single shared database.
* `MyIdsDb` is used by the [IdentityServer](Modules/IdentityServer.md) module.
* `MyPermissionDb` is used by the [Permission Management](Modules/Permission-Management.md) module.
[Pre-built application modules](Modules/Index.md) define constants for the connection string names. For example, the IdentityServer module defines a ` ConnectionStringName ` constant in the ` AbpIdentityServerDbProperties ` class (located in the ` Volo.Abp.IdentityServer ` namespace). Other modules similarly define constants, so you can investigate the connection string name.
### AbpDbConnectionOptions
ABP actually uses the `AbpDbConnectionOptions` to get the connection strings. If you set the connection strings as explained above, `AbpDbConnectionOptions` is automatically filled. However, you can set or override the connection strings using [the options pattern](Options.md). You can configure the `AbpDbConnectionOptions` in the `ConfigureServices` method of your [module](Module-Development-Basics.md) as shown below:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpDbConnectionOptions>(options =>
{
options.ConnectionStrings.Default = "...";
options.ConnectionStrings["AbpPermissionManagement"] = "...";
});
}
````
## Set the Connection String Name
A module typically has a unique connection string name associated to its `DbContext` class using the `ConnectionStringName` attribute. Example:
````csharp
[ConnectionStringName("AbpIdentityServer")]
public class IdentityServerDbContext
: AbpDbContext<IdentityServerDbContext>, IIdentityServerDbContext
{
}
````
For [Entity Framework Core](Entity-Framework-Core.md) and [MongoDB](MongoDB.md), write this to your `DbContext` class (and the interface if it has).
> If you are developing a reusable, database provider independent module see also [the best practices guide](Best-Practices/Index.md).
## Database Migrations for the Entity Framework Core
Relational databases require to create the database and the database schema (tables, views... etc.) before using it.
The startup template (with EF Core ORM) comes with a single database and a `.EntityFrameworkCore.DbMigrations` project that contains the migration files for that database. This project mainly defines a *YourProjectName*MigrationsDbContext that calls the `Configure...()` methods of the used modules, like `builder.ConfigurePermissionManagement()`.
Once you want to separate a module's database, you typically will need to create a second migration path. The easiest way to create a copy of the `.EntityFrameworkCore.DbMigrations` project with the `DbContext` inside it, change its content to only call the `Configure...()` methods of the modules needs to be stored in the second database and re-create the initial migration. In this case, you also need to change the `.DbMigrator` application to be able to work with these second database too. In this way, you will have a separate migrations DbContext per database.
## Multi-Tenancy
See [the multi-tenancy document](Multi-Tenancy.md) to learn how to use separate databases for tenants.
## Replace the Connection String Resolver
ABP defines the `IConnectionStringResolver` and uses it whenever it needs a connection string. It has two pre-built implementations:
* `DefaultConnectionStringResolver` uses the `AbpDbConnectionOptions` to select the connection string based on the rules defined in the "Configure the Connection Strings" section above.
* `MultiTenantConnectionStringResolver` used for multi-tenant applications and tries to get the configured connection string for the current tenant if available. It uses the `ITenantStore` to find the connection strings. It inherits from the `DefaultConnectionStringResolver` and fallbacks to the base logic if no connection string specified for the current tenant.
If you need a custom logic to determine the connection string, implement the `IConnectionStringResolver` interface (optionally derive from the existing implementations) and replace the existing implementation using the [dependency injection](Dependency-Injection.md) system.

29
docs/en/Contribution/Localization-Text-Files.md

@ -3,7 +3,7 @@
Here, a list of localization text files for anyone wants to contribute to localization of the texts coming from the framework. We will keep this list up to date:
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en.json
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/en.json
* https://github.com/abpframework/abp/blob/master/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/en.json
* https://github.com/abpframework/abp/tree/master/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Localization/Resource/en.json
@ -12,29 +12,20 @@ Here, a list of localization text files for anyone wants to contribute to locali
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json
* https://github.com/abpframework/abp/tree/master/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/SourceExt/en.json
* https://github.com/abpframework/abp/tree/master/modules/account/src/Volo.Abp.Account.Web/Localization/Resources/AbpAccount/Web/en.json
* https://github.com/abpframework/abp/blob/master/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json
* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Application.Contracts/Volo/Blogging/Localization/Resources/Blogging/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Web/Localization/Resources/Blogging/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/en.json
* https://github.com/abpframework/abp/tree/master/modules/docs/app/VoloDocs.Web/Localization/Resources/VoloDocs/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Admin.Web/Localization/Resources/Docs/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/Localization/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Localization/Resources/FeatureManagement/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/Localization/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json
* https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Localization/Resources/AbpPermissionManagement/en.json
* https://github.com/abpframework/abp/tree/master/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Localization/Resources/AbpSettingManagement/en.json
* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Application.Contracts/Volo/Abp/TenantManagement/Localization/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Localization/Resources/AbpTenantManagement/Web/en.json
* https://github.com/abpframework/abp/tree/master/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json
* https://github.com/abpframework/abp/tree/master/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/en.json
* https://github.com/abpframework/abp/tree/master/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json
* https://github.com/abpframework/abp/tree/master/samples/BookStore/src/Acme.BookStore.Domain.Shared/Localization/BookStore/en.json
* https://github.com/abpframework/abp/tree/master/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/en.json
* https://github.com/abpframework/abp/tree/master/samples/DashboardDemo/src/DashboardDemo.Domain.Shared/Localization/DashboardDemo/en.json
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Application.Contracts/ProductManagement/Localization/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Domain/ProductManagement/Localization/Domain/en.json
* https://github.com/abpframework/abp/tree/master/samples/MicroserviceDemo/modules/product/src/ProductManagement.Web/Localization/Resources/ProductManagement/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Application.Contracts/Localization/MyProjectName/ApplicationContracts/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/DomainShared/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc-module/src/MyCompanyName.MyProjectName.Web/Localization/MyProjectName/Web/en.json
* https://github.com/abpframework/abp/tree/master/templates/mvc/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/en.json
* https://github.com/abpframework/abp/tree/master/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/en.json

12
docs/en/Data-Access.md

@ -1,11 +1,15 @@
# Data Access
ABP framework was designed as database agnostic, it can work any type of data source by the help of the [repository](Repositories.md) and [unit of work](Unit-Of-Work.md) abstractions.
## Database Providers
However, currently the following providers are implements:
ABP framework was designed as database agnostic. It can work any type of data source by the help of the [repository](Repositories.md) and [unit of work](Unit-Of-Work.md) abstractions. However, currently the following providers are implemented:
* [Entity Framework Core](Entity-Framework-Core.md) (works with [various DBMS and providers](https://docs.microsoft.com/en-us/ef/core/providers/?tabs=dotnet-core-cli).)
* [Entity Framework Core](Entity-Framework-Core.md) (works with [various DBMS and providers](https://docs.microsoft.com/en-us/ef/core/providers/).)
* [MongoDB](MongoDB.md)
* [Dapper](Dapper.md)
More providers might be added in the next releases.
More providers will be added in the future.
## See Also
* [Connection Strings](Connection-Strings.md)

18
docs/en/Dependency-Injection.md

@ -166,6 +166,24 @@ public class BlogModule : AbpModule
}
````
### Replace a Service
If you need to replace an existing service (defined by the ABP framework or another module dependency), you have two options;
1. Use the `Dependency` attribute of the ABP framework as explained above.
2. Use the `IServiceCollection.Replace` method of the Microsoft Dependency Injection library. Example:
````csharp
public class MyModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//Replacing the IConnectionStringResolver service
context.Services.Replace(ServiceDescriptor.Transient<IConnectionStringResolver, MyConnectionStringResolver>());
}
}
````
## Injecting Dependencies
There are three common ways of using a service that has already been registered.

173
docs/en/Entities.md

@ -1,34 +1,87 @@
## Entities
# Entities
Entities are one of the core concepts of DDD (Domain Driven Design). Eric Evans describe it as "*An object that is not fundamentally defined by its attributes, but rather by a thread of continuity and identity*".
An entity is generally mapped to a table in a relational database.
### Entity Class
## Entity Class
Entities are derived from `Entity<TKey>` class as shown below:
Entities are derived from the `Entity<TKey>` class as shown below:
```C#
public class Person : Entity<int>
public class Book : Entity<Guid>
{
public string Name { get; set; }
public DateTime CreationTime { get; set; }
public float Price { get; set; }
}
```
> If you do not want to derive your entity from the base `Entity<TKey>` class, you can directly implement `IEntity<TKey>` interface.
`Entity<TKey>` class just defines an `Id` property with the given primary **key type**, which is `Guid` in the example above. It can be other types like `string`, `int`, `long` or whatever you need.
### Entities with GUID Keys
If your entity's Id type is `Guid`, there are some good practices to implement:
* Create a constructor that gets the Id as a parameter and passes to the base class.
* If you don't set a GUID Id, ABP Framework sets it on save, but it is good to have a valid Id on the entity even before saving it to the database.
* If you create an entity with a constructor that takes parameters, also create a `protected` empty constructor. This is used while your database provider reads your entity from the database (on deserialization).
* Don't use the `Guid.NewGuid()` to set the Id! Use [the `IGuidGenerator` service](Guid-Generation.md) while passing the Id from the code that creates the entity. `IGuidGenerator` optimized to generate sequential GUIDs, which is critical for clustered indexes in the relational databases.
An example entity:
public Person()
````csharp
public class Book : Entity<Guid>
{
public string Name { get; set; }
public float Price { get; set; }
protected Book()
{
CreationTime = DateTime.Now;
}
public Book(Guid id)
: base(id)
{
}
}
```
````
> If you do not want to derive your entity from the base `Entity<TKey>` class, you can directly implement `IEntity<TKey>` interface.
Example usage in an [application service](Application-Services.md):
`Entity<TKey>` class just defines an `Id` property with the given primary **key type**, which is `int` in the sample above. It can be other types like `string`, `Guid`, `long` or whatever you need.
````csharp
public class BookAppService : ApplicationService, IBookAppService
{
private readonly IRepository<Book> _bookRepository;
Entity class also overrides the **equality** operator (==) to easily check if two entities are equal (they are equals if they are same entity type and their Ids are equals).
public BookAppService(IRepository<Book> bookRepository)
{
_bookRepository = bookRepository;
}
#### Entities with Composite Keys
public async Task CreateAsync(CreateBookDto input)
{
await _bookRepository.InsertAsync(
new Book(GuidGenerator.Create())
{
Name = input.Name,
Price = input.Price
}
);
}
}
````
* `BookAppService` injects the default [repository](Repositories.md) for the book entity and uses its `InsertAsync` method to insert a `Book` to the database.
* `GuidGenerator` is type of `IGuidGenerator` which is a property defined in the `ApplicationService` base class. ABP defines such frequently used base properties as pre-injected for you, so you don't need to manually [inject](Dependency-Injection.md) them.
* If you want to follow the DDD best practices, see the *Aggregate Example* section below.
### Entities with Composite Keys
Some entities may need to have **composite keys**. In that case, you can derive your entity from the non-generic `Entity` class. Example:
@ -53,31 +106,31 @@ public class UserRole : Entity
}
````
For the example above, the composite key is composed of `UserId` and `RoleId`. For a relational database, it is the composite primary key of the related table.
Entities with composite keys should implement the `GetKeys()` method as shown above.
For the example above, the composite key is composed of `UserId` and `RoleId`. For a relational database, it is the composite primary key of the related table. Entities with composite keys should implement the `GetKeys()` method as shown above.
Notice that you also need to define keys of the entity in your **object-relational mapping** (ORM) configuration.
> Notice that you also need to define keys of the entity in your **object-relational mapping** (ORM) configuration. See the [Entity Framework Core](Entity-Framework-Core.md) integration document for example.
> Also note that Entities with Composite Primary Keys cannot utilize the `IRepository<TEntity, TKey>` interface since it requires a single unique Id property. However, you can always use `IRepository<TEntity>`. See [repositories documentation](Repositories.md) for more.
> Also note that Entities with Composite Primary Keys cannot utilize the `IRepository<TEntity, TKey>` interface since it requires a single Id property. However, you can always use `IRepository<TEntity>`. See [repositories documentation](Repositories.md) for more.
### AggregateRoot Class
## AggregateRoot Class
"*Aggregate is a pattern in Domain-Driven Design. A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An example may be an order and its line-items, these will be separate objects, but it's useful to treat the order (together with its line items) as a single aggregate.*" (see the [full description](http://martinfowler.com/bliki/DDD_Aggregate.html))
`AggregateRoot` class extends the `Entity` class. So, it also has an `Id` property by default.
`AggregateRoot<TKey>` class extends the `Entity<TKey>` class. So, it also has an `Id` property by default.
> Notice that ABP creates default repositories only for aggregate roots by default. However, it's possible to include all entities. See [repositories documentation](Repositories.md) for more.
> Notice that ABP creates default repositories only for aggregate roots by default. However, it's possible to include all entities. See the [repositories documentation](Repositories.md) for more.
ABP does not force you to use aggregate roots, you can in fact use the `Entity` class as defined before. However, if you want to implement DDD and want to create aggregate root classes, there are some best practices you may want to consider:
ABP does not force you to use aggregate roots, you can in fact use the `Entity` class as defined before. However, if you want to implement the [Domain Driven Design](Domain-Driven-Design.md) and want to create aggregate root classes, there are some best practices you may want to consider:
* An aggregate root is responsible to preserve it's own integrity. This is also true for all entities, but aggregate root has responsibility for it's sub entities too. So, the aggregate root must always be in a valid state.
* An aggregate root can be referenced by it's Id. Do not reference it by it's navigation property.
* An aggregate root is treated as a single unit. It's retrieved and updated as a single unit. It's generally considered as a transaction boundary.
* Work with sub-entities over the aggregate root- do not modify them independently.
#### Aggregate Example
See the [entity design best practice guide](Best-Practices/Entities.md) if you want to implement DDD in your application.
### Aggregate Example
This is a full sample of an aggregate root with a related sub-entity collection:
@ -156,6 +209,11 @@ public class OrderLine : Entity
{
Count = newCount;
}
public override object[] GetKeys()
{
return new Object[] {OrderId, ProductId};
}
}
````
@ -163,15 +221,80 @@ public class OrderLine : Entity
`Order` is an **aggregate root** with `Guid` type `Id` property. It has a collection of `OrderLine` entities. `OrderLine` is another entity with a composite primary key (`OrderId` and ` ProductId`).
While this example may not implement all the best practices of an aggregate root, it still follows good practices:
While this example may not implement all the best practices of an aggregate root, it still follows some good practices:
* `Order` has a public constructor that takes **minimal requirements** to construct an `Order` instance. So, it's not possible to create an order without an id and reference number. The **protected/private** constructor is only necessary to **deserialize** the object while reading from a data source.
* `OrderLine` constructor is internal, so it is only allowed to be created by the domain layer. It's used inside of the `Order.AddProduct` method.
* `Order.AddProduct` implements the business rule to add a product to an order.
* All properties have `protected` setters. This is to prevent the entity from arbitrary changes from outside of the entity. For exmple, it would be dangerous to set `TotalItemCount` without adding a new product to the order. It's value is maintained by the `AddProduct` method.
ABP does not force you to apply any DDD rule or patterns. However, it tries to make it possible and easier when you do want to apply them. The documentation also follows the same principle.
ABP Framework does not force you to apply any DDD rule or patterns. However, it tries to make it possible and easier when you do want to apply them. The documentation also follows the same principle.
#### Aggregate Roots with Composite Keys
### Aggregate Roots with Composite Keys
While it's not common (and not suggested) for aggregate roots, it is in fact possible to define composite keys in the same way as defined for the mentioned entities above. Use non-generic `AggregateRoot` base class in that case.
## Base Classes & Interfaces for Audit Properties
There are some properties like `CreationTime`, `CreatorId`, `LastModificationTime`... which are very common in all applications. ABP Framework provides some interfaces and base classes to **standardize** these properties and also **sets their values automatically**.
### Auditing Interfaces
There are a lot of auditing interfaces, so you can implement the one that you need.
> While you can manually implement these interfaces, you can use **the base classes** defined in the next section to simplify it.
* `IHasCreationTime` defines the following properties:
* `CreationTime`
* `IMayHaveCreator` defines the following properties:
* `CreatorId`
* `ICreationAuditedObject` inherits from the `IHasCreationTime` and the `IMayHaveCreator`, so it defines the following properties:
* `CreationTime`
* `CreatorId`
* `IHasModificationTime` defines the following properties:
* `LastModificationTime`
* `IModificationAuditedObject` extends the `IHasModificationTime` and adds the `LastModifierId` property. So, it defines the following properties:
* `LastModificationTime`
* `LastModifierId`
* `IAuditedObject` extends the `ICreationAuditedObject` and the `IModificationAuditedObject`, so it defines the following properties:
* `CreationTime`
* `CreatorId`
* `LastModificationTime`
* `LastModifierId`
* `ISoftDelete` (see the [data filtering document](Data-Filtering.md)) defines the following properties:
* `IsDeleted`
* `IHasDeletionTime` extends the `ISoftDelete` and adds the `DeletionTime` property. So, it defines the following properties:
* `IsDeleted`
* `DeletionTime`
* `IDeletionAuditedObject` extends the `IHasDeletionTime` and adds the `DeleterId` property. So, it defines the following properties:
* `IsDeleted`
* `DeletionTime`
* `DeleterId`
* `IFullAuditedObject` inherits from the `IAuditedObject` and the `IDeletionAuditedObject`, so it defines the following properties:
* `CreationTime`
* `CreatorId`
* `LastModificationTime`
* `LastModifierId`
* `IsDeleted`
* `DeletionTime`
* `DeleterId`
Once you implement any of the interfaces, or derive from a class defined in the next section, ABP Framework automatically manages these properties wherever possible.
> Implementing `ISoftDelete`, `IDeletionAuditedObject` or `IFullAuditedObject` makes your entity **soft-delete**. See the [data filtering document](Data-Filtering.md) to learn about the soft-delete pattern.
### Auditing Base Classes
While you can manually implement any of the interfaces defined above, it is suggested to inherit from the base classes defined here:
* `CreationAuditedEntity<TKey>` and `CreationAuditedAggregateRoot<TKey>` implement the `ICreationAuditedObject` interface.
* `AuditedEntity<TKey>` and `AuditedAggregateRoot<TKey>` implement the `IAuditedObject` interface.
* `FullAuditedEntity<TKey>` and `FullAuditedAggregateRoot<TKey>` implement the `IFullAuditedObject` interface.
All these base classes also have non-generic versions to take `AuditedEntity` and `FullAuditedAggregateRoot` to support the composite primary keys.
All these base classes also have `...WithUser` pairs, like `FullAuditedAggregateRootWithUser<TUser>` and`FullAuditedAggregateRootWithUser<TKey, TUser>`. This makes possible to add a navigation property to your user entity. However, it is not a good practice to add navigation properties between aggregate roots, so this usage is not suggested (unless you are using an ORM, like EF Core, that well supports this scenario and you really need it - otherwise remember that this approach doesn't work for NoSQL databases like MongoDB where you must truly implement the aggregate pattern).
## See Also
* [Best practice guide to design the entities](Best-Practices/Entities.md)

58
docs/en/Entity-Framework-Core-MySQL.md

@ -0,0 +1,58 @@
# Switch to EF Core MySQL Provider
This document explains how to switch to the **MySQL** database provider for **[the application startup template](Startup-Templates/Application.md)** which comes with SQL Server provider pre-configured.
## Replace the Volo.Abp.EntityFrameworkCore.SqlServer Package
`.EntityFrameworkCore` project in the solution depends on the [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet package. Remove this package and add the same version of the [Volo.Abp.EntityFrameworkCore.MySQL](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.MySQL) package.
## Replace the Module Dependency
Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFrameworkCore` project, remove `typeof(AbpEntityFrameworkCoreSqlServerModule)` from the `DependsOn` attribute, add `typeof(AbpEntityFrameworkCoreMySQLModule)` (also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Abp.EntityFrameworkCore.MySQL;`).
## UseMySQL()
Find `UseSqlServer()` calls in your solution, replace with `UseMySQL()`. Check the following files:
* *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project.
* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project.
> Depending on your solution structure, you may find more code files need to be changed.
## Change the Connection Strings
MySQL connection strings are different than SQL Server connection strings. So, check all `appsettings.json` files in your solution and replace the connection strings inside them. See the [connectionstrings.com]( https://www.connectionstrings.com/mysql/ ) for details of MySQL connection string options.
You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure.
## Change the Migrations DbContext
MySQL DBMS has some slight differences than the SQL Server. Some module database mapping configuration (especially the field lengths) causes problems with MySQL. For example, some of the the [IdentityServer module](Modules/IdentityServer.md) tables has such problems and it provides an option to configure the fields based on your DBMS.
The startup template contains a *YourProjectName*MigrationsDbContext which is responsible to maintain and migrate the database schema. This DbContext basically calls extension methods of the depended modules to configure their database tables.
Open the *YourProjectName*MigrationsDbContext and change the `builder.ConfigureIdentityServer();` line as shown below:
````csharp
builder.ConfigureIdentityServer(options =>
{
options.DatabaseProvider = EfCoreDatabaseProvider.MySql;
});
````
Then `ConfigureIdentityServer()` method will set the field lengths to not exceed the MySQL limits. Refer to related module documentation if you have any problem while creating or executing the database migrations.
## Re-Generate the Migrations
The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core Migrations depend on the selected DBMS provider. So, changing the DBMS provider will cause the migration fails.
* Delete the Migrations folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution.
* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console).
This will create a database migration with all database objects (tables) configured.
Run the `.DbMigrator` project to create the database and seed the initial data.
## Run the Application
It is ready. Just run the application and enjoy coding.

90
docs/en/Entity-Framework-Core-Other-DBMS.md

@ -0,0 +1,90 @@
# Switch to another DBMS for Entity Framework Core
**[The application startup template](Startup-Templates/Application.md)** comes with SQL Server provider pre-configured for the Entity Framework Core. Entity Framework Core supports [many other DBMSs](https://docs.microsoft.com/en-us/ef/core/providers/) and you can use any of them with your ABP based applications.
ABP framework provides integration packages for some common DBMSs to make the configuration a bit easier (see the [entity framework core document](Entity-Framework-Core.md) for a list of available integration packages). However, you can configure your DBMS provider without these integration packages.
While using the integration package is always recommended (it also makes standard for the depended version across different modules), you can do it manually if there is no integration package for your DBMS provider.
This document explains how to switch to MySQL without using [the MySQL integration package](Entity-Framework-Core-MySQL.md).
## Replace the SQL Server Dependency
* Remove the [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet package dependency from the `.EntityFrameworkCore` project.
* Add the [Pomelo.EntityFrameworkCore.MySql](https://www.nuget.org/packages/Pomelo.EntityFrameworkCore.MySql/) NuGet package dependency to your `.EntityFrameworkCore` project.
## Remove the Module Dependency
Remove the `AbpEntityFrameworkCoreSqlServerModule` from the dependency list of your ***YourProjectName*EntityFrameworkCoreModule** class.
## Change the UseSqlServer() Calls
Find the following code part inside the *YourProjectName*EntityFrameworkCoreModule class:
````csharp
Configure<AbpDbContextOptions>(options =>
{
options.UseSqlServer();
});
````
Replace it with the following code part:
````csharp
Configure<AbpDbContextOptions>(options =>
{
options.Configure(ctx =>
{
if (ctx.ExistingConnection != null)
{
ctx.DbContextOptions.UseMySql(ctx.ExistingConnection);
}
else
{
ctx.DbContextOptions.UseMySql(ctx.ConnectionString);
}
});
});
````
* `UseMySql` calls in this code is defined by the Pomelo.EntityFrameworkCore.MySql package and you can use its additional options if you need.
* This code first checks if there is an existing (active) connection to the same database in the current request and reuses it if possible. This allows to share a single transaction among different DbContext types. ABP handles the rest of the things.
* It uses `ctx.ConnectionString` and passes to the `UseMySql` if there is no active connection (which will cause to create a new database connection). Using the `ctx.ConnectionString` is important here. Don't pass a static connection string (or a connection string from a configuration). Because ABP [dynamically determines the correct connection string](Connection-Strings.md) in a multi-database or [multi-tenant](Multi-Tenancy.md) environment.
## Change the Connection Strings
MySQL connection strings are different than SQL Server connection strings. So, check all `appsettings.json` files in your solution and replace the connection strings inside them. See the [connectionstrings.com]( https://www.connectionstrings.com/mysql/ ) for details of MySQL connection string options.
You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure.
## Change the Migrations DbContext
MySQL DBMS has some slight differences than the SQL Server. Some module database mapping configuration (especially the field lengths) causes problems with MySQL. For example, some of the the [IdentityServer module](Modules/IdentityServer.md) tables has such problems and it provides an option to configure the fields based on your DBMS.
The startup template contains a *YourProjectName*MigrationsDbContext which is responsible to maintain and migrate the database schema. This DbContext basically calls extension methods of the depended modules to configure their database tables.
Open the *YourProjectName*MigrationsDbContext and change the `builder.ConfigureIdentityServer();` line as shown below:
````csharp
builder.ConfigureIdentityServer(options =>
{
options.DatabaseProvider = EfCoreDatabaseProvider.MySql;
});
````
Then `ConfigureIdentityServer()` method will set the field lengths to not exceed the MySQL limits. Refer to related module documentation if you have any problem while creating or executing the database migrations.
## Re-Generate the Migrations
The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core Migrations depend on the selected DBMS provider. So, changing the DBMS provider will cause the migration fails.
* Delete the Migrations folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution.
* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console).
This will create a database migration with all database objects (tables) configured.
Run the `.DbMigrator` project to create the database and seed the initial data.
## Run the Application
It is ready. Just run the application and enjoy coding.

41
docs/en/Entity-Framework-Core-PostgreSQL.md

@ -0,0 +1,41 @@
# Switch to EF Core PostgreSQL Provider
This document explains how to switch to the **PostgreSQL** database provider for **[the application startup template](Startup-Templates/Application.md)** which comes with SQL Server provider pre-configured.
## Replace the Volo.Abp.EntityFrameworkCore.SqlServer Package
`.EntityFrameworkCore` project in the solution depends on the [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet package. Remove this package and add the same version of the [Volo.Abp.EntityFrameworkCore.PostgreSql](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.PostgreSql) package.
## Replace the Module Dependency
Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFrameworkCore` project, remove `typeof(AbpEntityFrameworkCoreSqlServerModule)` from the `DependsOn` attribute, add `typeof(AbpEntityFrameworkCorePostgreSqlModule)` (also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Abp.EntityFrameworkCore.PostgreSql;`).
## UsePostgreSql()
Find `UseSqlServer()` call in *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project and replace with `UsePostgreSql()`.
Find `UseSqlServer()` call in *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project and replace with `UseNpgsql()`.
> Depending on your solution structure, you may find more `UseSqlServer()` calls that needs to be changed.
## Change the Connection Strings
PostgreSql connection strings are different than SQL Server connection strings. So, check all `appsettings.json` files in your solution and replace the connection strings inside them. See the [connectionstrings.com]( https://www.connectionstrings.com/postgresql/ ) for details of PostgreSql connection string options.
You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure.
## Re-Generate the Migrations
The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core Migrations depend on the selected DBMS provider. So, changing the DBMS provider will cause the migration fails.
* Delete the Migrations folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution.
* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console).
This will create a database migration with all database objects (tables) configured.
Run the `.DbMigrator` project to create the database and seed the initial data.
## Run the Application
It is ready. Just run the application and enjoy coding.

41
docs/en/Entity-Framework-Core-SQLite.md

@ -0,0 +1,41 @@
# Switch to EF Core SQLite Provider
This document explains how to switch to the **SQLite** database provider for **[the application startup template](Startup-Templates/Application.md)** which comes with SQL Server provider pre-configured.
## Replace the Volo.Abp.EntityFrameworkCore.SqlServer Package
`.EntityFrameworkCore` project in the solution depends on the [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet package. Remove this package and add the same version of the [Volo.Abp.EntityFrameworkCore.Sqlite](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.Sqlite) package.
## Replace the Module Dependency
Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFrameworkCore` project, remove `typeof(AbpEntityFrameworkCoreSqlServerModule)` from the `DependsOn` attribute, add `typeof(AbpEntityFrameworkCoreSqliteModule)` (also replace `using Volo.Abp.EntityFrameworkCore.SqlServer;` with `using Volo.Abp.EntityFrameworkCore.Sqlite;`).
## UseSqlite()
Find `UseSqlServer()` calls in your solution, replace with `UseSqlite()`. Check the following files:
* *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project.
* *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project.
> Depending on your solution structure, you may find more code files need to be changed.
## Change the Connection Strings
SQLite connection strings are different than SQL Server connection strings. So, check all `appsettings.json` files in your solution and replace the connection strings inside them. See the [connectionstrings.com]( https://www.connectionstrings.com/sqlite/ ) for details of SQLite connection string options.
You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure.
## Re-Generate the Migrations
The startup template uses [Entity Framework Core's Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/). EF Core Migrations depend on the selected DBMS provider. So, changing the DBMS provider will cause the migration fails.
* Delete the Migrations folder under the `.EntityFrameworkCore.DbMigrations` project and re-build the solution.
* Run `Add-Migration "Initial"` on the Package Manager Console (select the `.DbMigrator` (or `.Web`) project as the startup project in the Solution Explorer and select the `.EntityFrameworkCore.DbMigrations` project as the default project in the Package Manager Console).
This will create a database migration with all database objects (tables) configured.
Run the `.DbMigrator` project to create the database and seed the initial data.
## Run the Application
It is ready. Just run the application and enjoy coding.

46
docs/en/Entity-Framework-Core.md

@ -28,6 +28,19 @@ namespace MyCompany.MyProject
> Note: Instead, you can directly download a [startup template](https://abp.io/Templates) with EF Core pre-installed.
### Database Management System Selection
Entity Framework Core supports various database management systems ([see all](https://docs.microsoft.com/en-us/ef/core/providers/)). ABP framework and this document doesn't depend on any specific DBMS.
If you are creating a reusable library, avoid to depend on a specific DBMS package. However, in a final application you eventually will select a DBMS.
ABP framework provides integration packages for some common DBMSs to make the configuration a bit easier. [The startup templates](Startup-Templates/Index.md) come with **SQL Server (localdb) pre-configured**. See the following documents to learn how to configure for the other DBMS providers:
* [MySQL](Entity-Framework-Core-MySQL.md)
* [PostgreSQL](Entity-Framework-Core-PostgreSQL.md)
* [SQLite](Entity-Framework-Core-SQLite.md)
* [Others](Entity-Framework-Core-Other-DBMS.md)
## Creating DbContext
You can create your DbContext as you normally do. It should be derived from `AbpDbContext<T>` as shown below:
@ -62,7 +75,7 @@ public class MyDbContext : AbpDbContext<MyDbContext>
}
```
If you don't configure, the `Default` connection string is used. If you configure a specific connection string name, but not define this connection string name in the application configuration then it fallbacks to the `Default` connection string.
If you don't configure, the `Default` connection string is used. If you configure a specific connection string name, but not define this connection string name in the application configuration then it fallbacks to the `Default` connection string (see [the connection strings document](Connection-Strings.md) for more information).
## Registering DbContext To Dependency Injection
@ -126,7 +139,8 @@ public class BookManager : DomainService
{
private readonly IRepository<Book, Guid> _bookRepository;
public BookManager(IRepository<Book, Guid> bookRepository) //inject default repository
//inject default repository to the constructor
public BookManager(IRepository<Book, Guid> bookRepository)
{
_bookRepository = bookRepository;
}
@ -142,7 +156,8 @@ public class BookManager : DomainService
Type = type
};
await _bookRepository.InsertAsync(book); //Use a standard repository method
//Use a standard repository method
await _bookRepository.InsertAsync(book);
return book;
}
@ -153,9 +168,9 @@ This sample uses `InsertAsync` method to insert a new entity to the database.
### Add Custom Repositories
Default generic repositories are powerful enough in most cases (since they implement `IQueryable`). However, you may need to create a custom repository to add your own repository methods.
Default generic repositories are powerful enough in most cases (since they implement `IQueryable`). However, you may need to create a custom repository to add your own repository methods. Assume that you want to delete all books by type.
Assume that you want to delete all books by type. It's suggested to define an interface for your custom repository:
It's suggested to define an interface for your custom repository:
````csharp
public interface IBookRepository : IRepository<Book, Guid>
@ -187,21 +202,23 @@ public class BookRepository : EfCoreRepository<BookStoreDbContext, Book, Guid>,
Now, it's possible to [inject](Dependency-Injection.md) the `IBookRepository` and use the `DeleteBooksByType` method when needed.
#### Override Default Generic Repository
#### Override the Default Generic Repository
Even if you create a custom repository, you can still inject the default generic repository (`IRepository<Book, Guid>` for this example). Default repository implementation will not use the class you have created.
If you want to replace default repository implementation with your custom repository, do it inside `AddAbpDbContext` options:
If you want to replace default repository implementation with your custom repository, do it inside the `AddAbpDbContext` options:
````csharp
context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
{
options.AddDefaultRepositories();
options.AddRepository<Book, BookRepository>(); //Replaces IRepository<Book, Guid>
//Replaces IRepository<Book, Guid>
options.AddRepository<Book, BookRepository>();
});
````
This is especially important when you want to **override a base repository method** to customize it. For instance, you may want to override `DeleteAsync` method to delete an entity in a more efficient way:
This is especially important when you want to **override a base repository method** to customize it. For instance, you may want to override `DeleteAsync` method to delete a specific entity in a more efficient way:
````csharp
public override async Task DeleteAsync(
@ -215,7 +232,7 @@ public override async Task DeleteAsync(
### Access to the EF Core API
In most cases, you want to hide EF Core APIs behind a repository (this is the main purpose of the repository). However, if you want to access the DbContext instance over the repository, you can use `GetDbContext()` or `GetDbSet()` extension methods. Example:
In most cases, you want to hide EF Core APIs behind a repository (this is the main purpose of the repository pattern). However, if you want to access the `DbContext` instance over the repository, you can use `GetDbContext()` or `GetDbSet()` extension methods. Example:
````csharp
public class BookService
@ -243,9 +260,9 @@ public class BookService
#### Set Default Repository Classes
Default generic repositories are implemented by `EfCoreRepository` class by default. You can create your own implementation and use it for default repository implementation.
Default generic repositories are implemented by `EfCoreRepository` class by default. You can create your own implementation and use it for all the default repository implementations.
First, define your repository classes like that:
First, define your default repository classes like that:
```csharp
public class MyRepositoryBase<TEntity>
@ -271,7 +288,7 @@ public class MyRepositoryBase<TEntity, TKey>
First one is for [entities with composite keys](Entities.md), second one is for entities with single primary key.
It's suggested to inherit from the `EfCoreRepository` class and override methods if needed. Otherwise, you will have to implement all standard repository methods manually.
It's suggested to inherit from the `EfCoreRepository` class and override methods if needed. Otherwise, you will have to implement all the standard repository methods manually.
Now, you can use `SetDefaultRepositoryClasses` option:
@ -282,6 +299,7 @@ context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
typeof(MyRepositoryBase<,>),
typeof(MyRepositoryBase<>)
);
//...
});
```
@ -316,7 +334,7 @@ public class BookRepository : EfCoreRepository<IBookStoreDbContext, Book, Guid>,
}
````
One advantage of using interface for a DbContext is then it becomes replaceable by another implementation.
One advantage of using an interface for a DbContext is then it will be replaceable by another implementation.
#### Replace Other DbContextes

58
docs/en/FluentValidation.md

@ -0,0 +1,58 @@
# FluentValidation Integration
ABP [Validation](Validation.md) infrastructure is extensible. [Volo.Abp.FluentValidation](https://www.nuget.org/packages/Volo.Abp.FluentValidation) NuGet package extends the validation system to work with the [FluentValidation](https://fluentvalidation.net/) library.
## Installation
It is suggested to use the [ABP CLI](CLI.md) to install this package.
### Using the ABP CLI
Open a command line window in the folder of the project (.csproj file) and type the following command:
````bash
abp add-package Volo.Abp.FluentValidation
````
### Manual Installation
If you want to manually install;
1. Add the [Volo.Abp.FluentValidation](https://www.nuget.org/packages/Volo.Abp.FluentValidation) NuGet package to your project:
````
Install-Package Volo.Abp.FluentValidation
````
2. Add the `AbpFluentValidationModule` to the dependency list of your module:
````csharp
[DependsOn(
//...other dependencies
typeof(AbpFluentValidationModule) //Add the FluentValidation module
)]
public class YourModule : AbpModule
{
}
````
## Using the FluentValidation
Follow [the FluentValidation documentation](https://fluentvalidation.net/) to create validator classes. Example:
````csharp
public class CreateUpdateBookDtoValidator : AbstractValidator<CreateUpdateBookDto>
{
public CreateUpdateBookDtoValidator()
{
RuleFor(x => x.Name).Length(3, 10);
RuleFor(x => x.Price).ExclusiveBetween(0.0f, 999.0f);
}
}
````
ABP will automatically find this class and associate with the `CreateUpdateBookDto` on object validation.
## See Also
* [Validation System](Validation.md)

5
docs/en/Logging.md

@ -0,0 +1,5 @@
# Logging
ABP Framework doesn't implement any logging infrastructure. It uses the [ASP.NET Core's logging system](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging).
> .NET Core's logging system is actually independent from the ASP.NET Core. It is usable in any type of application.

7
docs/en/Modules/Audit-Logging.md

@ -0,0 +1,7 @@
# Audit Logging Module
The Audit Logging Module basically implements the `IAuditingStore` to save the audit log objects to a database.
> Audit Logging module is already installed and configured for [the startup templates](../Startup-Templates/Index.md). So, most of the times you don't need to manually add this module to your application.
See [the audit logging system](../Audit-Logging.md) document for more about the audit logging.

3
docs/en/Modules/Blogging.md

@ -0,0 +1,3 @@
# IdentityServer Module
TODO

111
docs/en/Modules/Docs.md

@ -16,7 +16,7 @@ Docs module is an application module and does not offer any hosting solution. Yo
When you use GitHub to store your docs, Docs Module supports versioning. If you have multiple versions for your docs, there will be a combo-box on the UI to switch between versions. If you choose file system to store your docs, it does not support multiple versions.
[The documents](https://abp.io/documents/) for ABP framework is also using this module.
[The documents](docs.abp.io) for ABP framework is also using this module.
> Docs module follows the [module architecture best practices](../Best-Practices/Module-Architecture.md) guide.
@ -316,7 +316,7 @@ You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documen
- ExtraProperties:
```json
{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs/en/","GitHubAccessToken":"***"}
{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs","GitHubAccessToken":"***"}
```
Note that `GitHubAccessToken` is masked with `***`. It's a private token that you must get it from GitHub. See https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
@ -328,7 +328,7 @@ You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documen
For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939658', N'ABP framework (GitHub)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'GitHub', N'{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs/en/","GitHubAccessToken":"***"}', N'/', N'master')
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939658', N'ABP framework (GitHub)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'GitHub', N'{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs","GitHubAccessToken":"***"}', N'/', N'master')
```
Be aware that `GitHubAccessToken` is masked. It's a private token and you must get your own token and replace the `***` string.
@ -354,10 +354,10 @@ You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documen
- ExtraProperties:
```json
{"Path":"C:\\Github\\abp\\docs\\en"}
{"Path":"C:\\Github\\abp\\docs"}
```
Note that `Path` must be replaced with your local docs directory. You can fetch the ABP Framework's documents from https://github.com/abpframework/abp/tree/master/docs/en and copy to the directory `C:\\Github\\abp\\docs\\en` to get it work.
Note that `Path` must be replaced with your local docs directory. You can fetch the ABP Framework's documents from https://github.com/abpframework/abp/tree/master/docs and copy to the directory `C:\\Github\\abp\\docs` to get it work.
- MainWebsiteUrl: `/`
@ -366,11 +366,9 @@ You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documen
For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP framework (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs\\en"}', N'/', NULL)
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP framework (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL)
```
Add one of the sample projects above and run the application. In the menu you will see `Documents` link, click the menu link to open the documents page.
So far, we have created a new application from abp.io website and made it up and ready for Docs module.
@ -408,12 +406,105 @@ public class Person
```
~~~
As an example you can see ABP Framework documentation:
[https://github.com/abpframework/abp/blob/master/docs/en/](https://github.com/abpframework/abp/blob/master/docs/en/)
#### Conditional sections feature (Using Scriban)
Docs module uses [Scriban](<https://github.com/lunet-io/scriban/tree/master/doc> ) for conditionally show or hide some parts of a document. In order to use that feature, you have to create a JSON file as **Parameter document** per every language. It will contain all the key-values, as well as their display names.
For example, [en/docs-params.json](https://github.com/abpio/abp-commercial-docs/blob/master/en/docs-params.json):
```json
{
"parameters": [{
"name": "UI",
"displayName": "UI",
"values": {
"MVC": "MVC / Razor Pages",
"NG": "Angular"
}
},
{
"name": "DB",
"displayName": "Database",
"values": {
"EF": "Entity Framework Core",
"Mongo": "MongoDB"
}
},
{
"name": "Tiered",
"displayName": "Tiered",
"values": {
"No": "Not Tiered",
"Yes": "Tiered"
}
}]
}
```
Since not every single document in your projects may not have sections or may not need all of those parameters, you have to declare which of those parameters will be used for sectioning the document, as a JSON block anywhere on the document.
For example [Getting-Started.md](https://github.com/abpio/abp-commercial-docs/blob/master/en/getting-started.md):
```
.....
​````json
//[doc-params]
{
"UI": ["MVC","NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
​````
........
```
This section will be automatically deleted during render. And f course, those key values must match with the ones in **Parameter document**.
![Interface](../images/docs-section-ui.png)
Now you can use **Scriban** syntax to create sections in your document.
For example:
````
{{ if UI == "NG" }}
* `-u` argument specifies the UI framework, `angular` in this case.
{{ end }}
{{ if DB == "Mongo" }}
* `-d` argument specifies the database provider, `mongodb` in this case.
{{ end }}
{{ if Tiered == "Yes" }}
* `--tiered` argument is used to create N-tiered solution where authentication server, UI and API layers are physically separated.
{{ end }}
````
You can also use variables in a text, adding **_Value** postfix to its key:
````
This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider.
````
Also, **Document_Language_Code** and **Document_Version** keys are pre-defined if you want to get the language code or the version of the current document (This may be useful for creating links that redirects to another documentation system in another domain).
------
**IMPORTANT NOTICE**: Scriban uses "{{" and "}}" for syntax. Therefore, you must use escape blocks if you are going to use those in your document (an Angular document, for example). See [Scriban docs](<https://github.com/lunet-io/scriban/blob/master/doc/language.md#13-escape-block> ) for more information.
### 8- Creating the Navigation Document
Navigation document is the main menu of the documents page. It is located on the left side of the page. It is a `JSON` file. Take a look at the below sample navigation document to understand the structure.

3
docs/en/Modules/IdentityServer.md

@ -0,0 +1,3 @@
# IdentityServer Module
TODO

22
docs/en/Modules/Index.md

@ -11,16 +11,20 @@ There are **two types of modules.** They don't have any structural difference bu
There are some **free and open source** application modules developed and maintained by the ABP community:
* **Account**: Used to make user login/register to the application.
* **Audit Logging**: Used to persist audit logs to a database.
* **Background Jobs**: Used to persist background jobs when using default background job manager.
* **Blogging**: Used to create fancy blogs. ABP's [own blog](https://abp.io/blog/abp/) already using this module.
* **Account**: Provides UI for the account management and allows user to login/register to the application.
* [**Audit Logging**](Audit-Logging.md): Persists audit logs to a database.
* **Background Jobs**: Persist background jobs when using the default background job manager.
* **Blogging**: Used to create fancy blogs. ABP's [own blog](https://blog.abp.io/) already using this module.
* [**Docs**](Docs.md): Used to create technical documentation pages. ABP's [own documentation](https://docs.abp.io) already using this module.
* **Identity**: Used to manage roles, users and their permissions.
* **Identity Server**: Integrates to IdentityServer4.
* **Identity**: Manages roles, users and their permissions, based on the Microsoft Identity library.
* **IdentityServer**: Integrates to IdentityServer4.
* **Permission Management**: Used to persist permissions.
* **[Setting Management](Setting-Management.md)**: Used to persist and manage the [settings](../Settings.md).
* **Tenant Management**: Used to manage tenants for a [multi-tenant](../Multi-Tenancy.md) application.
* **Users**: Used to abstract users, so other modules can depend on this instead of the Identity module.
* **Tenant Management**: Manages tenants for a [multi-tenant](../Multi-Tenancy.md) application.
* **Users**: Abstract users, so other modules can depend on this module instead of the Identity module.
Documenting the modules is in the progress. See [this repository](https://github.com/abpframework/abp/tree/master/modules) for source code of all modules.
See [the GitHub repository](https://github.com/abpframework/abp/tree/master/modules) for source code of all modules.
## Commercial Application Modules
[ABP Commercial](https://commercial.abp.io/) license provides additional pre-built application modules on top of the ABP framework. See the [module list](https://commercial.abp.io/modules) provided by the ABP Commercial.

4
docs/en/Modules/Setting-Management.md

@ -67,6 +67,8 @@ namespace Demo
So, you can get or set a setting value for different setting value providers (Default, Global, User, Tenant... etc).
> Use the `ISettingProvider` instead of the `ISettingManager` if you only need to read the setting values, because it implements caching and supports all deployment scenarios. You can use the `ISettingManager` if you are creating a setting management UI.
### Setting Cache
Setting values are cached using the [distributed cache](../Caching.md) system. Always use the `ISettingManager` to change the setting values which manages the cache for you.
@ -76,7 +78,7 @@ Setting values are cached using the [distributed cache](../Caching.md) system. A
Setting Management module is extensible, just like the [setting system](../Settings.md). You can extend it by defining setting management providers. There are 5 pre-built setting management providers registered by the order below:
* `DefaultValueSettingManagementProvider`: Gets the value from the default value of the setting definition. It can not set the default value since default values are hard-coded on the setting definition.
* `ConfigurationSettingManagementProvider`: Gets the value from the [IConfiguration service](Configuration.md). It can not set the configuration value because it is not possible to change the configuration values on runtime.
* `ConfigurationSettingManagementProvider`: Gets the value from the [IConfiguration service](../Configuration.md). It can not set the configuration value because it is not possible to change the configuration values on runtime.
* `GlobalSettingManagementProvider`: Gets or sets the global (system-wide) value for a setting.
* `TenantSettingManagementProvider`: Gets or sets the setting value for a tenant.
* `UserSettingManagementProvider`: Gets the setting value for a user.

116
docs/en/Options.md

@ -1,4 +1,118 @@
# Options
TODO!
Microsoft has introduced [the options pattern](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options) that is used to configure a group of settings used by the framework services. This pattern is implemented by the [Microsoft.Extensions.Options](https://www.nuget.org/packages/Microsoft.Extensions.Options) NuGet package, so it is usable by any type of applications in addition to ASP.NET Core based applications.
ABP framework follows this option pattern and defines options classes to configure the framework and the modules (they are explained in the documents of the related feature).
Since [the Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options) explains the pattern in detail, no reason to repeat all. However, ABP adds a few more features and they will be explained here.
## Configure Options
You typically configure options in the `ConfigureServices` of the `Startup` class. However, since ABP framework provides a modular infrastructure, you configure options in the `ConfigureServices` of your [module](Module-Development-Basics.md). Example:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Configure<AbpAuditingOptions>(options =>
{
options.IsEnabled = false;
});
}
````
* `AbpAuditingOptions` is a simple class defines some properties like `IsEnabled` used here.
* `AbpModule` base class defines `Configure` method to make the code simpler. So, instead of `context.Services.Configure<...>`, you can directly use the `Configure<...>` shortcut method.
If you are developing a reusable module, you may need to define an options class to allow developers to configure your module. In this case, define a plain options class as shown below:
````csharp
public class MyOptions
{
public int Value1 { get; set; }
public bool Value2 { get; set; }
}
````
Then developers can configure your options just like the `AbpAuditingOptions` example above:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<MyOptions>(options =>
{
options.Value1 = 42;
options.Value2 = true;
});
}
````
* In this example, used the shortcut `Configure<...>` method.
### Get the Option Value
Whenever you need to get the value of an option, [inject](Dependency-Injection.md) the `IOptions<TOption>` service into your class and use its `.Value` property. Example:
````csharp
public class MyService : ITransientDependency
{
private readonly MyOptions _options;
public MyService(IOptions<MyOptions> options)
{
_options = options.Value; //Notice the options.Value usage!
}
public void DoIt()
{
var v1 = _options.Value1;
var v2 = _options.Value2;
}
}
````
Read [the Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options) for all details of the options pattern.
## Pre Configure
One restriction of the options pattern is that you can only resolve (inject) the `IOptions<MyOptions>` and get the option values when the dependency injection configuration completes (that means the `ConfigureServices` methods of all modules complete).
If you are developing a module, you may need to allow developers to set some options and use these options in the dependency injection registration phase. You may need to configure other services or change the dependency injection registration code based on these option values.
For such cases, ABP introduces the `PreConfigure<TOptions>` and the `ExecutePreConfiguredActions<TOptions>` extension methods for the `IServiceCollection`. The pattern works as explained below.
1. Define a plan option class in your module. Example:
````csharp
public class MyPreOptions
{
public bool MyValue { get; set; }
}
````
Then any [module class](Module-Development-Basics.md) depends on your module can use the `PreConfigure<TOptions>` method in its `PreConfigureServices` method. Example:
````csharp
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<MyPreOptions>(options =>
{
options.MyValue = true;
});
}
````
> Multiple modules can pre-configure the options and override the option values based on their dependency order.
Finally, your module can execute the `ExecutePreConfiguredActions` method in its `ConfigureServices` method to get the configured option values. Example:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
var options = context.Services.ExecutePreConfiguredActions<MyPreOptions>();
if (options.MyValue)
{
//...
}
}
````

53
docs/en/Settings.md

@ -40,6 +40,33 @@ ABP automatically discovers this class and registers the setting definitions.
* **Providers**: Can be used to restrict providers available for a particular setting (see the setting value providers section for more).
* **Properties**: A name/value collection to set custom properties about this setting those can be used later in the application code.
### Change Setting Definitions of a Depended Module
In some cases, you may want to change some properties of a settings defined in some other module that your application/module depends on. A setting definition provider can query and update setting definitions.
The following example gets a setting defined by the [Volo.Abp.Emailing](Emailing.md) package and changes its properties:
````csharp
public class MySettingDefinitionProvider : SettingDefinitionProvider
{
public override void Define(ISettingDefinitionContext context)
{
var smtpHost = context.GetOrNull("Abp.Mailing.Smtp.Host");
if (smtpHost != null)
{
smtpHost.DefaultValue = "mail.mydomain.com";
smtpHost.DisplayName =
new LocalizableString(
typeof(MyLocalizationResource),
"SmtpServer_DisplayName"
);
}
}
}
````
> Using constants for the setting names is a good practice and ABP packages do it. `Abp.Mailing.Smtp.Host` setting name is a constant defined by the `EmailSettingNames` class (in the `Volo.Abp.Emailing` namespace).
## Reading Setting Values
### ISettingProvider
@ -118,6 +145,30 @@ There are 5 pre-built setting value providers registered by the order below:
Global, Tenant and User setting value providers use the `ISettingStore` to read the value from the data source (see the section below).
### Setting Values in the Application Configuration
As mentioned in the previous section, `ConfigurationSettingValueProvider` reads the settings from the `IConfiguration` service, which can read values from the `appsettings.json` by default. So, the easiest way to configure setting values to define them in the `appsettings.json` file.
For example, you can configure [IEmailSender](Emailing.md) settings as shown below:
````json
{
"Settings": {
"Abp.Mailing.DefaultFromAddress": "noreply@mydomain.com",
"Abp.Mailing.DefaultFromDisplayName": "My Application",
"Abp.Mailing.Smtp.Host": "mail.mydomain.com",
"Abp.Mailing.Smtp.Port": "547",
"Abp.Mailing.Smtp.UserName": "myusername",
"Abp.Mailing.Smtp.Password": "mySecretPassW00rd",
"Abp.Mailing.Smtp.EnableSsl": "True"
}
}
````
Setting values should be configured under the `Settings` section as like in this example.
> `IConfiguration` is an .NET Core service and it can read values not only from the `appsettings.json`, but also from the environment, user secrets... etc. See [Microsoft's documentation]( https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/ ) for more.
### Custom Setting Value Providers
If you need to extend the setting system, you can define a class derived from the `SettingValueProvider` class. Example:
@ -165,7 +216,7 @@ This example adds it as the last item, so it will be the first value provider us
### ISettingStore
While a setting value provider is free to use any source to get the setting value, the`ISettingStore` service is the default source of the setting values. Global, Tenant and User setting value providers use it.
While a setting value provider is free to use any source to get the setting value, the `ISettingStore` service is the default source of the setting values. Global, Tenant and User setting value providers use it.
## ISettingEncryptionService

2
docs/en/Tutorials/Angular/Part-I.md

@ -343,7 +343,7 @@ Run `yarn start`, wait Angular to run the application and open `http://localhost
Open the `app-routing.module.ts` and replace `books` as shown below:
```js
import { ApplicationLayoutComponent } from '@abp/ng.theme.basic';-
import { ApplicationLayoutComponent } from '@abp/ng.theme.basic';
//...
{

4
docs/en/Tutorials/AspNetCore-Mvc/Part-I.md

@ -345,7 +345,7 @@ Open the `Index.cshtml` and change the content as shown below:
````
* This code changes the default inheritance of the Razor View Page Model so it **inherits** from the `BookStorePage` class (instead of `PageModel`). The `BookStorePage` class which comes with the startup template and provides some shared properties/methods used by all pages.
* Ensure that the `IndexModel` (*Index.cshtml.cs)* has the `Acme.BookStore.Pages.Books` namespace, or update it in the `Index.cshtml`.
* Ensure that the `IndexModel` (*Index.cshtml.cs)* has the `Acme.BookStore.Web.Pages.Books` namespace, or update it in the `Index.cshtml`.
#### Add Books Page to the Main Menu
@ -422,7 +422,7 @@ Change the `Pages/Books/Index.cshtml` as following:
````
* `abp-script` [tag helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro) is used to add external **scripts** to the page. It has many additional features compared to standard `script` tag. It handles **minification** and **versioning** for example. See the [bundling & minification document](../../AspNetCore/Bundling-Minification.md) for details.
* `abp-card` and `abp-table` are **tag helpers** for Twitter Bootstrap's [card component](http://getbootstrap.com/docs/4.1/components/card/). There are many tag helpers in ABP to easily use most of the [bootstrap](https://getbootstrap.com/) components. You can also use regular HTML tags instead of these tag helpers, but using tag helpers reduces HTML code and prevents errors by help of the intellisense and compile time type checking. See the [tag helpers document](../../AspNetCore/Tag-Helpers.md).
* `abp-card` and `abp-table` are **tag helpers** for Twitter Bootstrap's [card component](http://getbootstrap.com/docs/4.1/components/card/). There are many tag helpers in ABP to easily use most of the [bootstrap](https://getbootstrap.com/) components. You can also use regular HTML tags instead of these tag helpers, but using tag helpers reduces HTML code and prevents errors by help of the intellisense and compile time type checking. See the [tag helpers document](../../AspNetCore/Tag-Helpers/Index.md).
* You can **localize** the column names in the localization file as you did for the menu items above.
##### Add a Script File

3
docs/en/Tutorials/AspNetCore-Mvc/Part-II.md

@ -421,7 +421,8 @@ $(function () {
Open the `en.json` in the `Acme.BookStore.Domain.Shared` project and add the following line:
````json
"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?"
"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?",
"SuccessfullyDeleted": "Successfully deleted"
````
Run the application and try to delete a book.

159
docs/en/Validation.md

@ -1,3 +1,158 @@
## Validation
# Validation
TODO
Validation system is used to validate the user input or client request for a particular controller action or service method.
ABP is compatible with the ASP.NET Core Model Validation system and everything written in [its documentation](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation) is already valid for ABP based applications. So, this document mostly focuses on the ABP features rather than repeating the Microsoft documentation.
In addition, ABP adds the following benefits:
* Defines `IValidationEnabled` to add automatic validation to an arbitrary class. Since all the [application services](Application-Services.md) inherently implements it, they are also validated automatically.
* Automatically localize the validation errors for the data annotation attributes.
* Provides extensible services to validate a method call or an object state.
* Provides [FluentValidation](https://fluentvalidation.net/) integration.
## Validating DTOs
This section briefly introduces the validation system. For details, see the [ASP.NET Core validation documentation](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation).
### Data Annotation Attributes
Using data annotations is a simple way to implement the formal validation for a [DTO](Data-Transfer-Objects.md) in a declarative way. Example:
````csharp
public class CreateBookDto
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; }
[Range(0, 999.99)]
public decimal Price { get; set; }
}
````
When you use this class as a parameter to an [application service](Application-Services.md) or a controller, it is automatically validated and a localized validation exception is thrown ([and handled](Exception-Handling.md) by the ABP framework).
### IValidatableObject
`IValidatableObject` can be implemented by a DTO to perform custom validation logic. `CreateBookDto` in the following example implements this interface and checks if the `Name` is equals to the `Description` and returns a validation error in this case.
````csharp
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Acme.BookStore
{
public class CreateBookDto : IValidatableObject
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; }
[Range(0, 999.99)]
public decimal Price { get; set; }
public IEnumerable<ValidationResult> Validate(
ValidationContext validationContext)
{
if (Name == Description)
{
yield return new ValidationResult(
"Name and Description can not be the same!",
new[] { "Name", "Description" }
);
}
}
}
}
````
#### Resolving a Service
If you need to resolve a service from the [dependency injection system](Dependency-Injection.md), you can use the `ValidationContext` object. Example:
````csharp
var myService = validationContext.GetRequiredService<IMyService>();
````
> While resolving services in the `Validate` method allows any possibility, it is not a good practice to implement your domain validation logic in DTOs. Keep DTOs simple. Their purpose is to transfer data (DTO: Data Transfer Object).
## Validation Infrastructure
This section explains a few additional services provided by the ABP framework.
### IValidationEnabled Interface
`IValidationEnabled` is an empty marker interface that can be implemented by any class (registered to and resolved from the [DI](Dependency-Injection.md)) to let the ABP framework perform the validation system for the methods of the class. Example:
````csharp
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Validation;
namespace Acme.BookStore
{
public class MyService : ITransientDependency, IValidationEnabled
{
public virtual async Task DoItAsync(MyInput input)
{
//...
}
}
}
````
> ABP framework uses the [dynamic proxying / interception](Dynamic-Proxying-Interceptors.md) system to perform the validation. In order to make it working, your method should be **virtual** or your service should be injected and used over an **interface** (like `IMyService`).
### AbpValidationException
Once ABP determines a validation error, it throws an exception of type `AbpValidationException`. Your application code can throw `AbpValidationException`, but most of the times it is not needed.
* `ValidationErrors` property of the `AbpValidationException` contains the validation error list.
* Log level of the `AbpValidationException` is set to `Warning`. It logs all the validation errors to the [logging system](Logging.md).
* `AbpValidationException` is automatically caught by the ABP framework and converted to a usable error into with HTTP 400 status code. See the [exception handling](Exception-Handling.md) document for more.
## Advanced Topics
### IObjectValidator
In addition to the automatic validation, you may want to manually validate an object. In this case, [inject](Dependency-Injection.md) and use the `IObjectValidator` service:
* `Validate` method validates the given object based on the validation rules and throws an `AbpValidationException` if it is not in a valid state.
* `GetErrors` doesn't throw an exception, but only returns the validation errors.
`IObjectValidator` is implemented by the `ObjectValidator` by default. `ObjectValidator` is extensible; you can implement `IObjectValidationContributor` interface to contribute a custom logic. Example:
````csharp
public class MyObjectValidationContributor
: IObjectValidationContributor, ITransientDependency
{
public void AddErrors(ObjectValidationContext context)
{
//Get the validating object
var obj = context.ValidatingObject;
//Add the validation errors if available
context.Errors.Add(...);
}
}
````
* Remember to register your class to the [DI](Dependency-Injection.md) (implementing `ITransientDependency` does it just like in this example)
* ABP will automatically discover your class and use on any type of object validation (including automatic method call validation).
### IMethodInvocationValidator
`IMethodInvocationValidator` is used to validate a method call. It internally uses the `IObjectValidator` to validate objects passes to the method call. You normally don't need to this service since it is automatically used by the framework, but you may want to reuse or replace it on your application in rare cases.
## FluentValidation Integration
Volo.Abp.FluentValidation package integrates the FluentValidation library to the validation system (by implementing the `IObjectValidationContributor`). See the [FluentValidation Integration document](FluentValidation.md) for more.

3
docs/en/Virtual-File-System.md

@ -38,7 +38,8 @@ If you want to add multiple files, this can be tedious. Alternatively, you can d
````C#
<ItemGroup>
<None Remove="MyResources\**\*.*" />
<EmbeddedResource Include="MyResources\**\*.*" />
<Content Remove="MyResources\**\*.*" />
</ItemGroup>
````

65
docs/en/docs-nav.json

@ -60,6 +60,10 @@
"text": "Configuration",
"path": "Configuration.md"
},
{
"text": "Options",
"path": "Options.md"
},
{
"text": "Dependency Injection",
"path": "Dependency-Injection.md",
@ -83,7 +87,14 @@
"path": "Exception-Handling.md"
},
{
"text": "Validation"
"text": "Validation",
"path": "Validation.md",
"items": [
{
"text": "FluentValidation Integration",
"path": "FluentValidation.md"
}
]
},
{
"text": "Authorization",
@ -94,7 +105,8 @@
"path": "Caching.md"
},
{
"text": "Auditing"
"text": "Audit Logging",
"path": "Audit-Logging.md"
},
{
"text": "Settings",
@ -257,25 +269,46 @@
},
{
"text": "Data Access",
"path": "Data-Access.md",
"path": "Data-Access.md",
"items": [
{
"text": "Entity Framework Core Integration",
"path": "Entity-Framework-Core.md",
"items": [
"text": "Connection Strings",
"path": "Connection-Strings.md"
},
{
"text": "Database Providers",
"items": [
{
"text": "Entity Framework Core",
"path": "Entity-Framework-Core.md",
"items": [
{
"text": "Switch to MySQL",
"path": "Entity-Framework-Core-MySQL.md"
},
{
"text": "Switch to PostgreSQL",
"path": "Entity-Framework-Core-PostgreSQL.md"
},
{
"text": "Switch to SQLite",
"path": "Entity-Framework-Core-SQLite.md"
},
{
"text": "Switch to another DBMS",
"path": "Entity-Framework-Core-Other-DBMS.md"
}
]
},
{
"text": "MongoDB",
"path": "MongoDB.md"
},
{
"text": "PostgreSQL Integration",
"path": "Best-Practices/PostgreSQL-Integration.md"
"text": "Dapper",
"path": "Dapper.md"
}
]
},
{
"text": "MongoDB Integration",
"path": "MongoDB.md"
},
{
"text": "Dapper Integration",
"path": "Dapper.md"
}
]
},

BIN
docs/en/images/auditlog-object-diagram.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
docs/en/images/docs-section-ui.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

3
docs/pt-BR/Tutorials/AspNetCore-Mvc/Part-II.md

@ -454,7 +454,8 @@ $(function () {
Abra o `en.json`no `Acme.BookStore.Domain.Shared`projeto e adicione a seguinte linha:
```json
"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?"
"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?",
"SuccessfullyDeleted": "Successfully deleted"
```

2
docs/pt-BR/docs-nav.json

@ -249,7 +249,7 @@
"items": [
{
"text": "Integração do PostgreSQL",
"path": "Best-Practices/PostgreSQL-Integration.md"
"path": "Entity-Framework-Core-PostgreSQL.md"
}
]
},

7
docs/zh-Hans/Best-Practices/Entity-Framework-Core-Integration.md

@ -173,12 +173,12 @@ public static IQueryable<IdentityUser> IncludeDetails(
* **推荐** 推荐在仓储其他方法中使用 `IncludeDetails` 扩展方法, 就像上面的示例代码一样(参阅 FindByNormalizedUserNameAsync).
- **推荐** 覆盖具有 **子集合** 的聚合根仓储中的`IncludeDetails` 方法. 例如:
- **推荐** 覆盖具有 **子集合** 的聚合根仓储中的 `WithDetails` 方法. 例如:
````C#
protected override IQueryable<IdentityUser> IncludeDetails(IQueryable<IdentityUser> queryable)
public override IQueryable<IdentityUser> WithDetails()
{
return queryable.IncludeDetails(); //uses the extension method defined above
return GetQueryable().IncludeDetails(); // Uses the extension method defined above
}
````
@ -205,4 +205,3 @@ public class AbpIdentityEntityFrameworkCoreModule : AbpModule
}
}
````

164
docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/Post.md

@ -0,0 +1,164 @@
# ABP框架v2.0 和 ABP商业版
ABP框架2.0版已经在本周公布.这篇文章解释了为什么我们发布了一个**抢先主版本**,和2.0版本中的变化.
除了v2.0版本,我们很高兴地宣布**ABP商业版**,这是建立在开源ABP框架的之上的一套专业的模块,工具,主题和服务.
## ABP框架V2.0
### 为什么2.0,而不是1.2?
本来在[V1.1.2](https://github.com/abpframework/abp/releases/tag/1.1.2)发布后计划发布1.2版.然而,[有报告](https://github.com/abpframework/abp/issues/2026)称1.x版在Linux上有一些**性能**和**稳定性**问题,尤其是当应用程序部署在**低配CPU和内存**的**Linux**容器上.
我们深入研究了这一问题,并已查明问题的根本原因与**拦截`async`方法**的实现有关.此外,也有一些 **`async`套`sync`** 的用法影响了线程池的优化.
最后,在**社区**在大力协助下我们**解决了所有的问题**.但是,我们也有一些重要的**设计决策**导致了一些**破坏性变更**,因为[语义版本](https://semver.org/),我们不得不改变框架的主版号.
大多数的应用程序不会受到[破坏性变更](https://github.com/abpframework/abp/releases)的影响,或者只需要做一些微小的修改.
### 破坏性变更
#### 删除了一些同步的API
一些拦截器需要使用`async`的API.当他们拦截`sync`方法时,他们需要调用`async`套`sync`.这最终导致了`async`套`sync`的问题.这就是为什么我们[删除了一些同步的API](https://github.com/abpframework/abp/pull/2464).
当你需要**在`async`方法中调用`sync`方法**时, **`async`套`sync`** 这种模式是`C#`一个经典问题.虽然有一些解决方法,但是都有相应的**缺点**,并建议**不要写**这样的代码.你可以在网上找到关于这一话题的许多文档.
为了避免这个问题,我们已经移除:
- `sync`[仓储](https://docs.abp.io/en/abp/latest/Repositories)方法 (如`insert`, `update`, 等...),
- `sync`[工作单元](https://docs.abp.io/en/abp/latest/Unit-Of-Work)API,
- `sync`[后台作业](https://docs.abp.io/en/abp/latest/Background-Jobs)API,
- `sync`[审计日志](https://docs.abp.io/en/abp/latest/Audit-Logging)API,
- 其他一些很少使用的`sync`API.
如果你遇到了编译错误,只需使用这些API的`async`版本.
#### 始终async!
从v2.0开始,ABP框架假设你以`async`方式编写你的应用程序代码.否则,一些框架的功能可能无法正常工作.
建议你的所有[应用服务](https://docs.abp.io/en/abp/latest/Application-Services), [仓储方法](https://docs.abp.io/en/abp/latest/Repositories), 控制器动作(ontroller actions), 页面处理器(page handlers)都是`async`.
即使你的应用服务方法并不需要是`async`,也将其设置为`async`,因为拦截器需要执行`async`操作(授权,工作单元等).你可以在不调用`async`的方法中返回`Task.Completed`.
示例:
````csharp
public Task<int> GetValueAsync()
{
//这个方法没有任何async调用
return Task.CompletedTask(42);
}
````
上述例子通常并不需要是`async`因为它不执行`async`调用.然而,将它设置为`async`,这样可以帮助ABP框架运行拦截器时避免出现`async`套sync的调用.
此规则不强制你写的每一个方法都是`async`.这样并不好而且很乏味.只在拦截的服务上需要(特别是[应用服务](https://docs.abp.io/en/abp/latest/Application-Services)和[仓库方法](https://docs.abp.io/en/abp/latest/Repositories))
#### 其他破坏性变更
查看[发行说明](https://github.com/abpframework/abp/releases/tag/2.0.0)中的破坏性变更.他们中的大多数都不会影响你的应用程序代码.
### 新功能
本次发布还包含一些新的功能和一堆改进:
- [#2597](https://github.com/abpframework/abp/pull/2597) 新的`Volo.Abp.AspNetCore.Serilog`包.
- [#2526](https://github.com/abpframework/abp/issues/2526) `C#`客户端代理的客户端验证.
- [#2374](https://github.com/abpframework/abp/issues/2374) `async`后台作业.
- [#265](https://github.com/abpframework/abp/issues/265) 管理应用程序关闭.
- [#2472](https://github.com/abpframework/abp/issues/2472) `IdentityServer`模块实现`DeviceFlowCodes`和`TokenCleanupService`.
功能,改进和BUG修复的完整列表, 请查看[发布说明](https://github.com/abpframework/abp/releases/tag/2.0.0).
### 文档
随着v2.0的发布,我们也完成了一些缺少的文档.在接下来的几周内,我们将主要关注文档和教程.
## ABP商业版
[ABP商业版](https://commercial.abp.io/)是建立在开源ABP框架之上的一套专业的**模块,工具,主题和服务**.
- 除了ABP框架免费和[开源模块](https://docs.abp.io/en/abp/latest/Modules/Index)之外, 提供[专业模块](https://commercial.abp.io/modules).
- 包含一个漂亮的[UI主题](https://commercial.abp.io/themes), 具有5种不同的样式.
- 提供[ABP套件](https://commercial.abp.io/tools/suite); 一个让开发更具有生产力的工具. 通过配置实体属性, 它可以在几秒内创建全栈的CRUD页面. 更多的功能陆续开发中.
- 为企业提供[高级支持](ttps://commercial.abp.io/support).
除了这些标准的功能,我们会将提供定制服务.更多细节请参见[commercial.abp.io](https://commercial.abp.io/)网站.
### ABP框架 vs ABP商业版
ABP商业版**不是付费版本**的ABP框架.可以把它当作为专业公司提供的**附加套餐**.你可以用它来节省时间和更快地开发产品.
ABP框架将永远是**开源免费**的!
一个原则是,我们创建的主要基础设施作为开源产品, 然后销售额外的预制应用程序功能,主题和工具.类似于[ASP.NET Boilerplate](https://aspnetboilerplate.com/)和[ASP.NET Zero](https://aspnetzero.com/)产品.
购买商业版许可极大地节省你的时间和精力,你可以专注于自己的业务,此外也可获得专门的和优先的支持.同时,你也在支持ABP核心团队,因为我们花了大部分时间来开发,维护和支持开源的ABP框架.
有了ABP商业版,ABP现在变为一个平台.我们称之为**ABP.IO平台**, 其中包括开源ABP框架和ABP商业版.
### 演示
如果你想知道ABP商业版应用程序的启动模板是什么样,你可以很容易地[创建一个演示](https://commercial.abp.io/demo),并看到它的实际效果.该演示包括所有的预制模块和主题.
下面是一张IdentityServer管理模块UI的截图:
![abp-commercial-demo](abp-commercial-demo.png)
这是一张来自使用material设计风格主题的演示应用程序的截图:
![lepton-theme-material](lepton-theme-material.png)
### 价格
你可以创建**无限个工程/产品**, 销售给**无限个客户**, 部署在**无限台服务器上**, 不受任何限制. 定价主要是基于**开发人员个数**,**支持等级**和**源代码**需求上.有三个标准包;
- **团队许可**: 包括所有的模块,主题和工具.允许最多3个开发者开发产品.可购买额外的开发者许可.
- **商业许可**: 允许下载所有的模块和主题的源代码.此外,默认包含了5个开发者许可.可购买额外的开发者许可.
- **企业许可**: 在商业许可上, 提供无限的专属支持.
请查看[价格页面](https://commercial.abp.io/pricing)了解详细信息.除了标准包以外,我们也提供定制服务和定制许可.如有任何问题,请[联系我们](https://commercial.abp.io/contact).
#### 许可比较
许可价格是根据开发者数量,支持等级和源代码访问而变化的.
##### 源代码
团队许可证不包括预制模块和主题的源代码.以**NuGet和NPM包**的方式使用所有这些模块.通过这种方式,你可以很容易地通过更新包的依赖得到**新功能和bug修复**仅.但是不能访问其源代码.所以不能嵌入模块的源代码到你的应用程序里,和随意修改源代码.
预制模块提供一定等级的**定制**和**扩展**,并允许你覆盖服务,UI部分等.我们正在努力使他们更加可定制和可扩展.如果你无需在预制模块中做很大修改的话,团队许可是你理想的选择,因为它更便宜,并且可轻松获得新的功能和bug修复.
商业和企业许可允许你在需要时**下载任何模块和主题的源代码**.它们使用与团队许可相同的启动模板,所以所有的模块都默认使用`NuGet`和`NPM`包.但是,在需要的情况下,你可以从一个模块中删除包的依赖,并嵌入它的源代码到你自己的解决方案中,然后完全定制它.在这种情况下,当一个新版本可用时, 升级模块将不会那么容易.当然, 你不必升级!但是,如果你愿意,你也可以使用一些合并工具或Git的分支系统来做到这一点.
#### 许可周期
ABP商业版许可是**永久的**,这意味着你可以**永远使用**它继续开发应用程序.
但是,下面的服务周期为一年:
- 高级**支持**一年后结束.你可以继续得到社区支持.
- 一年后将不会得到模块和主题的**更新**.你可以继续使用最后获得的版本.甚至可以在主版本内得到BUG修复和改进.
- 你可使用**ABP套件**一年.
如果想继续获得这些好处,可延长许可期限.续订价格比正常价格低20%.
## NDC London 2020
与[去年](https://medium.com/volosoft/impressions-of-ndc-london-2019-f8f391bb7a9c)一样, 我们是著名的软件开发会议[NDC London](https://ndc-london.com/)的合作伙伴! 去年, 我们开展了[ASP.NET Boilerplate](https://aspnetboilerplate.com/)和[ASP.NET Zero](https://aspnetzero.com/)主题:
![ndc-london-volosoft](ndc-london-volosoft.png)
今年,我们将着重于**ABP.IO平台**(开源ABP框架和ABP商业版).我们的展位会是这样的:
![ndc-london-volosoft](ndc-2020-volosoft-booth-wall.png)
如果你参加会议,记得要参观我们的展位.我们将很高兴来谈一谈ABP平台的功能,目标和软件开发.
### 你想见ABP团队吗?
如果你在伦敦, 而且想和我们喝杯咖啡的话, 在2月1日的下午[@hibrahimkalkan](https://twitter.com/hibrahimkalkan)和[@ismcagdas](https://twitter.com/ismcagdas)会在那.
想见面就给info@abp.io写个邮件 :)

BIN
docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/abp-commercial-demo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

BIN
docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/lepton-theme-material.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

BIN
docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/ndc-2020-volosoft-booth-wall.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

BIN
docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/ndc-london-volosoft.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

64
docs/zh-Hans/Connection-Strings.md

@ -0,0 +1,64 @@
# 连接字符串
ABP框架的设计是[模块化](Module-Development-Basics.md), [微服务兼容](Microservice-Architecture.md) 和 [多租户](Multi-Tenancy.md). 同时设计了连接字符串管理来支持这些场景;
* 允许为每个模块设置单独的连接字符串,这样每个模块都可以有自己的物理数据库. 甚至可以将模块配置为使用不同的DBMS.
* 允许为每个租户设置单独的连接字符串使用单独的数据库(在SaaS应用程序中).
它还支持混合场景;
* 允许将模块分组到数据库 (所有的模块分组到一个共享数据库, 两个模块使用数据库A, 3个模块使用数据库B, 一个数据库使用数据库C其余的数据库使用数据库D...等.)
* 允许将租户分组到数据库中,像模块一样.
* 允许为每个租户每个模块分离数据库 (数据库过多会增加维护成本,但ABP框架支持这种需求).
所有[预构建应用模块](Modules/Index.md)已设计为与以上场景兼容.
## 配置连接字符串
参见以下配置:
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=MyMainDb;Trusted_Connection=True;",
"AbpIdentityServer": "Server=localhost;Database=MyIdsDb;Trusted_Connection=True;",
"AbpPermissionManagement": "Server=localhost;Database=MyPermissionDb;Trusted_Connection=True;"
}
````
> ABP使用 `IConfiguration` 服务获取应用程序配置. 虽然在 `appsettings.json` 文件中写入配置是最简单的方法, 但它不仅限于此文件. 你可以使用环境变量, user secrets, Azure Key Vault... 等. 更多信息参阅 [配置](Configuration.md) 文档.
以上配置定义了三个不同的连接字符串:
* `MyMainDb` (`Default` 连接字符串)是应用程序的主连接字符串. 如果没有为模块指定连接字符串,则回退到 `Default` 连接字符串. [应用程序启动模板](Startup-Templates/Application.md) 配置为使用单个字符串, 所以所有的模块都使用单个数据库.
* `MyIdsDb` 由 [IdentityServer](Modules/IdentityServer.md) 模块使用.
* `MyPermissionDb` 由 [权限管理](Modules/Permission-Management.md) 模块使用.
[预构建的应用程序模块](Modules/Index.md) 为连接字符串名称定义常量. 例如IdentityServer模块在 `AbpIdentityServerDbProperties` 类(位于 `Volo.Abp.IdentityServer` 命名空间)定义了 `ConnectionStringName` 常量 . 其他的模块类似的定义常量,你可以查看连接字符串的名称.
## 设置连接字符串名称
模块通常使用 `ConnectionStringName` attribute 为 `DbContext` 类关联一个唯一的连接字符串名称. 示例:
````csharp
[ConnectionStringName("AbpIdentityServer")]
public class IdentityServerDbContext
: AbpDbContext<IdentityServerDbContext>, IIdentityServerDbContext
{
}
````
对于 [Entity Framework Core](Entity-Framework-Core.md) 和 [MongoDB](MongoDB.md), 写入到 `DbContext` 类 (和接口,如果有的话).
> 如果你开发的是与数据库提供程序无关的可重用模块, 请参见 [最佳实践指南](Best-Practices/Index.md).
## Entity Framework Core的数据库迁移
关系数据库需要在使用数据库之前创建数据库和数据库架构 (表, 视图...等).
启动模板(使用 EF Core ORM) 带有一个数据库和一个 `.EntityFrameworkCore.DbMigrations` 项目,其中包含数据库的迁移文件. 该项目主要定义了一个*YourProjectName*MigrationsDbContext,它调用所有模块的 `Configure...()` 方法,例如 `builder.ConfigurePermissionManagement()`.
一旦要分离模块的数据库,通常需要创建第二个迁移路径. 最简单的方法是创建一个带有 `DbContext` 的 `.EntityFrameworkCore.DbMigrations` 项目副本, 更改为只调用需要存储在第二个数据库中的模块的 `Configure...()` 方法并重新创建迁移. 这时你还需要更改 `.DbMigrator` 应用程序使其兼容第二个数据库,这样每个数据库将有一个单独的迁移DbContext.
## 多租户
参阅 [多租户文档](Multi-Tenancy.md)了解如何为租户使用单独的数据库.

0
docs/zh-Hans/Best-Practices/PostgreSQL-Integration.md → docs/zh-Hans/Entity-Framework-Core-PostgreSQL.md

59
docs/zh-Hans/FluentValidation.md

@ -0,0 +1,59 @@
# FluentValidation 集成
ABP[验证](Validation.md)基础设施是可扩展的. [Volo.Abp.FluentValidation](https://www.nuget.org/packages/Volo.Abp.FluentValidation) NuGet 包扩展了验证系统使其与[FluentValidation](https://fluentvalidation.net/)库一起工作.
## 安装
建议使用[ABP CLI](CLI.md)安装包.
### 使用ABP CLI
在项目(.csproj文件)的文件夹中打开命令行窗口并输入以下命令:
````bash
abp add-package Volo.Abp.FluentValidation
````
### 手动安装
如果你想手动安装;
1. 添加 [Volo.Abp.FluentValidation](https://www.nuget.org/packages/Volo.Abp.FluentValidation) NuGet包到你的项目:
````
Install-Package Volo.Abp.FluentValidation
````
2. 添加 `AbpFluentValidationModule` 到你的模块的依赖列表:
````csharp
[DependsOn(
//...other dependencies
typeof(AbpFluentValidationModule) //Add the FluentValidation module
)]
public class YourModule : AbpModule
{
}
````
## 使用 FluentValidation
按照 [FluentValidation文档](https://fluentvalidation.net/) 创建验证器类.
例如:
````csharp
public class CreateUpdateBookDtoValidator : AbstractValidator<CreateUpdateBookDto>
{
public CreateUpdateBookDtoValidator()
{
RuleFor(x => x.Name).Length(3, 10);
RuleFor(x => x.Price).ExclusiveBetween(0.0f, 999.0f);
}
}
````
ABP会自动找到这个类并在对象验证时与 `CreateUpdateBookDto` 关联.
## 另请参阅
* [验证系统](Validation.md)

5
docs/zh-Hans/Logging.md

@ -0,0 +1,5 @@
# 日志
ABP框架没有实现任何日志基础设施. 它使用[ASP.NET Core日志系统](https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/logging).
> .NET Core 的日志系统是独立于ASP.NET Core的,它可以在任何类型的应用程序中使用.

85
docs/zh-Hans/Modules/Setting-Management.md

@ -1,3 +1,84 @@
# Setting Management Module
# 设置管理模块
TODO
设置管理模块实现了 `ISettingStore` (参阅 [设置系统](../Settings.md)) 将设置值存储在数据库中, 并提供 `ISettingManager` 管理 (更改) 数据库中设置值的功能.
> [启动模板](../Startup-Templates/Index.md)默认安装并配置了设置管理模块. 大部分情况下你不需要手动的添加该到模块到应用程序中.
## ISettingManager
`ISettingManager` 用于获取和设定设置值. 示例:
````csharp
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.SettingManagement;
namespace Demo
{
public class MyService : ITransientDependency
{
private readonly ISettingManager _settingManager;
//Inject ISettingManager service
public MyService(ISettingManager settingManager)
{
_settingManager = settingManager;
}
public async Task FooAsync()
{
Guid user1Id = ...;
Guid tenant1Id = ...;
//Get/set a setting value for the current user or the specified user
string layoutType1 =
await _settingManager.GetOrNullForCurrentUserAsync("App.UI.LayoutType");
string layoutType2 =
await _settingManager.GetOrNullForUserAsync("App.UI.LayoutType", user1Id);
await _settingManager.SetForCurrentUserAsync("App.UI.LayoutType", "LeftMenu");
await _settingManager.SetForUserAsync(user1Id, "App.UI.LayoutType", "LeftMenu");
//Get/set a setting value for the current tenant or the specified tenant
string layoutType3 =
await _settingManager.GetOrNullForCurrentTenantAsync("App.UI.LayoutType");
string layoutType4 =
await _settingManager.GetOrNullForTenantAsync("App.UI.LayoutType", tenant1Id);
await _settingManager.SetForCurrentTenantAsync("App.UI.LayoutType", "LeftMenu");
await _settingManager.SetForTenantAsync(tenant1Id, "App.UI.LayoutType", "LeftMenu");
//Get/set a global and default setting value
string layoutType5 =
await _settingManager.GetOrNullGlobalAsync("App.UI.LayoutType");
string layoutType6 =
await _settingManager.GetOrNullDefaultAsync("App.UI.LayoutType");
await _settingManager.SetGlobalAsync("App.UI.LayoutType", "TopMenu");
}
}
}
````
你可以从不同的设置值提供程序中(默认,全局,用户,租户...等)中获取或设定设置值.
### Setting Cache
设置值缓存在 [分布式缓存](../Caching.md) 系统中. 建议始终使用 `ISettingManager` 更改设置值.
## Setting Management Providers
设置管理模块是可扩展的,像[设置系统](../Settings.md)一样. 你可以通过自定义设置管理提供程序进行扩展. 有5个预构建的设置管理程序程序按以下顺序注册:
* `DefaultValueSettingManagementProvider`: 从设置定义的默认值中获取值,由于默认值是硬编码在设置定义上的,所以无法更改默认值.
* `ConfigurationSettingManagementProvider`:从 [IConfiguration 服务](../Configuration.md)中获取值. 由于无法在运行时更改配置值,所以无法更改配置值.
* `GlobalSettingManagementProvider`: 获取或设定设置的全局 (系统范围)值.
* `TenantSettingManagementProvider`: 获取或设定租户的设置值.
* `UserSettingManagementProvider`: 获取或设定用户的设置值.
`ISettingManager` 在 `get/set` 方法中使用设置管理提供程序. 通常每个设置程序提供程序都在 `ISettingManagement` 服务上定义了模块方法 (比如用户设置管理程序提供定义了 `SetForUserAsync` 方法).

51
docs/zh-Hans/Settings.md

@ -40,6 +40,33 @@ ABP会自动发现并注册设置的定义.
* **Providers**: 限制可用于特定的设置值提供程序(参阅设置值提供程序部分了解更多).
* **Properties**: 设置此值的自定义属性 名称/值 集合,可以在之后的应用程序代码中使用.
### 更改依赖模块的设置定义
在某些情况下,你可能希望更改应用程序/模块所依赖的其他模块中定义的设置的某些属性. 设置定义提供程序可以查询和更新设置定义.
下面的示例中获取了由 [Volo.Abp.Emailing](Emailing.md) 包定义的设置并将其更改:
````csharp
public class MySettingDefinitionProvider : SettingDefinitionProvider
{
public override void Define(ISettingDefinitionContext context)
{
var smtpHost = context.GetOrNull("Abp.Mailing.Smtp.Host");
if (smtpHost != null)
{
smtpHost.DefaultValue = "mail.mydomain.com";
smtpHost.DisplayName =
new LocalizableString(
typeof(MyLocalizationResource),
"SmtpServer_DisplayName"
);
}
}
}
````
> 使用常量作为设置名称是一种好习惯,ABP的包就是这样做的. `Abp.Mailing.Smtp`设置名称是在`EmailSettingNames`类(在Volo.Abp.Emailing名称空间中)定义的常量.
## 读取设置值
### ISettingProvider
@ -118,6 +145,30 @@ var requireDigit = abp.setting.getBoolean('Abp.Identity.Password.RequireDigit');
全局,租户和用户设置值提供程序使用 `ISettingStore` 从数据源读取值(参见下面的小节).
### 在应用程序配置中设置值
上一节提到 `ConfigurationSettingValueProvider` 从 `IConfiguration` 服务中读取设置, 该服务默认从 `appsettings.json` 中读取值. 所以在 `appsettings.json` 文件中配置设置值是最简单的方式.
例如你可以像以下方式一样配置 [IEmailSender](Emailing.md) 设置:
````json
{
"Settings": {
"Abp.Mailing.DefaultFromAddress": "noreply@mydomain.com",
"Abp.Mailing.DefaultFromDisplayName": "My Application",
"Abp.Mailing.Smtp.Host": "mail.mydomain.com",
"Abp.Mailing.Smtp.Port": "547",
"Abp.Mailing.Smtp.UserName": "myusername",
"Abp.Mailing.Smtp.Password": "mySecretPassW00rd",
"Abp.Mailing.Smtp.EnableSsl": "True"
}
}
````
设置值应该在 `Settings` 部分配置,如本例所示.
> `IConfiguration`是.NET Core的服务,它不仅可以从 `appsettings.json` 中读取值,还可以从环境,用户机密...等中读取值. 有关更多信息请参阅[微软文档](https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/configuration/).
### 自定义设置值提供程序
扩展设置系统的方式是定义一个派生自 `SettingValueProvider` 的类. 示例:

10
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md

@ -225,7 +225,7 @@ using Volo.Abp.Application.Services;
namespace Acme.BookStore
{
public interface IBookAppService :
IAsyncCrudAppService< //定义了CRUD方法
ICrudAppService< //定义了CRUD方法
BookDto, //用来展示书籍
Guid, //Book实体的主键
PagedAndSortedResultRequestDto, //获取书籍的时候用于分页和排序
@ -238,8 +238,8 @@ namespace Acme.BookStore
````
* 框架定义应用程序服务的接口<u>不是必需的</u>. 但是,它被建议作为最佳实践.
* `IAsyncCrudAppService`定义了常见的**CRUD**方法:`GetAsync`,`GetListAsync`,`CreateAsync`,`UpdateAsync`和`DeleteAsync`. 你可以从空的`IApplicationService`接口继承并手动定义自己的方法.
* `IAsyncCrudAppService`有一些变体, 你可以在每个方法中使用单独的DTO,也可以分别单独指定.
* `ICrudAppService`定义了常见的**CRUD**方法:`GetAsync`,`GetListAsync`,`CreateAsync`,`UpdateAsync`和`DeleteAsync`. 你可以从空的`IApplicationService`接口继承并手动定义自己的方法.
* `ICrudAppService`有一些变体, 你可以在每个方法中使用单独的DTO,也可以分别单独指定.
#### BookAppService
@ -255,7 +255,7 @@ using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore
{
public class BookAppService :
AsyncCrudAppService<Book, BookDto, Guid, PagedAndSortedResultRequestDto,
CrudAppService<Book, BookDto, Guid, PagedAndSortedResultRequestDto,
CreateUpdateBookDto, CreateUpdateBookDto>,
IBookAppService
{
@ -268,7 +268,7 @@ namespace Acme.BookStore
}
````
* `BookAppService`继承了`AsyncCrudAppService<...>`.`AsyncCrudAppService<...>`实现了上面定义的CRUD方法.
* `BookAppService`继承了`CrudAppService<...>`.它实现了上面定义的CRUD方法.
* `BookAppService`注入`IRepository <Book,Guid>`,这是`Book`实体的默认仓储. ABP自动为每个聚合根(或实体)创建默认仓储. 请参阅[仓储文档](../../Repositories.md)
* `BookAppService`使用`IObjectMapper`将`Book`对象转换为`BookDto`对象, 将`CreateUpdateBookDto`对象转换为`Book`对象. 启动模板使用[AutoMapper](http://automapper.org/)库作为对象映射提供程序. 你之前定义了映射, 因此它将按预期工作.

3
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md

@ -421,7 +421,8 @@ $(function () {
打开`Acme.BookStore.Domain.Shared`项目中的`en.json`并添加以下行:
````json
"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?"
"BookDeletionConfirmationMessage": "Are you sure to delete the book {0}?",
"SuccessfullyDeleted": "Successfully deleted"
````
运行程序并尝试删除一个book实体.

164
docs/zh-Hans/Validation.md

@ -1,3 +1,163 @@
## Validation
# 验证
待添加
验证系统用于验证对于特定的控制器操作或服务的方法的用户输入或客户端请求.
ABP与ASP.NET Core模型验证系统系统兼容,[模型验证文档](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation)中的内容对于基于ABP应用程序同样有效.所以本文主要集中在ABP特征,而不是重复微软文档.
ABP增加了以下优点:
* 定义 `IValidationEnabled` 向任意类添加自动验证. 所有的[应用服务](Application-Services.md)都实现了该接口,所以它们会被自动验证.
* 自动将数据注解属性的验证错误信息本地化.
* 提供可扩展的服务来验证方法调用或对象的状态。
* 提供[FluentValidation](https://fluentvalidation.net/)的集成.
## 验证DTO
本节简要介绍了验证系统.有关详细信息请参阅[ASP.NET Core验证文档](https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/validation).
### 数据注解 Attribute
使用数据注解是一种以声明式对[DTO](Data-Transfer-Objects.md)进行验证的简单方法.
示例 :
````csharp
public class CreateBookDto
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; }
[Range(0, 999.99)]
public decimal Price { get; set; }
}
````
当使用该类作为[应用服务](Application-Services.md)或控制器的参数时,将对其自动验证并抛出本地化异常(由ABP框架[处理](Exception-Handling.md)).
### IValidatableObject
`IValidatableObject` can be implemented by a DTO to perform custom validation logic. `CreateBookDto` in the following example implements this interface and checks if the `Name` is equals to the `Description` and returns a validation error in this case.
可以将DTO实现 `IValidatableObject` 接口进行自定义验证逻辑. 下面的示例中 `CreateBookDto` 实现了这个接口,并检查 `Name` 是否等于 `Description` 并返回一个验证错误.
````csharp
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Acme.BookStore
{
public class CreateBookDto : IValidatableObject
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; }
[Range(0, 999.99)]
public decimal Price { get; set; }
public IEnumerable<ValidationResult> Validate(
ValidationContext validationContext)
{
if (Name == Description)
{
yield return new ValidationResult(
"Name and Description can not be the same!",
new[] { "Name", "Description" }
);
}
}
}
}
````
#### 解析服务
如果你需要从[依赖注入系统](Dependency-Injection.md)解析服务,可以使用 `ValidationContext` 对象.
例:
````csharp
var myService = validationContext.GetRequiredService<IMyService>();
````
> 虽然可以在 `Validate` 方法中解析服务实现任何可能性,但在DTO中实现领域验证逻辑不是一个很好的做法. 应保持简单的DTO,他们的目的是传输数据(DTO:数据传输对象).
## 验证基础设施
本节介绍了ABP框架提供的一些额外的服务.
### IValidationEnabled 接口
`IValidationEnabled` 是可以由任何类来实现的空标记接口(注册到[DI](Dependency-Injection.md)并从中解析),让ABP框架为该类执行验证系统.
示例 :
````csharp
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Validation;
namespace Acme.BookStore
{
public class MyService : ITransientDependency, IValidationEnabled
{
public virtual async Task DoItAsync(MyInput input)
{
//...
}
}
}
````
> ABP框架使用[动态代理/拦截](Dynamic-Proxying-Interceptors.md)系统来执行验证.为了使其工作,你的方法应该是 **virtual** 的,服务应该被注入并通过接口(如`IMyService`)使用.
### AbpValidationException
一旦ABP确定了一个验证错误,它就会抛出类型为 `AbpValidationException` 的异常. 你的应用程序代码可以抛出 `AbpValidationException`,但大多数情况不会使用它.
* `ValidationErrors` 是 `AbpValidationException` 的属性,它包含了验证错误列表.
* `AbpValidationException` 的日志级别设置为 `Warning`. 它将所有验证错误记录到[日志系统](Logging.md).
* `AbpValidationException` 由ABP框架自动捕获并将HTTP状态码设置为400转换成可用的错误响应. 参阅[异常处理](Exception-Handling.md)文档了解更多.
## 高级主题
### IObjectValidator
除了自动验证你可能需要手动验证对象,这种情况下[注入](Dependency-Injection.md)并使用 `IObjectValidator` 服务:
* `Validate` 方法根据验证​​规则验证给定对象,如果对象没有被验证通过会抛出 `AbpValidationException` 异常.
* `GetErrors` 不会抛出异常,只返回验证错误.
`IObjectValidator` 默认由 `ObjectValidator` 实现. `ObjectValidator`是可扩展的; 可以实现`IObjectValidationContributor`接口提供自定义逻辑.
示例 :
````csharp
public class MyObjectValidationContributor
: IObjectValidationContributor, ITransientDependency
{
public void AddErrors(ObjectValidationContext context)
{
//Get the validating object
var obj = context.ValidatingObject;
//Add the validation errors if available
context.Errors.Add(...);
}
}
````
* 记录将类注册到[DI](Dependency-Injection.md)(实现`ITransientDependency` 如同本例)
* ABP会自动发现验证类,并用于任何类型的对象验证(包括自动方法调用验证).
### IMethodInvocationValidator
`IMethodInvocationValidator` 用于验证方法调用. 它在内部使用 `IObjectValidator` 来验证传递给方法调用的对象. 由于框架会自动使用此服务,通常你并不需要此服务,但在少数情况下你可能在应用程序中重用或替换它.
## FluentValidation Integration
Volo.Abp.FluentValidation 包将FluentValidation库集成到了验证系统(通过实现 `IObjectValidationContributor`). 请参阅[FluentValidation集成文档](FluentValidation.md)了解更多信息.

3
docs/zh-Hans/Virtual-File-System.md

@ -39,7 +39,8 @@ namespace MyCompany.MyProject
````C#
<ItemGroup>
<None Remove="MyResources\**\*.*" />
<EmbeddedResource Include="MyResources\**\*.*" />
<Content Remove="MyResources\**\*.*" />
</ItemGroup>
````

11
docs/zh-Hans/docs-nav.json

@ -75,7 +75,14 @@
"path": "Exception-Handling.md"
},
{
"text": "验证"
"text": "验证",
"path": "Validation.md",
"items": [
{
"text": "FluentValidation集成",
"path": "FluentValidation.md"
}
]
},
{
"text": "授权"
@ -254,7 +261,7 @@
"items": [
{
"text": "PostgreSQL 集成",
"path": "Best-Practices/PostgreSQL-Integration.md"
"path": "Entity-Framework-Core-PostgreSQL.md"
}
]
},

16
framework/Volo.Abp.sln

@ -1,4 +1,4 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28922.388
MinimumVisualStudioVersion = 10.0.40219.1
@ -256,6 +256,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Minify", "src\Volo
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Minify.Tests", "test\Volo.Abp.Minify.Tests\Volo.Abp.Minify.Tests.csproj", "{E69182B3-350A-43F5-A935-5EBBEBECEF97}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Serilog", "src\Volo.Abp.AspNetCore.Serilog\Volo.Abp.AspNetCore.Serilog.csproj", "{3B801003-BE74-49ED-9749-DA5E99F45EBF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Serilog.Tests", "test\Volo.Abp.AspNetCore.Serilog.Tests\Volo.Abp.AspNetCore.Serilog.Tests.csproj", "{9CAA07ED-FE5C-4427-A6FA-6C6CB5B4CC62}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -762,6 +766,14 @@ Global
{E69182B3-350A-43F5-A935-5EBBEBECEF97}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E69182B3-350A-43F5-A935-5EBBEBECEF97}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E69182B3-350A-43F5-A935-5EBBEBECEF97}.Release|Any CPU.Build.0 = Release|Any CPU
{3B801003-BE74-49ED-9749-DA5E99F45EBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B801003-BE74-49ED-9749-DA5E99F45EBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B801003-BE74-49ED-9749-DA5E99F45EBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B801003-BE74-49ED-9749-DA5E99F45EBF}.Release|Any CPU.Build.0 = Release|Any CPU
{9CAA07ED-FE5C-4427-A6FA-6C6CB5B4CC62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9CAA07ED-FE5C-4427-A6FA-6C6CB5B4CC62}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9CAA07ED-FE5C-4427-A6FA-6C6CB5B4CC62}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9CAA07ED-FE5C-4427-A6FA-6C6CB5B4CC62}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -892,6 +904,8 @@ Global
{73559227-EBF0-475F-835B-1FF0CD9132AA} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{928DC30D-C078-4BB4-A9F8-FE7252C67DC6} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{E69182B3-350A-43F5-A935-5EBBEBECEF97} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{3B801003-BE74-49ED-9749-DA5E99F45EBF} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{9CAA07ED-FE5C-4427-A6FA-6C6CB5B4CC62} = {447C8A77-E5F0-4538-8687-7383196D04EA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

4
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs

@ -11,14 +11,14 @@ namespace Microsoft.AspNetCore.Builder
{
if (ctx.User.Identity?.IsAuthenticated != true)
{
var result = await ctx.AuthenticateAsync(schema);
var result = await ctx.AuthenticateAsync(schema).ConfigureAwait(false);
if (result.Succeeded && result.Principal != null)
{
ctx.User = result.Principal;
}
}
await next();
await next().ConfigureAwait(false);
});
}
}

6
framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo/Abp/AspNetCore/Authentication/OAuth/Claims/MultipleClaimAction.cs

@ -14,7 +14,11 @@ namespace Volo.Abp.AspNetCore.Authentication.OAuth.Claims
public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer)
{
var prop = userData.GetProperty(ValueType);
JsonElement prop;
if (!userData.TryGetProperty(ValueType, out prop))
return;
if (prop.ValueKind == JsonValueKind.Null)
{
return;

8
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/MultiTenancyMiddleware.cs

@ -33,7 +33,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
TenantConfiguration tenant = null;
if (resolveResult.TenantIdOrName != null)
{
tenant = await FindTenantAsync(resolveResult.TenantIdOrName);
tenant = await FindTenantAsync(resolveResult.TenantIdOrName).ConfigureAwait(false);
if (tenant == null)
{
//TODO: A better exception?
@ -45,7 +45,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
using (_currentTenant.Change(tenant?.Id, tenant?.Name))
{
await next(context);
await next(context).ConfigureAwait(false);
}
}
@ -53,11 +53,11 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
{
if (Guid.TryParse(tenantIdOrName, out var parsedTenantId))
{
return await _tenantStore.FindAsync(parsedTenantId);
return await _tenantStore.FindAsync(parsedTenantId).ConfigureAwait(false);
}
else
{
return await _tenantStore.FindAsync(tenantIdOrName);
return await _tenantStore.FindAsync(tenantIdOrName).ConfigureAwait(false);
}
}
}

5
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/CachedApplicationConfigurationClient.cs

@ -7,6 +7,7 @@ using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.DynamicProxying;
using Volo.Abp.Threading;
using Volo.Abp.Users;
namespace Volo.Abp.AspNetCore.Mvc.Client
@ -42,12 +43,12 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
configuration = await Cache.GetOrAddAsync(
cacheKey,
async () => await Proxy.Service.GetAsync(),
async () => await Proxy.Service.GetAsync().ConfigureAwait(false),
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(120) //TODO: Should be configurable. Default value should be higher (5 mins would be good).
}
);
).ConfigureAwait(false);
if (httpContext != null)
{

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

Loading…
Cancel
Save