Browse Source

Merge branch 'dev' into #1666-organization-units

pull/2563/head
Mehmet Perk 6 years ago
committed by GitHub
parent
commit
444a2dcced
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      README.md
  2. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/AbpIoLocalization.csproj
  3. 13
      abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hant.json
  4. 32
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  5. 29
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hans.json
  6. 60
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hant.json
  7. 31
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hant.json
  8. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/zh-Hant.json
  9. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  10. 30
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json
  11. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/zh-Hant.json
  12. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/zh-Hant.json
  13. 159
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hant.json
  14. 40
      build-all-release.ps1
  15. 40
      build-all.ps1
  16. 16
      build/build-all-release.ps1
  17. 16
      build/build-all.ps1
  18. 34
      build/common.ps1
  19. 16
      build/test-all.ps1
  20. 2
      common.props
  21. 9
      configureawait.props
  22. 18
      docs/cs/CLI.md
  23. 77
      docs/cs/Entity-Framework-Core-PostgreSQL.md
  24. 59
      docs/cs/docs-nav.json
  25. BIN
      docs/cs/images/docs-section-ui.png
  26. 3
      docs/en/Ambient-Context-Pattern.md
  27. 734
      docs/en/AspNet-Boilerplate-Migration-Guide.md
  28. 372
      docs/en/Audit-Logging.md
  29. 42
      docs/en/Background-Jobs-Hangfire.md
  30. 8
      docs/en/Background-Jobs.md
  31. 2
      docs/en/Best-Practices/Index.md
  32. 4
      docs/en/Blog-Posts/2019-02-22/Post.md
  33. 164
      docs/en/Blog-Posts/2020-01-15 v2_0_Release/Post.md
  34. BIN
      docs/en/Blog-Posts/2020-01-15 v2_0_Release/abp-commercial-demo.png
  35. BIN
      docs/en/Blog-Posts/2020-01-15 v2_0_Release/abp-io-abpcommercial-release.png
  36. BIN
      docs/en/Blog-Posts/2020-01-15 v2_0_Release/lepton-theme-material.png
  37. BIN
      docs/en/Blog-Posts/2020-01-15 v2_0_Release/ndc-2020-volosoft-booth-wall.png
  38. BIN
      docs/en/Blog-Posts/2020-01-15 v2_0_Release/ndc-london-volosoft.png
  39. 26
      docs/en/Caching.md
  40. 3
      docs/en/Clock.md
  41. 91
      docs/en/Connection-Strings.md
  42. 29
      docs/en/Contribution/Localization-Text-Files.md
  43. 8
      docs/en/Data-Access.md
  44. 18
      docs/en/Dependency-Injection.md
  45. 173
      docs/en/Entities.md
  46. 49
      docs/en/Entity-Framework-Core-MySQL.md
  47. 90
      docs/en/Entity-Framework-Core-Other-DBMS.md
  48. 74
      docs/en/Entity-Framework-Core-PostgreSQL.md
  49. 41
      docs/en/Entity-Framework-Core-SQLite.md
  50. 4
      docs/en/Entity-Framework-Core.md
  51. 3
      docs/en/Features.md
  52. 58
      docs/en/FluentValidation.md
  53. 6
      docs/en/Logging.md
  54. 7
      docs/en/Modules/Audit-Logging.md
  55. 3
      docs/en/Modules/Blogging.md
  56. 22
      docs/en/Modules/Docs.md
  57. 3
      docs/en/Modules/Feature-Management.md
  58. 3
      docs/en/Modules/IdentityServer.md
  59. 23
      docs/en/Modules/Index.md
  60. 4
      docs/en/Modules/Setting-Management.md
  61. 8
      docs/en/Multi-Tenancy.md
  62. 116
      docs/en/Options.md
  63. 1
      docs/en/Repositories.md
  64. 2
      docs/en/Tutorials/Angular/Part-I.md
  65. 18
      docs/en/Tutorials/AspNetCore-Mvc/Part-I.md
  66. 3
      docs/en/Tutorials/AspNetCore-Mvc/Part-II.md
  67. 18
      docs/en/Tutorials/AspNetCore-Mvc/Part-III.md
  68. 159
      docs/en/Validation.md
  69. 3
      docs/en/Virtual-File-System.md
  70. 77
      docs/en/docs-nav.json
  71. BIN
      docs/en/images/auditlog-object-diagram.png
  72. 3
      docs/pt-BR/Tutorials/AspNetCore-Mvc/Part-II.md
  73. 3
      docs/zh-Hans/Ambient-Context-Pattern.md
  74. 375
      docs/zh-Hans/Audit-Logging.md
  75. 44
      docs/zh-Hans/Background-Jobs-Hangfire.md
  76. 8
      docs/zh-Hans/Background-Jobs.md
  77. 12
      docs/zh-Hans/Blog-Posts/2019-02-22/Post.md
  78. 164
      docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/Post.md
  79. BIN
      docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/abp-commercial-demo.png
  80. BIN
      docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/lepton-theme-material.png
  81. BIN
      docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/ndc-2020-volosoft-booth-wall.png
  82. BIN
      docs/zh-Hans/Blog-Posts/2020-01-15 v2_0_Release/ndc-london-volosoft.png
  83. 26
      docs/zh-Hans/Caching.md
  84. 80
      docs/zh-Hans/Connection-Strings.md
  85. 29
      docs/zh-Hans/Contribution/Localization-Text-Files.md
  86. 2
      docs/zh-Hans/Dependency-Injection.md
  87. 58
      docs/zh-Hans/Entity-Framework-Core-MySQL.md
  88. 90
      docs/zh-Hans/Entity-Framework-Core-Other-DBMS.md
  89. 52
      docs/zh-Hans/Entity-Framework-Core-PostgreSQL.md
  90. 41
      docs/zh-Hans/Entity-Framework-Core-SQLite.md
  91. 58
      docs/zh-Hans/Entity-Framework-Core.md
  92. 59
      docs/zh-Hans/FluentValidation.md
  93. 2
      docs/zh-Hans/Getting-Started-AspNetCore-MVC-Template.md
  94. 5
      docs/zh-Hans/Logging.md
  95. 2
      docs/zh-Hans/Microservice-Architecture.md
  96. 7
      docs/zh-Hans/Modules/Audit-Logging.md
  97. 146
      docs/zh-Hans/Modules/Docs.md
  98. 18
      docs/zh-Hans/Modules/Index.md
  99. 87
      docs/zh-Hans/Modules/Setting-Management.md
  100. 8
      docs/zh-Hans/Multi-Tenancy.md

4
README.md

@ -3,7 +3,7 @@
[![Build Status](http://vjenkins.dynu.net:5480/job/abp/badge/icon)](http://ci.volosoft.com:5480/blue/organizations/jenkins/abp/activity)
[![NuGet](https://img.shields.io/nuget/v/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core)
[![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core)
[![MyGet (with prereleases)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.Core.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds)
[![MyGet (with prereleases)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds)
This project is the next generation of the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) web application framework. See [the announcement](https://blog.abp.io/abp/Abp-vNext-Announcement).
@ -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

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>

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": "商業版支援網站"
}
}

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

@ -1,6 +1,8 @@
{
"culture": "en",
"texts": {
"Permission:Organizations": "Organizations",
"Permission:Manage": "Manage Organizations",
"Permission:NpmPackages": "NPM Packages",
"Permission:NugetPackages": "Nuget Packages",
"Permission:Maintenance": "Maintenance",
@ -11,6 +13,7 @@
"Permission:Edit": "Edit",
"Permission:Delete": "Delete",
"Permission:Create": "Create",
"Menu:Organizations": "Organizations",
"Menu:Packages": "Packages",
"NpmPackageDeletionWarningMessage": "This NPM Package will be deleted. Do you confirm that?",
"NugetPackageDeletionWarningMessage": "This Nuget Package will be deleted. Do you confirm that?",
@ -34,7 +37,7 @@
"NugetPackageTarget.HttpApi": "Http Api",
"NugetPackageTarget.HttpApiClient": "Http Api Client",
"NugetPackageTarget.Web": "Web",
"NugetPackageTarget.EntityFrameworkCore": "EntityFramework Core",
"NugetPackageTarget.EntityFrameworkCore": "DeleteAllEntityFramework Core",
"NugetPackageTarget.MongoDB": "MongoDB",
"Edit": "Edit",
"Delete": "Delete",
@ -55,6 +58,31 @@
"Menu:NpmPackages": "NPM Packages",
"Menu:Modules": "Modules",
"Menu:Maintenance": "Maintenance",
"Menu:NugetPackages": "Nuget Packages"
"Menu:NugetPackages": "Nuget Packages",
"CreateAnOrganization": "Create an organization",
"Organizations": "Organizations",
"LongName": "Long name",
"LicenseType": "License type",
"LicenseStartTime": "License start time",
"LicenseEndTime": "License end time",
"AllowedDeveloperCount": "Allowed developer count",
"UserNameOrEmailAddress": "Username or email address",
"AddOwner": "Add owner",
"UserName": "Username",
"Email": "Email",
"Developers": "Developers",
"AddDeveloper": "Add developer",
"Create": "Create",
"UserNotFound": "User not found",
"{0}WillBeRemovedFromMembers": "{0} Will be removed from members",
"Computers": "Computers",
"UniqueComputerId": "Unique computer id",
"LastSeenDate": "Last seen date",
"{0}Computer{1}WillBeRemovedFromRecords": "Computer of {0} ({1}) will be removed from records",
"OrganizationDeletionWarningMessage": "Organization will be deleted",
"This{0}AlreadyExistInThisOrganization": "This {0} already exist in this organization",
"AreYouSureYouWantToDeleteAllComputers": "Are you sure you want to delete all computers?",
"DeleteAll": "Delete all",
"DoYouWantToCreateNewUser": "Do you want to create new user?"
}
}

29
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hans.json

@ -1,6 +1,8 @@
{
"culture": "zh-Hans",
"texts": {
"Permission:Organizations": "组织",
"Permission:Manage": "管理组织",
"Permission:NpmPackages": "NPM包",
"Permission:NugetPackages": "Nuget包",
"Permission:Maintenance": "维护",
@ -11,6 +13,7 @@
"Permission:Edit": "编辑",
"Permission:Delete": "删除",
"Permission:Create": "创建",
"Menu:Organizations": "组织",
"Menu:Packages": "包",
"NpmPackageDeletionWarningMessage": "该NPM包将会被删除. 你确定吗?",
"NugetPackageDeletionWarningMessage": "该Nuget包将会被删除. 你确定吗?",
@ -55,6 +58,30 @@
"Menu:NpmPackages": "NPM包",
"Menu:Modules": "模块",
"Menu:Maintenance": "维护",
"Menu:NugetPackages": "Nuget包"
"Menu:NugetPackages": "Nuget包",
"CreateAnOrganization": "创建新组织",
"Organizations": "组织",
"LongName": "完整名称",
"LicenseType": "授权类型",
"LicenseStartTime": "授权开始时间",
"LicenseEndTime": "授权结束时间",
"AllowedDeveloperCount": "允许的开发人员数量",
"UserNameOrEmailAddress": "用户名或电子邮件地址",
"AddOwner": "添加所有者",
"UserName": "用户名",
"Email": "电子邮件地址",
"Developers": "开发者",
"AddDeveloper": "添加开发者",
"Create": "创建",
"UserNotFound": "用户不存在",
"{0}WillBeRemovedFromMembers": "{0} 将从成员中删除",
"Computers": "计算机",
"UniqueComputerId": "计算机唯一ID",
"LastSeenDate": "上次查看日期",
"{0}Computer{1}WillBeRemovedFromRecords": "计算机 {0} ({1}) 将从记录中删除",
"OrganizationDeletionWarningMessage": "组织将被删除",
"This{0}AlreadyExistInThisOrganization": "该组织中已经存在此 {0}",
"AreYouSureYouWantToDeleteAllComputers": "您确定要删除所有计算机吗?",
"DeleteAll": "删除所有"
}
}

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": {
}
}

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

@ -6,6 +6,7 @@
"Volo.AbpIo.Commercial:010003": "You are not owner of this organization!",
"OrganizationNotFoundMessage": "No organization found!",
"DeveloperCount": "Developer count",
"QuestionCount": "Question count",
"Owners": "Owners",
"AddMember": "Add member",
"AddOwner": "Add owner",
@ -26,6 +27,8 @@
"MyOrganizations": "My organizations",
"ApiKey": "API key",
"UserNameNotFound": "There is no user with username {0}",
"SuccessfullyAddedToNewsletter": "Thanks you for subscribing to our newsletter!"
"SuccessfullyAddedToNewsletter": "Thanks you for subscribing to our newsletter!",
"ManageProfile": "Manage your profile",
"EmailNotValid": "Please enter a valid email address."
}
}

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>2.0.0</Version>
<Version>2.1.0</Version>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>https://abp.io</PackageProjectUrl>

9
configureawait.props

@ -0,0 +1,9 @@
<Project>
<ItemGroup>
<PackageReference Include="ConfigureAwait.Fody" Version="3.3.1" />
<PackageReference Include="Fody" Version="6.0.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

18
docs/cs/CLI.md

@ -129,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.

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

@ -1,74 +1,39 @@
## Entity Framework Core PostgreSQL integrace
# Přepnutí na EF Core PostgreSQL providera
> Podívejte se na [Entity Framework Core integrační dokument](../Entity-Framework-Core.md) pro základy integrace EF Core.
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.
### Aktualizace projektu EntityFrameworkCore
## Výměna balíku Volo.Abp.EntityFrameworkCore.SqlServer
- 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
- Více informací v [PostgreSQL connection strings](https://www.connectionstrings.com/postgresql/), v tomto dokumentu věnujte pozornost sekci `Npgsql`
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).
### Aktualizace projektu EntityFrameworkCore.DbMigrations
- Aktualizace pro použití PostgreSQL v `XXXMigrationsDbContextFactory`
- Nahraďte `new DbContextOptionsBuilder<XXXMigrationsDbContext>().UseSqlServer()` za `new DbContextOptionsBuilder<XXXMigrationsDbContext>().UseNpgsql()`
## 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;`).
### Odstranění stávajících migrací
## UsePostgreSql()
Smažte všechny stavající migrační soubory (včetně `DbContextModelSnapshot`)
Najděte volání `UseSqlServer()` v *YourProjectName*EntityFrameworkCoreModule.cs uvnitř projektu `.EntityFrameworkCore` a nahraďte za `UsePostgreSql()`.
![postgresql-delete-initial-migrations](images/postgresql-delete-initial-migrations.png)
Najděte volání `UseSqlServer()` v *YourProjectName*MigrationsDbContextFactory.cs uvnitř projektu `.EntityFrameworkCore.DbMigrations` a nahraďte za `UseNpgsql()`.
### Znovu vygenerujte počáteční migraci
> V závislosti na struktuře řešení můžete najít více volání `UseSqlServer()`, které je třeba změnit.
Nastavte správný spouštěcí projekt (obvykle web projekt)
## Změna connection stringů
![set-as-startup-project](../images/set-as-startup-project.png)
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ů.
Otevřete **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), zvolte `.EntityFrameworkCore.DbMigrations` jako **Default project** a proveďte následující příkaz:
Typicky je potřeba změnit `appsettings.json` v projektech `.DbMigrator` a `.Web` projects, ale to záleží na vaší struktuře řešení.
Proveďte příkaz `Add-Migration`:
````
PM> Add-Migration Initial
````
## Regenerace migrací
### Aktualizace databáze
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).
K vytvoření databáze máte dvě možnosti.
Tímto vytvoříte migraci databáze se všemi nakonfigurovanými databázovými objekty (tabulkami).
#### Použití DbMigrator aplikace
Spusťte projekt `.DbMigrator` k vytvoření databáze a vložení počátečních dat.
Řešení obsahuje konzolovou aplikaci (v tomto příkladu nazvanou `Acme.BookStore.DbMigrator`), která může vytvářet databáze, aplikovat migrace a vkládat seed data. Je užitečná jak pro vývojové, tak pro produkční prostředí.
## Spuštění aplikace
> Projekt `.DbMigrator` má vlastní `appsettings.json`. Takže pokud jste změnili connection string uvedený výše, musíte změnit také tento.
Klikněte pravým na projekt `.DbMigrator` a vyberte **Set as StartUp Project**:
![set-as-startup-project](images/set-as-startup-project.png)
Zmáčkněte F5 (nebo Ctrl+F5) ke spuštění aplikace. Výstup bude vypadat následovně:
![set-as-startup-project](images/db-migrator-app.png)
#### Použití EF Core Update-Database příkazu
Ef Core má `Update-Database` příkaz, který v případě potřeby vytvoří databázi a aplikuje čekající migrace.
Nastavte správný spouštěcí projekt (obvykle web projekt)
![set-as-startup-project](../images/set-as-startup-project.png)
Otevřete **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), vyberte projekt `.EntityFrameworkCore.DbMigrations` jako **Default Project** and spusťte následující příkaz:
````
PM> Update-Database
````
Dojde k vytvoření nové databáze na základě nakonfigurovaného connection stringu.
![postgresql-update-database](images/postgresql-update-database.png)
> Použití nástroje `.DbMigrator` je doporučený způsob, jelikož zároveň vloží seed data nutné k správnému běhu webové aplikace.
Vše je připraveno. Stačí už jen spustit aplikaci a užívat si kódování.

59
docs/cs/docs-nav.json

@ -60,6 +60,10 @@
"text": "Konfigurace",
"path": "Configuration.md"
},
{
"text": "Možnosti",
"path": "Options.md"
},
{
"text": "Vkládání závislostí",
"path": "Dependency-Injection.md",
@ -83,7 +87,14 @@
"path": "Exception-Handling.md"
},
{
"text": "Validace"
"text": "Validace",
"path": "Validation.md",
"items": [
{
"text": "FluentValidation integrace",
"path": "FluentValidation.md"
}
]
},
{
"text": "Autorizace",
@ -257,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": "Entity-Framework-Core-PostgreSQL.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/docs-section-ui.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

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

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

734
docs/en/AspNet-Boilerplate-Migration-Guide.md

@ -0,0 +1,734 @@
# ASP.NET Boilerplate v5+ to ABP Framework Migration
ABP Framework is **the successor** of the open source [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework. This guide aims to help you to **migrate your existing solutions** (you developed with the ASP.NET Boilerplate framework) to the ABP Framework.
## Introduction
**ASP.NET Boilerplate** is being **actively developed** [since 2013](https://github.com/aspnetboilerplate/aspnetboilerplate/graphs/contributors). It is loved, used and contributed by the community. It started as a side project of [a developer](http://halilibrahimkalkan.com/), but now it is officially maintained and improved by the company [Volosoft](https://volosoft.com/) in addition to the great community support.
ABP Framework has the same goal of the ASP.NET Boilerplate framework: **Don't Repeat Yourself**! It provides infrastructure, tools and startup templates to make a developer's life easier while developing enterprise software solutions.
See [the introduction blog post](https://blog.abp.io/abp/Abp-vNext-Announcement) if you wonder why we needed to re-write the ASP.NET Boilerplate framework.
### Should I Migrate?
No, you don't have to!
* ASP.NET Boilerplate is still in active development and maintenance.
* It also works on the latest ASP.NET Core and related libraries and tools. It is up to date.
However, if you want to take the advantage of the new ABP Framework [features](https://abp.io/features) and the new architecture opportunities (like support for NoSQL databases, microservice compatibility, advanced modularity), you can use this document as a guide.
### What About the ASP.NET Zero?
[ASP.NET Zero](https://aspnetzero.com/) is a commercial product developed by the core ASP.NET Boilerplate team, on top of the ASP.NET Boilerplate framework. It provides pre-built application [features](https://aspnetzero.com/Features), code generation tooling and a nice looking modern UI. It is trusted and used by thousands of companies from all around the World.
We have created the [ABP Commercial](https://commercial.abp.io/) as an alternative to the ASP.NET Zero. ABP Commercial is more modular and upgradeable compared to the ASP.NET Zero. It currently has less features compared to ASP.NET Zero, but the gap will be closed by the time (it also has some features don't exist in the ASP.NET Zero).
We think ASP.NET Zero is still a good choice while starting a new application. It is production ready and mature solution delivered as a full source code. It is being actively developed and we are constantly adding new features.
We don't suggest to migrate your ASP.NET Zero based solution to the ABP Commercial if;
* Your ASP.NET Zero solution is mature and it is in maintenance rather than a rapid development.
* You don't have enough development time to perform the migration.
* A monolithic solution fits in your business.
* You've customized existing ASP.NET Zero features too much based on your requirements.
We also suggest you to compare the features of two products based on your needs.
If you have an ASP.NET Zero based solution and want to migrate to the ABP Commercial, this guide will also help you.
### ASP.NET MVC 5.x Projects
The ABP Framework doesn't support ASP.NET MVC 5.x, it only works with ASP.NET Core. So, if you migrate your ASP.NET MVC 5.x based projects, you will also deal with the .NET Core migration.
## The Migration Progress
We've designed the ABP Framework by **getting the best parts** of the ASP.NET Boilerplate framework, so it will be familiar to you if you've developed ASP.NET Boilerplate based applications.
In the ASP.NET Boilerplate, we have not worked much on the UI side, but used some free themes (we've used [metronic theme](https://keenthemes.com/metronic/) for ASP.NET Zero on the other side). In the ABP Framework, we worked a lot on the UI side (especially for the MVC / Razor Pages UI, because Angular already has a good modular system of its own). So, the **most challenging part** of the migration will be the **User Interface** of your solution.
ABP Framework is (and ASP.NET Boilerplate was) designed based on the [Domain Driven Design](https://docs.abp.io/en/abp/latest/Domain-Driven-Design) patterns & principles and the startup templates are layered based on the DDD layers. So, this guide respects to that layering model and explains the migration layer by layer.
## Creating the Solution
First step of the migration is to create a new solution. We suggest you to create a fresh new project using [the startup templates](https://abp.io/get-started) (see [this document](https://docs.abp.io/en/commercial/latest/getting-started) for the ABP Commercial).
After creating the project and running the application, you can copy your code from your existing solution to the new solution step by step, layer by layer.
### About Pre-Built Modules
The startup projects for the ABP Framework use the [pre-built modules](https://docs.abp.io/en/abp/latest/Modules/Index) (not all of them, but the essentials) and themes as NuGet/NPM packages. So, you don't see the source code of the modules/themes in your solution. This has an advantage that you can easily update these packages when a new version is released. However, you can not easily customize them as their source code in your hands.
We suggest to continue to use these modules as package references, in this way you can get new features easily (see [abp update command](https://docs.abp.io/en/abp/latest/CLI#update)). In this case, you have a few options to customize or extend the functionality of the used modules;
* You can create your own entity and share the same database table with an entity in a used module. An example of this is the `AppUser` entity comes in the startup template.
* You can [replace](https://docs.abp.io/en/abp/latest/Dependency-Injection#replace-a-service) a domain service, application service, controller, page model or other types of services with your own implementation. We suggest you to inherit from the existing implementation and override the method you need.
* You can replace a `.cshtml` view, page, view component, partial view... with your own one using the [Virtual File System](https://docs.abp.io/en/abp/latest/Virtual-File-System).
* You can override javascript, css, image or any other type of static files using the [Virtual File System](https://docs.abp.io/en/abp/latest/Virtual-File-System).
More extend/customization options will be developed and documented by the time. However, if you need to fully change the module implementation, it is best to add the [source code](https://github.com/abpframework/abp/tree/dev/modules) of the related module into your own solution and remove the package dependencies.
The source code of the modules and the themes are [MIT](https://opensource.org/licenses/MIT) licensed, you can fully own and customize it without any limitation (for the ABP Commercial, you can download the source code of a [module](https://commercial.abp.io/modules)/[theme](https://commercial.abp.io/themes) if you have a [license](https://commercial.abp.io/pricing) type that includes the source code).
## The Domain Layer
Most of your domain layer code will remain same, while you need to perform some minor changes in your domain objects.
### Aggregate Roots & Entities
The ABP Framework and the ASP.NET Boilerplate both have the `IEntity` and `IEntity<T>` interfaces and `Entity` and `Entity<T>` base classes to define entities but they have some differences.
If you have an entity in the ASP.NET Boilerplate application like that:
````csharp
public class Person : Entity //Default PK is int for the ASP.NET Boilerplate
{
...
}
````
Then your primary key (the `Id` property in the base class) is `int` which is the **default primary key** (PK) type for the ASP.NET Boilerplate. If you want to set another type of PK, you need to explicitly declare it:
````csharp
public class Person : Entity<Guid> //Set explicit PK in the ASP.NET Boilerplate
{
...
}
````
ABP Framework behaves differently and expects to **always explicitly set** the PK type:
````csharp
public class Person : Entity<Guid> //Set explicit PK in the ASP.NET Boilerplate
{
...
}
````
`Id` property (and the corresponding PK in the database) will be `Guid` in this case.
#### Composite Primary Keys
ABP Framework also has a non-generic `Entity` base class, but this time it has no `Id` property. Its purpose is to allow you to create entities with composite PKs. See [the documentation](https://docs.abp.io/en/abp/latest/Entities#entities-with-composite-keys) to learn more about the composite PKs.
#### Aggregate Root
It is best practice now to use the `AggregateRoot` base class instead of `Entity` for aggregate root entities. See [the documentation](https://docs.abp.io/en/abp/latest/Entities#aggregateroot-class) to learn more about the aggregate roots.
In opposite to the ASP.NET Boilerplate, the ABP Framework creates default repositories (`IRepository<T>`) **only for the aggregate roots**. It doesn't create for other types derived from the `Entity`.
If you still want to create default repositories for all entity types, find the *YourProjectName*EntityFrameworkCoreModule class in your solution and change `options.AddDefaultRepositories()` to `options.AddDefaultRepositories(includeAllEntities: true)` (it may be already like that for the application startup template).
#### Migrating the Existing Entities
We suggest & use the GUID as the PK type for all the ABP Framework modules. However, you can continue to use your existing PK types to migrate your database tables easier.
The challenging part will be the primary keys of the ASP.NET Boilerplate related entities, like Users, Roles, Tenants, Settings... etc. Our suggestion is to copy data from existing database to the new database tables using a tool or in a manual way (be careful about the foreign key values).
#### Documentation
See the documentation for details on the entities:
* [ASP.NET Boilerplate - Entity documentation](https://aspnetboilerplate.com/Pages/Documents/Entities)
* [ABP Framework - Entity documentation](https://docs.abp.io/en/abp/latest/Entities)
### Repositories
> ABP Framework creates default repositories (`IRepository<T>`) **only for the aggregate roots**. It doesn't create for other types derived from the `Entity`. See the "Aggregate Root" section above for more information.
The ABP Framework and the ASP.NET Boilerplate both have the default generic repository system, but has some differences.
#### Injecting the Repositories
In the ASP.NET Boilerplate, there are two default repository interfaces you can directly inject and use:
* `IRepository<TEntity>` (e.g. `IRepository<Person>`) is used for entities with `int` primary key (PK) which is the default PK type.
* `IRepository<TEntity, TKey>` (e.g. `IRepository<Person, Guid>`) is used for entities with other types of PKs.
ABP Framework doesn't have a default PK type, so you need to **explicitly declare the PK type** of your entity, like `IRepository<Person, int>` or `IRepository<Person, Guid>`.
ABP Framework also has the `IRepository<TEntity>` (without PK), but it is mostly used when your entity has a composite PK (because this repository has no methods work with the `Id` property). See [the documentation](https://docs.abp.io/en/abp/latest/Entities#entities-with-composite-keys) to learn more about the **composite PKs**.
#### Restricted Repositories
ABP Framework additionally provides a few repository interfaces:
* `IBasicRepository<TEntity, TKey>` has the same methods with the `IRepository` except it doesn't have `IQueryable` support. It can be useful if you don't want to expose complex querying code to the application layer. In this case, you typically want to create custom repositories to encapsulate the querying logic. It is also useful for database providers those don't support `IQueryable`.
* `IReadOnlyRepository<TEntity,TKey>` has the methods get data from the database, but doesn't contain any method change the database.
* `IReadOnlyBasicRepository<TEntity, TKey>` is similar to the read only repository but also doesn't support `IQueryable`.
All the interfaces also have versions without `TKey` (like ``IReadOnlyRepository<TEntity>`) those can be used for composite PKs just like explained above.
#### GetAll() vs IQueryable
ASP.NET Boilerplate's repository has a `GetAll()` method that is used to obtain an `IQueryable` object to execute LINQ on it. An example application service calls the `GetAll()` method:
````csharp
public class PersonAppService : ApplicationService, IPersonAppService
{
private readonly IRepository<Person, Guid> _personRepository;
public PersonAppService(IRepository<Person, Guid> personRepository)
{
_personRepository = personRepository;
}
public async Task DoIt()
{
var people = await _personRepository
.GetAll() //GetAll() returns IQueryable
.Where(p => p.BirthYear > 2000) //Use LINQ extension methods
.ToListAsync();
}
}
````
ABP Framework's repository doesn't have this method. Instead, it implements the `IQueryable` itself. So, you can directly use LINQ on the repository:
````csharp
public class PersonAppService : ApplicationService, IPersonAppService
{
private readonly IRepository<Person, Guid> _personRepository;
public PersonAppService(IRepository<Person, Guid> personRepository)
{
_personRepository = personRepository;
}
public async Task DoIt()
{
var people = await _personRepository
.Where(p => p.BirthYear > 2000) //Use LINQ extension methods
.ToListAsync();
}
}
````
> Note that in order to use the async LINQ extension methods (like `ToListAsync` here), you may need to depend on the database provider (like EF Core) since these methods are defined in the database provider package, they are not standard LINQ methods.
#### FirstOrDefault(predicate), Single()... Methods
ABP Framework repository has not such methods get predicate (expression) since the repository itself is `IQueryable` and all these methods are already standard LINQ extension methods those can be directly used.
However, it provides the following methods those can be used to query a single entity by its Id:
* `FindAsync(id)` returns the entity or null if not found.
* `GetAsync(id)` method returns the entity or throws an `EntityNotFoundException` (which causes HTTP 404 status code) if not found.
#### Sync vs Async
ABP Framework repository has no sync methods (like `Insert`). All the methods are async (like `InsertAsync`). So, if your application has sync repository method usages, convert them to async versions.
In general, ABP Framework forces you to completely use async everywhere, because mixing async & sync methods is not a recommended approach.
#### Documentation
See the documentation for details on the repositories:
* [ASP.NET Boilerplate - Repository documentation](https://aspnetboilerplate.com/Pages/Documents/Repositories)
* [ABP Framework - Repository documentation](https://docs.abp.io/en/abp/latest/Repositories)
### Domain Services
Your domain service logic mostly remains same on the migration. ABP Framework also defines the base `DomainService` class and the `IDomainService` interface just works like the ASP.NET Boilerplate.
## The Application Layer
Your application service logic remains similar on the migration. ABP Framework also defines the base `ApplicationService` class and the `IApplicationService` interface just works like the ASP.NET Boilerplate, but there are some differences in details.
### Declarative Authorization
ASP.NET Boilerplate has `AbpAuthorize` and `AbpMvcAuthorize` attributes for declarative authorization. Example usage:
````csharp
[AbpAuthorize("MyUserDeletionPermissionName")]
public async Task DeleteUserAsync(...)
{
...
}
````
ABP Framework doesn't has such a custom attribute. It uses the standard `Authorize` attribute in all layers.
````csharp
[Authorize("MyUserDeletionPermissionName")]
public async Task DeleteUserAsync(...)
{
...
}
````
This is possible with the better integration to the Microsoft Authorization Extensions libraries. See the Authorization section below for more information about the authorization system.
### CrudAppService and AsyncCrudAppService Classes
ASP.NET Boilerplate has `CrudAppService` (with sync service methods) and `AsyncCrudAppService` (with async service methods) classes.
ABP Framework only has the `CrudAppService` which actually has only the async methods (instead of sync methods).
ABP Framework's `CrudAppService` method signatures are slightly different than the old one. For example, old update method signature was ` Task<TEntityDto> UpdateAsync(TUpdateInput input) ` while the new one is ` Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input) `. The main difference is that it gets the Id of the updating entity as a separate parameter instead of including in the input DTO.
### Data Transfer Objects (DTOs)
There are similar base DTO classes (like `EntityDto`) in the ABP Framework too. So, you can find the corresponding DTO base class if you need.
#### Validation
You can continue to use the data annotation attributes to validate your DTOs just like in the ASP.NET Boilerplate.
ABP Framework doesn't include the ` ICustomValidate ` that does exists in the ASP.NET Boilerplate. Instead, you should implement the standard `IValidatableObject` interface for your custom validation logic.
## The Infrastructure Layer
### Namespaces
ASP.NET Boilerplate uses the `Abp.*` namespaces while the ABP Framework uses the `Volo.Abp.*` namespaces for the framework and pre-built fundamental modules.
In addition, there are also some pre-built application modules (like docs and blog modules) those are using the `Volo.*` namespaces (like `Volo.Blogging.*` and `Volo.Docs.*`). We consider these modules as standalone open source products developed by Volosoft rather than add-ons or generic modules completing the ABP Framework and used in the applications. We've developed them as a module to make them re-usable as a part of a bigger solution.
### Module System
Both of the ASP.NET Boilerplate and the ABP Framework have the `AbpModule` while they are a bit different.
ASP.NET Boilerplate's `AbpModule` class has `PreInitialize`, `Initialize` and `PostInitialize` methods you can override and configure the framework and the depended modules. You can also register and resolve dependencies in these methods.
ABP Framework's `AbpModule` class has the `ConfigureServices` and `OnApplicationInitialization` methods (and their Pre and Post versions). It is similar to ASP.NET Core's Startup class. You configure other services and register dependencies in the `ConfigureServices`. However, you can now resolve dependencies in that point. You can resolve dependencies and configure the ASP.NET Core pipeline in the `OnApplicationInitialization` method while you can not register dependencies here. So, the new module classes separate dependency registration phase from dependency resolution phase since it follows the ASP.NET Core's approach.
### Dependency Injection
#### The DI Framework
ASP.NET Boilerplate is using the [Castle Windsor](http://www.castleproject.org/projects/windsor/) as the dependency injection framework. This is a fundamental dependency of the ASP.NET Boilerplate framework. We've got a lot of feedback to make the ASP.NET Boilerplate DI framework agnostic, but it was not so easy because of the design.
ABP Framework is dependency injection framework independent since it uses Microsoft's [Dependency Injection Extensions](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection) library as an abstraction. None of the ABP Framework or module packages depends on any specific library.
However, ABP Framework doesn't use the Microsoft's base DI library because it has some missing features ABP Framework needs to: Property Injection and Interception. All the startup templates and the samples are using the [Autofac](https://autofac.org/) as the DI library and it is the only [officially integrated](Autofac-Integration.md) library to the ABP Framework. We suggest you to use the Autofac with the ABP Framework if you have not a good reason. If you have a good reason, please create an [issue](https://github.com/abpframework/abp/issues/new) on GitHub to request it or just implement it and send a pull request :)
#### Registering the Dependencies
Registering the dependencies are similar and mostly handled by the framework conventionally (like repositories, application services, controllers... etc). Implement the same `ITransientDependency`, `ISingletonDependency` and `IScopedDependency` interfaces for the services not registered by conventions.
When you need to manually register dependencies, use the `context.Services` in the `ConfigureServices` method of your module. Example:
````csharp
public class BlogModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//Register an instance as singleton
context.Services.AddSingleton<TaxCalculator>(new TaxCalculator(taxRatio: 0.18));
//Register a factory method that resolves from IServiceProvider
context.Services.AddScoped<ITaxCalculator>(
sp => sp.GetRequiredService<TaxCalculator>()
);
}
}
````
See the ABP Framework [dependency injection document](https://docs.abp.io/en/abp/latest/Dependency-Injection) for details.
### Configuration vs Options System
ASP.NET Boilerplate has its own configuration system to configure the framework and the modules. For example, you could disable the audit logging in the `Initialize` method of your [module](https://aspnetboilerplate.com/Pages/Documents/Module-System):
````csharp
public override void Initialize()
{
Configuration.Auditing.IsEnabled = false;
}
````
ABP Framework uses [the options pattern](Options.md) to configure the framework and the modules. You typically configure the options in the `ConfigureServices` method of your [module](Module-Development-Basics.md):
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAuditingOptions>(options =>
{
options.IsEnabled = false;
});
}
````
Instead of a central configuration object, there are separated option classes for every module and feature those are defined in the related documents.
### IAbpSession vs ICurrentUser and ICurrentTenant
ASP.NET Boilerplate's `IAbpSession` service is used to obtain the current user and tenant information, like ` UserId ` and `TenantId`.
ABP Framework doesn't have the same service. Instead, use `ICurrentUser` and `ICurrentTenant` services. These services are defined as base properties in some common classes (like `ApplicationService` and `AbpController`), so you generally don't need to manually inject them. They also have much properties compared to the `IAbpSession`.
### Authorization
ABP Framework extends the [ASP.NET Core Authorization](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/introduction) by adding **permissions** as auto [policies](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies) and allowing the authorization system to be usable in the [application services](Application-Services.md) too.
#### AbpAutorize vs Autorize
Use the standard `[Autorize]` and `[AllowAnonymous]` attributes instead of ASP.NET Boilerplate's custom `[AbpAutorize]` and `[AbpAllowAnonymous]` attributes.
#### IPermissionChecker vs IAuthorizationService
Use the standard `IAuthorizationService` to check permissions instead of the ASP.NET Boilerplate's `IPermissionChecker` service. While `IPermissionChecker` also exists in the ABP Framework, it is used to explicitly use the permissions. Using `IAuthorizationService` is the recommended way since it covers other type of policy checks too.
#### AuthorizationProvider vs PermissionDefinitionProvider
You inherit from the `AuthorizationProvider` in the ASP.NET Boilerplate to define your permissions. ABP Framework replaces it by the `PermissionDefinitionProvider` base class. So, define your permissions by inheriting from the `PermissionDefinitionProvider` class.
### Unit of Work
Unit of work system has been designed to work seamlessly. For most of the cases, you don't need to change anything.
`UnitOfWork` attribute of the ABP Framework doesn't have the `ScopeOption` (type of `TransactionScopeOption`) property. Instead, use `IUnitOfWorkManager.Begin()` method with `requiresNew = true` to create an independent inner transaction in a transaction scope.
#### Data Filters
ASP.NET Boilerplate implements the data filtering system as a part of the unit of work. ABP Framework has a separate `IDataFilter` service.
See the [data filtering document](Data-Filtering.md) to learn how to enable/disable a filter.
See [the UOW documentation](Unit-Of-Work.md) for more about the UOW system.
### Multi-Tenancy
#### IMustHaveTenant & IMayHaveTenant vs IMultiTenant
ASP.NET Boilerplate defines `IMustHaveTenant` and `IMayHaveTenant` interfaces to implement them for your entities. In this way, your entities are automatically filtered according to the current tenant. Because of the design, there was a problem: You had to create a "Default" tenant in the database with "1" as the Id if you want to create a non multi-tenant application (this "Default" tenant was used as the single tenant).
ABP Framework has a single interface for multi-tenant entities: `IMultiTenant` which defines a nullable `TenantId` property of type `Guid`. If your application is not multi-tenant, then your entities will have null TenantId (instead of a default one).
On the migration, you need to change the TenantId field type and replace these interfaces with the `IMultiTenant`
#### Switch Between Tenants
In some cases you might need to switch to a tenant for a code scope and work with the tenant's data in this scope.
In ASP.NET Boilerplate, it is done using the `IUnitOfWorkManager` service:
````csharp
public async Task<List<Product>> GetProducts(int tenantId)
{
using (_unitOfWorkManager.Current.SetTenantId(tenantId))
{
return await _productRepository.GetAllListAsync();
}
}
````
In the ABP Framework it is done with the `ICurrentTenant` service:
````csharp
public async Task<List<Product>> GetProducts(Guid tenantId)
{
using (_currentTenant.Change(tenantId))
{
return await _productRepository.GetListAsync();
}
}
````
Pass `null` to the `Change` method to switch to the host side.
### Caching
ASP.NET Boilerplate has its [own distributed caching abstraction](https://aspnetboilerplate.com/Pages/Documents/Caching) which has in-memory and Redis implementations. You typically inject the `ICacheManager` service and use its `GetCache(...)` method to obtain a cache, then get and set objects in the cache.
ABP Framework uses and extends ASP.NET Core's [distributed caching abstraction](Caching.md). It defines the `IDistributedCache<T>` services to inject a cache and get/set objects.
### Logging
ASP.NET Boilerplate uses Castle Windsor's [logging facility](http://docs.castleproject.org/Windsor.Logging-Facility.ashx) as an abstraction and supports multiple logging providers including Log4Net (the default one comes with the startup projects) and Serilog. You typically property-inject the logger:
````csharp
using Castle.Core.Logging; //1: Import Logging namespace
public class TaskAppService : ITaskAppService
{
//2: Getting a logger using property injection
public ILogger Logger { get; set; }
public TaskAppService()
{
//3: Do not write logs if no Logger supplied.
Logger = NullLogger.Instance;
}
public void CreateTask(CreateTaskInput input)
{
//4: Write logs
Logger.Info("Creating a new task with description: " + input.Description);
//...
}
}
````
ABP Framework depends on Microsoft's [logging extensions](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging) library which is also an abstraction and there are many providers implement it. Startup templates are using the Serilog as the pre-configured logging libary while it is easy to change in your project. The usage pattern is similar:
````csharp
//1: Import the Logging namespaces
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
public class TaskAppService : ITaskAppService
{
//2: Getting a logger using property injection
public ILogger<TaskAppService> Logger { get; set; }
public TaskAppService()
{
//3: Do not write logs if no Logger supplied.
Logger = NullLogger<TaskAppService>.Instance;
}
public void CreateTask(CreateTaskInput input)
{
//4: Write logs
Logger.Info("Creating a new task with description: " + input.Description);
//...
}
}
````
You inject the `ILogger<T>` instead of the `ILogger`.
### Object to Object Mapping
#### IObjectMapper Service
ASP.NET Boilerplate defines an `IObjectMapper` service ([see](https://aspnetboilerplate.com/Pages/Documents/Object-To-Object-Mapping)) and has an integration to the [AutoMapper](https://automapper.org/) library.
Example usage: Create a `User` object with the given `CreateUserInput` object:
````csharp
public void CreateUser(CreateUserInput input)
{
var user = ObjectMapper.Map<User>(input);
...
}
````
Example: Update an existing `User` properties with the given `UpdateUserInput` object:
````csharp
public async Task UpdateUserAsync(Guid id, UpdateUserInput input)
{
var user = await _userRepository.GetAsync(id);
ObjectMapper.Map(input, user);
}
````
ABP Framework has the same `IObjectMapper` service ([see](Object-To-Object-Mapping.md)) and the AutoMapper integration with a slightly different mapping methods.
Example usage: Create a `User` object with the given `CreateUserInput` object:
````csharp
public void CreateUser(CreateUserInput input)
{
var user = ObjectMapper.Map<CreateUserInput, User>(input);
}
````
This time you need to explicitly declare the source type and target type (while ASP.NET Boilerplate was requiring only the target type).
Example: Update an existing `User` properties with the given `UpdateUserInput` object:
````csharp
public async Task UpdateUserAsync(Guid id, UpdateUserInput input)
{
var user = await _userRepository.GetAsync(id);
ObjectMapper.Map<UpdateUserInput, User>(input, user);
}
````
Again, ABP Framework expects to explicitly set the source and target types.
#### AutoMapper Integration
##### Auto Mapping Attributes
ASP.NET Boilerplate has `AutoMapTo`, `AutoMapFrom` and `AutoMap` attributes to automatically create mappings for the declared types. Example:
````csharp
[AutoMapTo(typeof(User))]
public class CreateUserInput
{
public string Name { get; set; }
public string Surname { get; set; }
...
}
````
ABP Framework has no such attributes, because AutoMapper as a [similar attribute](https://automapper.readthedocs.io/en/latest/Attribute-mapping.html) now. You need to switch to AutoMapper's attribute.
##### Mapping Definitions
ABP Framework follows AutoMapper principles closely. You can define classes derived from the `Profile` class to define your mappings.
##### Configuration Validation
Configuration validation is a best practice for the AutoMapper to maintain your mapping configuration in a safe way.
See [the documentation](Object-To-Object-Mapping.md) for more information related to the object mapping.
### Setting Management
#### Defining the Settings
In an ASP.NET Boilerplate based application, you create a class deriving from the `SettingProvider` class, implement the `GetSettingDefinitions` method and add your class to the `Configuration.Settings.Providers` list.
In the ABP Framework, you need to derive your class from the `SettingDefinitionProvider` and implement the `Define` method. You don't need to register your class since the ABP Framework automatically discovers it.
#### Getting the Setting Values
ASP.NET Boilerplate provides the `ISettingManager` to read the setting values in the server side and `abp.setting.get(...)` method in the JavaScript side.
ABP Framework has the `ISettingProvider` service to read the setting values in the server side and `abp.setting.get(...)` method in the JavaScript side.
#### Setting the Setting Values
For ASP.NET Boilerplate, you use the same `ISettingManager` service to change the setting values.
ABP Framework separates it and provides the setting management module (pre-added to the startup projects) which has the ` ISettingManager ` to change the setting values. This separation was introduced to support tiered deployment scenarios (where `ISettingProvider` can also work in the client application while `ISettingManager ` can also work in the server (API) side).
### Clock
ASP.NET Boilerplate has a static `Clock` service ([see](https://aspnetboilerplate.com/Pages/Documents/Timing)) which is used to abstract the `DateTime` kind, so you can easily switch between Local and UTC times. You don't inject it, but just use the `Clock.Now` static method to obtain the current time.
ABP Framework has the `IClock` service ([see](Clock.md)) which has a similar goal, but now you need to inject it whenever you need it.
### Event Bus
ASP.NET Boilerplate has an in-process event bus system. You typically inject the `IEventBus` (or use the static instance `EventBus.Default`) to trigger an event. It automatically triggers events for entity changes (like `EntityCreatingEventData` and `EntityUpdatedEventData`). You create a class by implementing the `IEventHandler<T>` interface.
ABP Framework separates the event bus into two services: `ILocalEventBus` and `IDistributedEventBus`.
The local event bus is similar to the event bus of the ASP.NET Boilerplate while the distributed event bus is new feature introduced in the ABP Framework.
So, to migrate your code;
* Use the `ILocalEventBus` instead of the `IEventBus`.
* Implement the `ILocalEventHandler` instead of the `IEventHandler`.
> Note that ABP Framework has also an `IEventBus` interface, but it does exists to be a common interface for the local and distributed event bus. It is not injected and directly used.
### Feature Management
Feature system is used in multi-tenant applications to define features of your application check if given feature is available for the current tenant.
#### Defining Features
In the ASP.NET Boilerplate ([see](https://aspnetboilerplate.com/Pages/Documents/Feature-Management)), you create a class inheriting from the `FeatureProvider`, override the `SetFeatures` method and add your class to the `Configuration.Features.Providers` list.
In the ABP Framework ([see](Features.md)), you derive your class from the `FeatureDefinitionProvider` and override the `Define` method. No need to add your class to the configuration, it is automatically discovered by the framework.
#### Checking Features
You can continue to use the `RequiresFeature` attribute and `IFeatureChecker` service to check if a feature is enabled for the current tenant.
#### Changing the Feature Values
In the ABP Framework you use the `IFeatureManager` to change a feature value for a tenant.
### Audit Logging
The ASP.NET Boilerplate ([see](https://aspnetboilerplate.com/Pages/Documents/Audit-Logging)) and the ABP Framework ([see](Audit-Logging.md)) has similar audit logging systems. ABP Framework requires to add `UseAuditing()` middleware to the ASP.NET Core pipeline, which is already added in the startup templates. So, most of the times it will be work out of the box.
### Localization
ASP.NET Boilerplate supports XML and JSON files to define the localization key-values for the UI ([see](https://aspnetboilerplate.com/Pages/Documents/Localization)). ABP Framework only supports the JSON formatter localization files ([see](Localization.md)). So, you need to convert your XML file to JSON.
The ASP.NET Boilerplate has its own the `ILocalizationManager` service to be injected and used for the localization in the server side.
The ABP Framework uses [Microsoft localization extension](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization) library, so it is completely integrated to ASP.NET Core. You use the `IStringLocalizer<T>` service to get a localized text. Example:
````csharp
public class MyService
{
private readonly IStringLocalizer<TestResource> _localizer;
public MyService(IStringLocalizer<TestResource> localizer)
{
_localizer = localizer;
}
public void Foo()
{
var str = _localizer["HelloWorld"]; //Get a localized text
}
}
````
So, you need to replace `ILocalizationManager` usage by the `IStringLocalizer`.
It also provides API used in the client side:
````js
var testResource = abp.localization.getResource('Test');
var str = testResource('HelloWorld');
````
It was like `abp.localization.localize(...)` in the ASP.NET Boilerplate.
### Navigation vs Menu
In ASP.NET you create a class deriving from the `NavigationProvider` to define your menu elements. Menu items has `requiredPermissionName` attributes to restrict access to a menu element. Menu items were static and your class is executed only one time.
Int the ABP Framework you need to create a class implements the `IMenuContributor` interface. Your class is executed whenever the menu needs to be rendered. So, you can conditionally add menu items.
As an example, this is the menu contributor of the tenant management module:
````csharp
public class AbpTenantManagementWebMainMenuContributor : IMenuContributor
{
public async Task ConfigureMenuAsync(MenuConfigurationContext context)
{
//Add items only to the main menu
if (context.Menu.Name != StandardMenus.Main)
{
return;
}
//Get the standard administration menu item
var administrationMenu = context.Menu.GetAdministration();
//Resolve some needed services from the DI container
var authorizationService = context.ServiceProvider
.GetRequiredService<IAuthorizationService>();
var l = context.ServiceProvider
.GetRequiredService<IStringLocalizer<AbpTenantManagementResource>>();
var tenantManagementMenuItem = new ApplicationMenuItem(
TenantManagementMenuNames.GroupName,
l["Menu:TenantManagement"],
icon: "fa fa-users");
administrationMenu.AddItem(tenantManagementMenuItem);
//Conditionally add the "Tenants" menu item based on the permission
if (await authorizationService
.IsGrantedAsync(TenantManagementPermissions.Tenants.Default))
{
tenantManagementMenuItem.AddItem(
new ApplicationMenuItem(
TenantManagementMenuNames.Tenants,
l["Tenants"],
url: "/TenantManagement/Tenants"));
}
}
}
````
So, you need to check permission using the `IAuthorizationService` if you want to show a menu item only when the user has the related permission.
> Navigation/Menu system is only for ASP.NET Core MVC / Razor Pages applications. Angular applications has a different system implemented in the startup templates.
## Missing Features
The following features are not present for the ABP Framework. Here, a list of some major missing features (and the related issue for that feature waiting on the ABP Framework GitHub repository):
* [Multi-Lingual Entities](https://aspnetboilerplate.com/Pages/Documents/Multi-Lingual-Entities) ([#1754](https://github.com/abpframework/abp/issues/1754))
* [Real time notification system](https://aspnetboilerplate.com/Pages/Documents/Notification-System) ([#633](https://github.com/abpframework/abp/issues/633))
* [NHibernate Integration](https://aspnetboilerplate.com/Pages/Documents/NHibernate-Integration) ([#339](https://github.com/abpframework/abp/issues/339)) - We don't intent to work on this, but any community contribution welcome.
Some of these features will eventually be implemented. However, you can implement them yourself if they are important for you. If you want, you can [contribute](Contribution/Index.md) to the framework, it is appreciated.

372
docs/en/Audit-Logging.md

@ -1,3 +1,373 @@
# 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.
* `AlwaysLogOnException` (default: `true`): If you set to true, it always saves the audit log on an exception/error case without checking other options (except `IsEnabled`, which completely disables the audit logging).
* `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...

8
docs/en/Background-Jobs.md

@ -108,7 +108,7 @@ Enqueue method gets some optional arguments to control the background job:
You may want to disable background job execution for your application. This is generally needed if you want to execute background jobs in another process and disable it for the current process.
Use `BackgroundJobOptions` to configure the job execution:
Use `AbpBackgroundJobOptions` to configure the job execution:
````csharp
[DependsOn(typeof(AbpBackgroundJobsModule))]
@ -116,7 +116,7 @@ public class MyModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<BackgroundJobOptions>(options =>
Configure<AbpBackgroundJobOptions>(options =>
{
options.IsJobExecutionEnabled = false; //Disables job execution
});
@ -140,7 +140,7 @@ ABP framework includes a simple `IBackgroundJobManager` implementation that;
### Configuration
Use `BackgroundJobWorkerOptions` in your [module class](Module-Development-Basics.md) to configure the default background job manager. The example below changes the timeout duration for background jobs:
Use `AbpBackgroundJobWorkerOptions` in your [module class](Module-Development-Basics.md) to configure the default background job manager. The example below changes the timeout duration for background jobs:
````csharp
[DependsOn(typeof(AbpBackgroundJobsModule))]
@ -148,7 +148,7 @@ public class MyModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<BackgroundJobWorkerOptions>(options =>
Configure<AbpBackgroundJobWorkerOptions>(options =>
{
options.DefaultTimeout = 864000; //10 days (as seconds)
});

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)

4
docs/en/Blog-Posts/2019-02-22/Post.md

@ -1,6 +1,6 @@
# Microservice Demo, Projects Status and Road Map
After [the first announcement](https://abp.io/blog/abp/Abp-vNext-Announcement) on the ABP vNext, we have a lot of improvements on the codebase (1100+ commits on the [GitHub repository](https://github.com/abpframework/abp)). We've created features, samples, documentation and much more. In this post, I want to inform you about some news and the status of the project.
After [the first announcement](https://blog.abp.io/Abp-vNext-Announcement) on the ABP vNext, we have a lot of improvements on the codebase (1100+ commits on the [GitHub repository](https://github.com/abpframework/abp)). We've created features, samples, documentation and much more. In this post, I want to inform you about some news and the status of the project.
## Microservice Demo Solution
@ -38,7 +38,7 @@ First release may not include a SPA template. However, we want to prepare a simp
## Chinese Web Site
There is a big ABP community in China. They have created a Chinese version of the abp.io web site: https://cn.abp.io/ They are keeping it up to date. Thanks to the Chinese developers and especially to [Liming Ma](https://github.com/maliming).
There is a big ABP community in China. They have created a Chinese version of the abp.io web site: https://abp.io/ They are keeping it up to date. Thanks to the Chinese developers and especially to [Liming Ma](https://github.com/maliming).
## NDC {London} 2019

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

26
docs/en/Caching.md

@ -2,6 +2,32 @@
ABP framework extends ASP.NET Core's distributed caching system.
## Volo.Abp.Caching Package
> This package is already installed by default with the startup template. So, most of the time, you don't need to install it manually.
Volo.Abp.Caching is the core package of the caching system. Install it to your project using the package manager console (PMC):
```
Install-Package Volo.Abp.Caching
```
Then you can add **AbpCachingModule** dependency to your module:
```c#
using Volo.Abp.Modularity;
using Volo.Abp.Caching;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpCachingModule))]
public class MyModule : AbpModule
{
//...
}
}
```
## `IDistributedCache` Interface
ASP.NET Core defines the `IDistributedCache` interface to get/set cache values. But it has some difficulties:

3
docs/en/Clock.md

@ -0,0 +1,3 @@
# Clock
TODO

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

8
docs/en/Data-Access.md

@ -1,9 +1,15 @@
# Data Access
## Database Providers
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/).)
* [MongoDB](MongoDB.md)
* [Dapper](Dapper.md)
More providers will be added in the future.
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)

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

@ -1,4 +1,4 @@
# Entity Framework Core MySQL Database Provider
# 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.
@ -10,8 +10,49 @@ This document explains how to switch to the **MySQL** database provider for **[t
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;`).
## Call UseMySQL
## UseMySQL()
Find `UseSqlServer()` calls in your solution, replace with `UseMySQL()`
Find `UseSqlServer()` calls in your solution, replace with `UseMySQL()`. Check the following files:
TODO
* *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.

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

@ -1,73 +1,41 @@
## Entity Framework Core PostgreSQL Integration
# Switch to EF Core PostgreSQL Provider
> See [Entity Framework Core Integration document](../Entity-Framework-Core.md) for the basics of the EF Core integration.
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.
### EntityFrameworkCore Project Update
## Replace the Volo.Abp.EntityFrameworkCore.SqlServer Package
- 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` 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.
### EntityFrameworkCore.DbMigrations Project Update
- Update to use PostgreSQL in `XXXMigrationsDbContextFactory`
- Replace the `new DbContextOptionsBuilder<XXXMigrationsDbContext>().UseSqlServer()` with the `new DbContextOptionsBuilder<XXXMigrationsDbContext>().UseNpgsql()`
## Replace the Module Dependency
### Delete Existing Migrations
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;`).
Delete all existing migration files (including `DbContextModelSnapshot`)
## UsePostgreSql()
![postgresql-delete-initial-migrations](images/postgresql-delete-initial-migrations.png)
Find `UseSqlServer()` call in *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project and replace with `UsePostgreSql()`.
### Regenerate Initial Migration
Set the correct startup project (usually a web project)
Find `UseSqlServer()` call in *YourProjectName*MigrationsDbContextFactory.cs inside the `.EntityFrameworkCore.DbMigrations` project and replace with `UseNpgsql()`.
![set-as-startup-project](../images/set-as-startup-project.png)
> Depending on your solution structure, you may find more `UseSqlServer()` calls that needs to be changed.
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:
## Change the Connection Strings
Run `Add-Migration` command.
````
PM> Add-Migration Initial
````
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.
### Update the Database
You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure.
You have two options to create the database.
## Re-Generate the Migrations
#### Using the DbMigrator Application
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.
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.
* 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).
> `.DbMigrator` project has its own `appsettings.json`. So, if you have changed the connection string above, you should also change this one.
This will create a database migration with all database objects (tables) configured.
Right click to the `.DbMigrator` project and select **Set as StartUp Project**:
Run the `.DbMigrator` project to create the database and seed the initial data.
![set-as-startup-project](../images/set-as-startup-project.png)
## Run the Application
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.
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.

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

@ -38,6 +38,8 @@ ABP framework provides integration packages for some common DBMSs to make the co
* [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
@ -191,7 +193,7 @@ public class BookRepository : EfCoreRepository<BookStoreDbContext, Book, Guid>,
public async Task DeleteBooksByType(BookType type)
{
await DbContext.Database.ExecuteSqlCommandAsync(
await DbContext.Database.ExecuteSqlRawAsync(
$"DELETE FROM Books WHERE Type = {(int)type}"
);
}

3
docs/en/Features.md

@ -0,0 +1,3 @@
# Features
TODO

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)

6
docs/en/Logging.md

@ -0,0 +1,6 @@
# 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

22
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], [ParametersDocumentName]) 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', N'')
```
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], [ParametersDocumentName]) 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, N'')
```
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.
@ -449,7 +447,7 @@ For example, [en/docs-params.json](https://github.com/abpio/abp-commercial-docs/
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):
For example [Getting-Started.md](https://github.com/abpio/abp-commercial-docs/blob/master/en/getting-started.md):
```
.....
@ -468,7 +466,7 @@ For example [Getting-Started.md](https://github.com/abpio/abp-commercial-docs/bl
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)
![Interface](../images/docs-section-ui.png)
Now you can use **Scriban** syntax to create sections in your document.
@ -501,6 +499,10 @@ 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

3
docs/en/Modules/Feature-Management.md

@ -0,0 +1,3 @@
# Feature Management Module
TODO

3
docs/en/Modules/IdentityServer.md

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

23
docs/en/Modules/Index.md

@ -11,16 +11,21 @@ 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.
* **Feature Management**: Used to persist and manage the [features](../Features.md).
* **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.

8
docs/en/Multi-Tenancy.md

@ -98,7 +98,7 @@ The first thing for a multi-tenant application is to determine the current tenan
##### Custom Tenant Resolvers
You can add your custom tenant resolver to **TenantResolveOptions** in your module's ConfigureServices method as like below:
You can add your custom tenant resolver to **AbpTenantResolveOptions** in your module's ConfigureServices method as like below:
````C#
using Microsoft.Extensions.DependencyInjection;
@ -112,7 +112,7 @@ namespace MyCompany.MyProject
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<TenantResolveOptions>(options =>
Configure<AbpTenantResolveOptions>(options =>
{
options.TenantResolvers.Add(new MyCustomTenantResolveContributor());
});
@ -323,7 +323,7 @@ services.Configure<AbpAspNetCoreMultiTenancyOptions>(options =>
##### Domain Tenant Resolver
In a real application, most of times you will want to determine current tenant either by subdomain (like mytenant1.mydomain.com) or by the whole domain (like mytenant.com). If so, you can configure TenantResolveOptions to add a domain tenant resolver.
In a real application, most of times you will want to determine current tenant either by subdomain (like mytenant1.mydomain.com) or by the whole domain (like mytenant.com). If so, you can configure AbpTenantResolveOptions to add a domain tenant resolver.
###### Example: Add a subdomain resolver
@ -340,7 +340,7 @@ namespace MyCompany.MyProject
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<TenantResolveOptions>(options =>
Configure<AbpTenantResolveOptions>(options =>
{
//Subdomain format: {0}.mydomain.com (adding as the highest priority resolver)
options.TenantResolvers.Insert(0, new DomainTenantResolver("{0}.mydomain.com"));

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)
{
//...
}
}
````

1
docs/en/Repositories.md

@ -52,7 +52,6 @@ Generic Repositories provides some standard CRUD features out of the box:
* Provides `Update` and `Delete` methods to update or delete an entity by entity object or it's id.
* Provides `Delete` method to delete multiple entities by a filter.
* Implements `IQueryable<TEntity>`, so you can use LINQ and extension methods like `FirstOrDefault`, `Where`, `OrderBy`, `ToList` and so on...
* Have **sync** and **async** versions for all methods.
### Basic Repositories

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';
//...
{

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

@ -50,6 +50,20 @@ namespace Acme.BookStore
public DateTime PublishDate { get; set; }
public float Price { get; set; }
protected Book()
{
}
public Book(Guid id, string name, BookType type, DateTime publishDate, float price)
:base(id)
{
Name = name;
Type = type;
PublishDate = publishDate;
Price = price;
}
}
}
````
@ -345,7 +359,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 +436,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.

18
docs/en/Tutorials/AspNetCore-Mvc/Part-III.md

@ -57,25 +57,11 @@ namespace Acme.BookStore
public async Task SeedAsync(DataSeedContext context)
{
await _bookRepository.InsertAsync(
new Book
{
Id = _guidGenerator.Create(),
Name = "Test book 1",
Type = BookType.Fantastic,
PublishDate = new DateTime(2015, 05, 24),
Price = 21
}
new Book(_guidGenerator.Create(), "Test book 1", BookType.Fantastic, new DateTime(2015, 05, 24), 21)
);
await _bookRepository.InsertAsync(
new Book
{
Id = _guidGenerator.Create(),
Name = "Test book 2",
Type = BookType.Science,
PublishDate = new DateTime(2014, 02, 11),
Price = 15
}
new Book(_guidGenerator.Create(), "Test book 2", BookType.Science, new DateTime(2014, 02, 11), 15)
);
}
}

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>
````

77
docs/en/docs-nav.json

@ -49,6 +49,10 @@
}
]
},
{
"text": "ASP.NET Boilerplate Migration Guide",
"path": "AspNet-Boilerplate-Migration-Guide.md"
},
{
"text": "CLI",
"path": "CLI.md"
@ -60,6 +64,10 @@
"text": "Configuration",
"path": "Configuration.md"
},
{
"text": "Options",
"path": "Options.md"
},
{
"text": "Dependency Injection",
"path": "Dependency-Injection.md",
@ -83,7 +91,14 @@
"path": "Exception-Handling.md"
},
{
"text": "Validation"
"text": "Validation",
"path": "Validation.md",
"items": [
{
"text": "FluentValidation Integration",
"path": "FluentValidation.md"
}
]
},
{
"text": "Authorization",
@ -94,11 +109,20 @@
"path": "Caching.md"
},
{
"text": "Auditing"
"text": "Logging",
"path": "Logging.md"
},
{
"text": "Audit Logging",
"path": "Audit-Logging.md"
},
{
"text": "Settings",
"path": "Settings.md"
},
{
"text": "Data Filtering",
"path": "Data-Filtering.md"
}
]
},
@ -257,25 +281,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": "PostgreSQL Integration",
"path": "Entity-Framework-Core-PostgreSQL.md"
"text": "MongoDB",
"path": "MongoDB.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

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"
```

3
docs/zh-Hans/Ambient-Context-Pattern.md

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

375
docs/zh-Hans/Audit-Logging.md

@ -0,0 +1,375 @@
# 审计日志
[维基百科](https://en.wikipedia.org/wiki/Audit_trail): "*审计跟踪(也称为**审计日志**)是一种安全相关的按时间顺序记录,记录集或记录目的和来源. 这种记录提供了在任何特定时间的操作,过程或事件产生影响活动顺序的文件证据* ".
ABP框架提供一个可扩展的**审计日志系统**,自动化的根据**约定**记录审计日志,并提供**配置**控制审计日志的级别.
一个**审计日志对象**(参见下面的审计日志对象部分)通常是针对每个web请求创建和保存的.包括;
* **请求和响应的细节** (如URL,HTTP方法,浏览器信息,HTTP状态代码...等).
* **执行的动作** (控制器操作和应用服务方法调用及其参数).
* **实体的变化** (在Web请求中).
* **异常信息** (如果在执行请求发生操作).
* **请求时长** (测量应用程序的性能).
> [启动模板](Startup-Templates/Index.md)已经将审计日志系统配置为适用于大多数应用程序. 本文档介绍了对审计日志系统更精细的控制.
## 数据库提供程序支持
* [Entity Framework Core](Entity-Framework-Core.md)提供程序完全支持.
* [MongoDB](MongoDB.md)提供程序不支持实体更改审计记录. 其他功能按预期工作.
## UseAuditing()
`UseAuditing()` 中间件应该被添加到ASP.NET Core请求管道,用于创建和保存审计日志. 如果你使用[启动模板](Startup-Templates/Index.md)创建的应用程序,它已经默认添加.
## AbpAuditingOptions
`AbpAuditingOptions` 是配置审计日志系统的主要[options对象](Options.md). 你可以在[模块](Module-Development-Basics.md)的 `ConfigureServices` 方法中进行配置:
````csharp
Configure<AbpAuditingOptions>(options =>
{
options.IsEnabled = false; //Disables the auditing system
});
````
这里是你可以配置的选项列表:
* `IsEnabled` (默认值: `true`): 启用或禁用审计系统的总开关. 如果值为 `false`,则不使用其他选项.
* `HideErrors` (默认值: `true`): 在保存审计日志对象时如果发生任何错误,审计日志系统会将错误隐藏并写入常规[日志](Logging.md). 如果保存审计日志对系统非常重要那么将其设置为 `false` 以便在隐藏错误时抛出异常.
* `IsEnabledForAnonymousUsers` (默认值: `true`): 如果只想为经过身份验证的用户记录审计日志,请设置为 `false`.如果为匿名用户保存审计日志,你将看到这些用户的 `UserId` 值为 `null`.
* `AlwaysLogOnException`(默认值: `true`): 如果设置为 `true`,将始终在异常/错误情况下保存审计日志,不检查其他选项(`IsEnabled` 除外,它完全禁用了审计日志).
* `IsEnabledForGetRequests` (默认值: `false`): HTTP GET请求通常不应该在数据库进行任何更改,审计日志系统不会为GET请求保存审计日志对象. 将此值设置为 `true` 可为GET请求启用审计日志系统.
* `ApplicationName`: 如果有多个应用程序保存审计日志到单一的数据库,使用此属性设置为你的应用程序名称区分不同的应用程序日志.
* `IgnoredTypes`: 审计日志系统忽略的 `Type` 列表. 如果它是实体类型,则不会保存此类型实体的更改. 在序列化操作参数时也使用此列表.
* `EntityHistorySelectors`:选择器列表,用于确定是否选择了用于保存实体更改的实体类型. 有关详细信息请参阅下面的部分.
* `Contributors`: `AuditLogContributor` 实现的列表. 贡献者是扩展审计日志系统的一种方式. 有关详细信息请参阅下面的"审计日志贡献者"部分.
### 实体历史选择器
保存您的所有实体的所有变化将需要大量的数据库空间. 出于这个原因**审计日志系统不保存为实体的任何改变,除非你明确地对其进行配置**.
要保存的所有实体的所有更改,只需使用 `AddAllEntities()` 扩展方法.
````csharp
Configure<AbpAuditingOptions>(options =>
{
options.EntityHistorySelectors.AddAllEntities();
});
````
`options.EntityHistorySelectors` 实际上是一个类型谓词的列表,你可以写一个lambda表达式定义过滤器.
下面的示例中与使用 `AddAllEntities()` 扩展方法效果相同:
````csharp
Configure<AbpAuditingOptions>(options =>
{
options.EntityHistorySelectors.Add(
new NamedTypeSelector(
"MySelectorName",
type =>
{
if (typeof(IEntity).IsAssignableFrom(type))
{
return true;
}
else
{
return false;
}
}
)
);
});
````
条件 `typeof(IEntity).IsAssignableFrom(type)` 对于任何实现 `IEntity` 接口的类(从技术上来这些都是你应用程序中的实体) 结果都为 `true` . 你可以根据自己的逻辑编写条件并返回 `true``false`.
`options.EntityHistorySelectors` 是一种灵活动态的选择实体进行审计日志记录的方法. 另一种方法是为每个实体使用 `Audited``DisableAuditing` attribute.
## 启用/禁用审计日志服务
### 启用/禁用 Controllers & Actions
默认所有的控制器动作都会被记录下来(有关GET请求,请参阅上面的 `IsEnabledForGetRequests` ).
你可以使用 `[DisableAuditing]` 来禁用特定的控制器:
````csharp
[DisableAuditing]
public class HomeController : AbpController
{
//...
}
````
使用 `[DisableAuditing]` 在action级别控制:
````csharp
public class HomeController : AbpController
{
[DisableAuditing]
public async Task<ActionResult> Home()
{
//...
}
public async Task<ActionResult> OtherActionLogged()
{
//...
}
}
````
### 启用/禁用 应用服务&方法
[应用服务](Application-Services.md)也默认包含在审计日志中. 你可在服务或方法级别使用 `[DisableAuditing]`
#### 启用/禁用 其他服务
可以为任何类型的类(注册到[依赖注入](Dependency-Injection.md)并从依赖注入解析)启用审计日志,默认情况下仅对控制器和应用程序服务启用.
对于任何需要被审计记录的类或方法都可以使用 `[Audited]` 和`IAuditingEnabled`.此外,您的类可以(直接或固有的)实现 `IAuditingEnabled` 接口以认启用该类的审计日志记录.
### 启用/禁用 实体 & 属性
以下情况下实体在实体更改审计日志记录中忽略实体;
* 如果将实体类型添加到 `AbpAuditingOptions.IgnoredTypes`(如前所述),它在审计日志系统中被完全忽略.
* 如果对象不是[实体](Entities.md)(没有直接或固有的实现 `IEntity` - 所有实体默认实现这个接口).
* 如果实体访问级别不是public的.
你可以使用 `Audited` 来启用实体更改审计日志:
````csharp
[Audited]
public class MyEntity : Entity<Guid>
{
//...
}
````
或者禁用实体:
````csharp
[DisableAuditing]
public class MyEntity : Entity<Guid>
{
//...
}
````
只有前面提到的 `AbpAuditingOptions.EntityHistorySelector` 选择实体时才有必要禁用审计日志记录.
你可以仅禁用实体的某些属性的审计,以审计日志记录进行精细控制:
````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; }
}
````
审计日志系统保存 `MyUser` 实体的更改,出于安全的目的忽略 `Password` 属性.
在某些情况下你可能要保存一些属性,但忽略所有其他属性. 为忽略的属性编写 `[DisableAuditing]` 将很乏味. 这种情况下将 `[Audited]` 用于所需的属性,使用 `[DisableAuditing]` 属性标记该实体:
````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` 是一个接口,用于保存ABP框架的审计日志对象(下面说明). 如果需要将审计日志对象保存到自定义数据存储中,可以在自己的应用程序中实现 `IAuditingStore` 并在[依赖注入系统](Dependency-Injection.md)替换.
如果没有注册审计存储,则使用 `SimpleLogAuditingStore`. 它只是将审计对象写入标准[日志系统](Logging.md).
[审计日志模块](Modules/Audit-Logging.md)已在[启动模板](Startup-Templates/Index.md)中配置,它将审计日志对象保存到数据库中(支持多个数据库提供程序). 所以大多数时候你并不需要关心 `IAuditingStore` 是如何实现和使用的.
## 审计日志对象
默认为每个**web请求**创建一个**审计日志对象**,审计日志对象可以由以下关系图表示:
![**auditlog-object-diagram**](images/auditlog-object-diagram.png)
* **AuditLogInfo**: 具有以下属性:
* `ApplicationName`: 当你保存不同的应用审计日志到同一个数据库,这个属性用来区分应用程序.
* `UserId`:当前用户的Id,用户未登录为 `null`.
* `UserName`:当前用户的用户名,如果用户已经登录(这里的值不依赖于标识模块/系统进行查找).
* `TenantId`: 当前租户的Id,对于多租户应用.
* `TenantName`: 当前租户的名称,对于多租户应用.
* `ExecutionTime`: 审计日志对象创建的时间.
* `ExecutionDuration`: 请求的总执行时间,以毫秒为单位. 可以用来观察应用程序的性能.
* `ClientId`: 当前客户端的Id,如果客户端已经通过认证.客户端通常是使用HTTP API的第三方应用程序.
* `ClientName`: 当前客户端的名称,如果有的话.
* `ClientIpAddress`: 客户端/用户设备的IP地址.
* `CorrelationId`: 当前[相关Id](CorrelationId.md). 相关Id用于在单个逻辑操作中关联由不同应用程序(或微服务)写入的审计日志.
* `BrowserInfo`: 当前用户的浏览器名称/版本信息,如果有的话.
* `HttpMethod`: 当前HTTP请求的方法(GET,POST,PUT,DELETE ...等).
* `HttpStatusCode`: HTTP响应状态码.
* `Url`: 请求的URL.
* **AuditLogActionInfo**: 一个 审计日志动作通常是web请求期间控制器动作或[应用服务](Application-Services.md)方法调用. 一个审计日志可以包含多个动作. 动作对象具有以下属性:
* `ServiceName`:执行的控制器/服务的名称.
* `MethodName`:控制器/服务执行的方法的名称.
* `Parameters`:传递给方法的参数的JSON格文本.
* `ExecutionTime`: 执行的时间.
* `ExecutionDuration`: 方法执行时长,以毫秒为单位. 可以用来观察方法的性能.
* **EntityChangeInfo**: 表示一个实体在Web请求中的变更. 审计日志可以包含0个或多个实体的变更. 实体变更具有以下属性:
* `ChangeTime`: 当实体被改变的时间.
* `ChangeType`:具有以下字段的枚举: `Created`(0), `Updated`(1)和 `Deleted`(2).
* `EntityId`: 更改实体的Id.
* `EntityTenantId`:实体所属的租户Id.
* `EntityTypeFullName`: 实体的类型(类)的完整命名空间名称(例如Book实体的*Acme.BookStore.Book*.
* **EntityPropertyChangeInfo**: 表示一个实体的属性的更改.一个实体的更改信息(上面已说明)可含有具有以下属性的一个或多个属性的更改:
* `NewValue`: 属性的新值. 如果实体已被删除为 `null`.
* `OriginalValue`:变更前旧/初始值. 如果实体是新创建为 `null`.
* `PropertyName`: 实体类的属性名称.
* `PropertyTypeFullName`:属性类型的完整命名空间名称.
* **Exception**: 审计日志对象可能包含零个或多个异常. 可以得到失败请求的异常信息.
* **Comment**:用于将自定义消息添加到审计日志条目的任意字符串值. 审计日志对象可能包含零个或多个注释.
除了上面说明的标准属性之外,`AuditLogInfo`, `AuditLogActionInfo``EntityChangeInfo` 对象还实现了`IHasExtraProperties` 接口,你可以向这些对象添加自定义属性.
## 审计日志贡献者
你可以创建类继承 `AuditLogContributor`类 来扩展审计系统,该类定义了 `PreContribute``PostContribute` 方法.
唯一预构建的贡献者是 `AspNetCoreAuditLogContributor` 类,它设置HTTP请求的相关属性.
贡献者可以设置 `AuditLogInfo` 类的属性和集合来添加更多信息.
例:
````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` 可以从[依赖注入系统](Dependency-Injection.md)中解析服务.
* `context.AuditInfo` 可以用来访问当前审计日志的对象并进行操作.
创建贡献者后,需要将其添加到 `AbpAuditingOptions.Contributors` 列表中:
````csharp
Configure<AbpAuditingOptions>(options =>
{
options.Contributors.Add(new MyAuditLogContributor());
});
````
## IAuditLogScope & IAuditingManager
本节介绍用于高级用例的 `IAuditLogScope``IAuditingManager` 服务.
**审计日志范围**是**构建**和**保存**审计日志对象的[环境范围](Ambient-Context-Pattern.md)(前面解释过). 默认审计日志中间件会为Web请求创建审计日志范围(请参阅上面的 `UseAuditing()` 部分).
### 获取当前审计日志范围
上面提到,审计日志贡献者是操作审计日志对象的全局方法. 你可从服务中获得值.
如果需要在应用程序的任意位置上操作审计日志对象,可以访问当前审计日志范围并获取当前审计日志对象(与范围的管理方式无关).
例:
````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);
}
}
}
````
总是检查 `_auditingManager.Current` 是否为空,因为它是在外部范围中控制的,在调用方法之前你不知道是否创建了审计日志范围.
### 手动创建审计日志范围
你很少需要手动创建审计日志的范围,但如果你需要,可以使用 `IAuditingManager` 创建审计日志的范围.
例:
````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();
}
}
}
}
````
您可以调用其他服务,它们可能调用其他服务,它们可能更改实体,等等. 所有这些交互都保存为finally块中的一个审计日志对象.
## 审计日志模块
审计日志模块基本上实现了 `IAuditingStore`, 将审计日志对象保存到数据库中并支持多个数据库提供程序. 默认此模块已添加到启动模板中.
参见[审计日志模块文档](Modules/Audit-Logging.md)了解更多.

44
docs/zh-Hans/Background-Jobs-Hangfire.md

@ -1,3 +1,43 @@
# Hangfire Background Job Manager
# Hangfire后台作业管理
待添加
[Hangfire](https://www.hangfire.io/)是一个高级的后台作业管理. 你可以用ABP框架集成Hangfire代替[默认后台作业管理](Background-Jobs.md). 通过这种方式你可以使用相同的后台作业API,将你的代码独立于Hangfire. 如果你喜欢也可以直接使用Hangfire的API.
> 参阅[后台作业文档](Background-Jobs.md),学习如何使用后台作业系统. 本文只介绍了如何安装和配置Hangfire集成.
## 安装
建议使用[ABP CLI](CLI.md)安装包.
### 使用ABP CLI
在项目的文件夹(.csproj文件)中打开命令行窗口输入以下命令:
````bash
abp add-package Volo.Abp.BackgroundJobs.HangFire
````
### 手动安装
如果你想手动安装;
1. 添加 [Volo.Abp.BackgroundJobs.HangFire](https://www.nuget.org/packages/Volo.Abp.BackgroundJobs.HangFire) NuGet包添加到你的项目:
````
Install-Package Volo.Abp.BackgroundJobs.HangFire
````
2. 添加 `AbpBackgroundJobsHangfireModule` 到你的模块的依赖列表:
````csharp
[DependsOn(
//...other dependencies
typeof(AbpBackgroundJobsHangfireModule) //Add the new module dependency
)]
public class YourModule : AbpModule
{
}
````
## 配置
TODO...

8
docs/zh-Hans/Background-Jobs.md

@ -110,7 +110,7 @@ Enqueue方法接收一些可选参数用于控制后台作业:
你可能希望在你的应用程序中禁用后台作业执行. 如果你希望在另一个进程中执行后台作业并在当前进程中禁用它,通常可以使用以下命令.
使用 `BackgroundJobOptions` 配置作业执行:
使用 `AbpBackgroundJobOptions` 配置作业执行:
````csharp
[DependsOn(typeof(AbpBackgroundJobsModule))]
@ -118,7 +118,7 @@ public class MyModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<BackgroundJobOptions>(options =>
Configure<AbpBackgroundJobOptions>(options =>
{
options.IsJobExecutionEnabled = false; //禁用作业执行
});
@ -142,7 +142,7 @@ ABP framework 包含一个简单的 `IBackgroundJobManager` 实现;
### 配置
在你的[模块类](Module-Development-Basics.md)中使用 `BackgroundJobWorkerOptions` 配置默认作业管理器.
在你的[模块类](Module-Development-Basics.md)中使用 `AbpBackgroundJobWorkerOptions` 配置默认作业管理器.
示例中更改后台作业的的超时时间:
````csharp
@ -151,7 +151,7 @@ public class MyModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<BackgroundJobWorkerOptions>(options =>
Configure<AbpBackgroundJobWorkerOptions>(options =>
{
options.DefaultTimeout = 864000; //10 days (as seconds)
});

12
docs/zh-Hans/Blog-Posts/2019-02-22/Post.md

@ -1,12 +1,12 @@
# 微服务演示,项目状态和路线图
在ABP vNext上的[第一个公告](https://cn.abp.io/blog/abp/Abp-vNext-Announcement)之后,我们对代码库进行了很多改进([GitHub存储库](https://github.com/abpframework/abp)上的1100多次提交).我们已经创建了功能,示例,文档等等.在这篇文章中,我想告诉你一些新闻和项目的状态.
在ABP vNext上的[第一个公告](https://abp.io/blog/abp/Abp-vNext-Announcement)之后,我们对代码库进行了很多改进([GitHub存储库](https://github.com/abpframework/abp)上的1100多次提交).我们已经创建了功能,示例,文档等等.在这篇文章中,我想告诉你一些新闻和项目的状态.
## 微服务演示解决方案
ABP框架的主要目标之一是提供[创建微服务解决方案的便利基础设施](https://cn.abp.io/documents/abp/latest/Microservice-Architecture).
ABP框架的主要目标之一是提供[创建微服务解决方案的便利基础设施](https://abp.io/documents/abp/latest/Microservice-Architecture).
我们一直在努力开发微服务解决方案演示.初始版本已完成并[文档化](https://cn.abp.io/documents/abp/latest/Samples/Microservice-Demo).该示例解决方案旨在演示一个简单而完整的微服务解决方案;
我们一直在努力开发微服务解决方案演示.初始版本已完成并[文档化](https://abp.io/documents/abp/latest/Samples/Microservice-Demo).该示例解决方案旨在演示一个简单而完整的微服务解决方案;
- 具有多个独立的,可自我部署的**微服务**.
- 多个**Web应用程序**,每个都使用不同的API网关.
@ -20,7 +20,7 @@ ABP框架的主要目标之一是提供[创建微服务解决方案的便利基
- 使用[Docker](https://www.docker.com/)和[Kubernates](https://kubernetes.io/)**部署**并运行所有服务和应用程序.
- 使用[Elasticsearch](https://www.elastic.co/products/elasticsearch)和[Kibana](https://www.elastic.co/products/kibana)存储和可视化日志(使用[Serilog](https://serilog.net/)编写).
有关解决方案的详细说明,请参阅[其文档](https://cn.abp.io/documents/abp/latest/Samples/Microservice-Demo).
有关解决方案的详细说明,请参阅[其文档](https://abp.io/documents/abp/latest/Samples/Microservice-Demo).
## 改进/功能
@ -32,13 +32,13 @@ ABP框架的主要目标之一是提供[创建微服务解决方案的便利基
根据我们的估计,我们计划在2019年第二季度(可能在五月或六月)发布v1.0.所以,不用等待太长时间了.我们也对第一个稳定版本感到非常兴奋.
我们还将完善[文档](https://cn.abp.io/documents/abp/latest),因为它现在还远未完成.
我们还将完善[文档](https://abp.io/documents/abp/latest),因为它现在还远未完成.
第一个版本可能不包含SPA模板.但是,如果可能的话,我们想要准备一个简单些的.SPA框架还没有确定下来.备选有:**Angular,React和Blazor**.请将您的想法写为对此帖的评论.
## 中文网
中国有一个大型的ABP社区.他们创建了一个中文版的abp.io网站:https://cn.abp.io/. 他们一直在保持更新.感谢中国的开发人员,特别是[Liming Ma](https://github.com/maliming).
中国有一个大型的ABP社区.他们创建了一个中文版的abp.io网站:https://abp.io/. 他们一直在保持更新.感谢中国的开发人员,特别是[Liming Ma](https://github.com/maliming).
## NDC {London} 2019

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

26
docs/zh-Hans/Caching.md

@ -2,6 +2,32 @@
ABP框架扩展了ASP.NET Core的分布式缓存系统.
## Volo.Abp.Caching Package
> 默认情况下启动模板已经安装了这个包,所以大部分情况下你不需要手动安装.
Volo.Abp.Caching是缓存系统的核心包.使用包管理控制台(PMC)安装到项目:
```
Install-Package Volo.Abp.Caching
```
然后将 **AbpCachingModule** 依赖添加到你的模块:
```c#
using Volo.Abp.Modularity;
using Volo.Abp.Caching;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpCachingModule))]
public class MyModule : AbpModule
{
//...
}
}
```
## `IDistributedCache` 接口
ASP.NET Core 定义了 `IDistributedCache` 接口用于 get/set 缓存值 . 但是会有以下问题:

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

@ -0,0 +1,80 @@
# 连接字符串
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` 常量 . 其他的模块类似的定义常量,你可以查看连接字符串的名称.
### AbpDbConnectionOptions
ABP实际上使用 `AbpDbConnectionOptions` 获取连接字符串. 如果如上所述设置了连接字符串, `AbpDbConnectionOptions` 会被自动填充. 但是你也可以使用[选项模式](Options.md)设置或覆盖连接字符串. 你可以在[模块](Module-Development-Basics.md)的 `ConfigureServices` 方法配置`AbpDbConnectionOptions`).
如下所示:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpDbConnectionOptions>(options =>
{
options.ConnectionStrings.Default = "...";
options.ConnectionStrings["AbpPermissionManagement"] = "...";
});
}
````
## 设置连接字符串名称
模块通常使用 `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)了解如何为租户使用单独的数据库.

29
docs/zh-Hans/Contribution/Localization-Text-Files.md

@ -3,7 +3,7 @@
这是一个来自框架的本地化文本文件列表, 任何人都可以做出贡献. 我们会将此列表保持最新:
* 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 @@
* 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

2
docs/zh-Hans/Dependency-Injection.md

@ -319,4 +319,4 @@ public class AppModule : AbpModule
### 请参阅
* [ASP.NET Core依赖注入最佳实践,提示和技巧](https://cn.abp.io/blog/Abp/asp-net-core-dependency-injection-best-practices-tips-tricks)
* [ASP.NET Core依赖注入最佳实践,提示和技巧](https://blog.abp.io/asp-net-core-dependency-injection-best-practices-tips-tricks)

58
docs/zh-Hans/Entity-Framework-Core-MySQL.md

@ -0,0 +1,58 @@
# 切换到EF Core MySql提供程序
本文介绍如何将预配置为SqlServer提供程序的 **[应用程序启动模板](Startup-Templates/Application.md)** 切换到 **MySql** 数据库提供程序
## 替换Volo.Abp.EntityFrameworkCore.SqlServer包
解决方案中的 `.EntityFrameworkCore` 项目依赖于 [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet包. 删除这个包并且添加相同版本的 [Volo.Abp.EntityFrameworkCore.MySQL](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.MySQL) 包.
## 替换模块依赖项
`.EntityFrameworkCore` 项目中找到 **YourProjectName*EntityFrameworkCoreModule** 类, 删除 `DependsOn` attribute 上的`typeof(AbpEntityFrameworkCoreSqlServerModule)`, 添加 `typeof(AbpEntityFrameworkCoreMySQLModule)` (或者替换 `using Volo.Abp.EntityFrameworkCore.SqlServer;``using Volo.Abp.EntityFrameworkCore.MySQL;`).
## UseMySQL()
查找你的解决方案中 `UseSqlServer()`调用,替换为 `UseMySQL()`. 检查下列文件:
* `.EntityFrameworkCore` 项目中的*YourProjectName*EntityFrameworkCoreModule.cs.
* `.EntityFrameworkCore` 项目中的*YourProjectName*MigrationsDbContextFactory.cs.
> 根据你的解决方案的结构,你可能发现更多需要改变代码的文件.
## 更改连接字符串
MySQL连接字符串与SQL Server连接字符串不同. 所以检查你的解决方案中所有的 `appsettings.json` 文件,更改其中的连接字符串. 有关MySQL连接字符串选项的详细内容请参见[connectionstrings.com](https://www.connectionstrings.com/mysql/).
通常需要更改 `.DbMigrator``.Web` 项目里面的 `appsettings.json` ,但它取决于你的解决方案结构.
## 更改迁移DbContext
MySQL DBMS与SQL Server有一些细微的差异. 某些模块数据库映射配置(尤其是字段长度)会导致MySQL出现问题. 例如某些[IdentityServer模块](Modules/IdentityServer.md)表就存在这样的问题,它提供了一个选项可以根据您的DBMS配置字段.
启动模板包含*YourProjectName*MigrationsDbContext,它负责维护和迁移数据库架构. 此DbContext基本上调用依赖模块的扩展方法来配置其数据库表.
打开 *YourProjectName*MigrationsDbContext 更改 `builder.ConfigureIdentityServer();` 行,如下所示:
````csharp
builder.ConfigureIdentityServer(options =>
{
options.DatabaseProvider = EfCoreDatabaseProvider.MySql;
});
````
然后 `ConfigureIdentityServer()` 方法会将字段长度设置为不超过MySQL的限制. 如果在创建或执行数据库迁移时遇到任何问题请参考相关的模块文档.
## 重新生成迁移
启动模板使用[Entity Framework Core的Code First迁移](https://docs.microsoft.com/zh-cn/ef/core/managing-schemas/migrations/). EF Core迁移取决于所选的DBMS提供程序. 因此更改DBMS提供程序会导致迁移失败.
* 删除 `.EntityFrameworkCore.DbMigrations` 项目下的Migrations文件夹,并重新生成解决方案.
* 在包管理控制台中运行 `Add-Migration "Initial"`(在解决方案资源管理器选择 `.DbMigrator` (或 `.Web`) 做为启动项目并且选择 `.EntityFrameworkCore.DbMigrations` 做为默认项目).
这将创建一个配置所有数据库对象(表)的数据库迁移.
运行 `.DbMigrator` 项目创建数据库和初始种子数据.
## 运行应用程序
它已准备就绪, 只需要运行该应用程序与享受编码.

90
docs/zh-Hans/Entity-Framework-Core-Other-DBMS.md

@ -0,0 +1,90 @@
# 切换到EF Core 其它DBMS提供程序
**[应用程序启动模板](Startup-Templates/Application.md)** 为EF Core预配置了Sql Server提供程序,EF Core支持许多其它DBMS,你可以在基于ABP的应用程序使用它们.
ABP框架为一些常见的DMBS提供了简化配置的集成包(有关可用集成包的列表,请参阅[EF Core文档](Entity-Framework-Core.md)),你也可以不使用集成包配置DBMS提供程序.
虽然总是建议使用集成包(它也使不同模块之间的依赖版本成为标准版本),但是如果没有用于DBMS提供程序的集成包,也可以手动集成.
本文介绍了如何在不使用[MySQL集成包](Entity-Framework-Core-MySQL.md)的情况下切换到MySQL.
## 替换SQL Server依赖
* 删除 `.EntityFrameworkCore` 项目依赖的 [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet 包.
* 添加 [Pomelo.EntityFrameworkCore.MySql](https://www.nuget.org/packages/Pomelo.EntityFrameworkCore.MySql/) NuGet 包到 `.EntityFrameworkCore` 项目.
## 删除模块依赖项
***YourProjectName*EntityFrameworkCoreModule** 类的依赖列表中删除`AbpEntityFrameworkCoreSqlServerModule`.
## 更改UseSqlServer()调用
在*YourProjectName*EntityFrameworkCoreModule类中找到以下代码:
````csharp
Configure<AbpDbContextOptions>(options =>
{
options.UseSqlServer();
});
````
替换成以下代码:
````csharp
Configure<AbpDbContextOptions>(options =>
{
options.Configure(ctx =>
{
if (ctx.ExistingConnection != null)
{
ctx.DbContextOptions.UseMySql(ctx.ExistingConnection);
}
else
{
ctx.DbContextOptions.UseMySql(ctx.ConnectionString);
}
});
});
````
* 调用的 `UseMySql` 代码是在 Pomelo.EntityFrameworkCore.MySql 包中定义的,方法还有附加选项,如果需要可以使用它.
* 这段代码首先检查当前请求中是否存在到相同数据库的现有(活动)连接,并在可能的情况下重用它. 这允许在不同的DbContext类型之间共享单个事务. ABP处理其余的事情.
* 如果没有活动的连接,它将把 `ctx.ConnectionString` 传递给UseMySql(这将创建新的数据库连接). 这里使用 `ctx.ConnectionString` 很重要. 不要传递静态连接字符串(或配置中的连接字符串). 因为ABP在多数据库或[多租户](Multi-Tenancy.md)环境中[动态确定正确的连接字符串](Connection-Strings.md).
## 更改连接连接字符串
MySQL连接字符串与SQL Server连接字符串不同. 所以检查你的解决方案中所有的 `appsettings.json` 文件,更改其中的连接字符串. 有关MySQL连接字符串选项的详细内容请参见[connectionstrings.com](https://www.connectionstrings.com/mysql/).
通常需要更改 `.DbMigrator``.Web` 项目里面的 `appsettings.json` ,但它取决于你的解决方案结构.
## 更改迁移DbContext
MySQL DBMS与SQL Server有一些细微的差异. 某些模块数据库映射配置(尤其是字段长度)会导致MySQL出现问题. 例如某些[IdentityServer模块](Modules/IdentityServer.md)表就存在这样的问题,它提供了一个选项可以根据您的DBMS配置字段.
启动模板包含*YourProjectName*MigrationsDbContext,它负责维护和迁移数据库架构. 此DbContext基本上调用依赖模块的扩展方法来配置其数据库表.
打开 *YourProjectName*MigrationsDbContext 更改 `builder.ConfigureIdentityServer();` 行,如下所示:
````csharp
builder.ConfigureIdentityServer(options =>
{
options.DatabaseProvider = EfCoreDatabaseProvider.MySql;
});
````
然后 `ConfigureIdentityServer()` 方法会将字段长度设置为超过MySQL的限制. 如果在创建或执行数据库迁移时遇到任何问题请参考相关的模块文档.
## 重新生成迁移
启动模板使用[Entity Framework Core的Code First迁移](https://docs.microsoft.com/zh-cn/ef/core/managing-schemas/migrations/). EF Core迁移取决于所选的DBMS提供程序. 因此更改DBMS提供程序会导致迁移失败.
* 删除 `.EntityFrameworkCore.DbMigrations` 项目下的Migrations文件夹,并重新生成解决方案.
* 在包管理控制台中运行 `Add-Migration "Initial"`(在解决方案资源管理器选择 `.DbMigrator` (或 `.Web`) 做为启动项目并且选择 `.EntityFrameworkCore.DbMigrations` 做为默认项目).
这将创建一个配置所有数据库对象(表)的数据库迁移.
运行 `.DbMigrator` 项目创建数据库和初始种子数据.
## 运行应用程序
它已准备就绪, 只需要运行该应用程序与享受编码.

52
docs/zh-Hans/Entity-Framework-Core-PostgreSQL.md

@ -1,35 +1,41 @@
## Entity Framework Core PostgreSQL 集成
# 切换到EF Core PostgreSQL提供程序
> 参阅 [Entity Framework Core 集成文档](../Entity-Framework-Core.md) 了解集成EF Core的基础知识.
本文介绍如何将预配置为SqlServer提供程序的 **[应用程序启动模板](Startup-Templates/Application.md)** 切换到 **PostgreSQL** 数据库提供程序
### 更新 EntityFrameworkCore 项目
## 替换Volo.Abp.EntityFrameworkCore.SqlServer包
- 在 `Acme.BookStore.EntityFrameworkCore` 中将包 `Volo.Abp.EntityFrameworkCore.SqlServer` 替换为 `Volo.Abp.EntityFrameworkCore.PostgreSql`
- 打开 `BookStoreEntityFrameworkCoreModule` 模块类
- 将 `AbpEntityFrameworkCoreSqlServerModule` 替换为 `AbpEntityFrameworkCorePostgreSqlModule`
- 将 `options.UseSqlServer()` 替换为 `options.UsePostgreSql()`
- 在其他的项目中将 `appsetting.json` 文件中的连接字符串更新为PostgreSQL链接字符串
解决方案中的 `.EntityFrameworkCore` 项目依赖于 [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet包. 删除这个包并且添加相同版本的 [Volo.Abp.EntityFrameworkCore.PostgreSql](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.PostgreSql) 包.
#### 删除现有迁移
## 替换模块依赖项
删除所有的现有迁移文件 (包括 `DbContextModelSnapshot`)
`.EntityFrameworkCore` 项目中找到 **YourProjectName*EntityFrameworkCoreModule** 类, 删除 `DependsOn` attribute 上的`typeof(AbpEntityFrameworkCoreSqlServerModule)`, 添加 `typeof(AbpEntityFrameworkCorePostgreSqlModule)` (或者替换 `using Volo.Abp.EntityFrameworkCore.SqlServer;``using Volo.Abp.EntityFrameworkCore.PostgreSql;`).
![postgresql-delete-initial-migrations](images/postgresql-delete-initial-migrations.png)
## UsePostgreSql()
#### 生成生成迁移并更新数据库
查找你的解决方案中 `UseSqlServer()`调用,替换为 `UsePostgreSql()`. 检查下列文件:
设置正确的启动项目 (通常是Web项目),
打开 **程序包管理器控制台** (工具 -> Nuget包管理器 -> 程序包管理器控制台), 选择 `Acme.BookStore.EntityFrameworkCore.DbMigrations` 做为 **默认项目** 并执行以下命令:
* `.EntityFrameworkCore` 项目中的*YourProjectName*EntityFrameworkCoreModule.cs.
* `.EntityFrameworkCore` 项目中的*YourProjectName*MigrationsDbContextFactory.cs.
运行 `Add-Migration` 命令.
````
PM> Add-Migration Initial
````
> 根据你的解决方案的结构,你可能发现更多需要改变代码的文件.
然后执行 `Update-Database` 执行更新数据库:
## 更改连接字符串
````
PM> Update-Database
````
PostgreSql连接字符串与SQL Server连接字符串不同. 所以检查你的解决方案中所有的 `appsettings.json` 文件,更改其中的连接字符串. 有关PostgreSql连接字符串选项的详细内容请参见[connectionstrings.com](https://www.connectionstrings.com/postgresql/).
![postgresql-update-database](images/postgresql-update-database.png)
通常需要更改 `.DbMigrator``.Web` 项目里面的 `appsettings.json` ,但它取决于你的解决方案结构.
## 重新生成迁移
启动模板使用[Entity Framework Core的Code First迁移](https://docs.microsoft.com/zh-cn/ef/core/managing-schemas/migrations/). EF Core迁移取决于所选的DBMS提供程序. 因此更改DBMS提供程序会导致迁移失败.
* 删除 `.EntityFrameworkCore.DbMigrations` 项目下的Migrations文件夹,并重新生成解决方案.
* 在包管理控制台中运行 `Add-Migration "Initial"`(在解决方案资源管理器选择 `.DbMigrator` (或 `.Web`) 做为启动项目并且选择 `.EntityFrameworkCore.DbMigrations` 做为默认项目).
这将创建一个配置所有数据库对象(表)的数据库迁移.
运行 `.DbMigrator` 项目创建数据库和初始种子数据.
## 运行应用程序
它已准备就绪, 只需要运行该应用程序与享受编码.

41
docs/zh-Hans/Entity-Framework-Core-SQLite.md

@ -0,0 +1,41 @@
# 切换到EF Core SQLite提供程序
本文介绍如何将预配置为SqlServer提供程序的 **[应用程序启动模板](Startup-Templates/Application.md)** 切换到 **SQLite** 数据库提供程序.
## 替换Volo.Abp.EntityFrameworkCore.SqlServer包
解决方案中的 `.EntityFrameworkCore` 项目依赖于 [Volo.Abp.EntityFrameworkCore.SqlServer](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SqlServer) NuGet包. 删除这个包并且添加相同版本的 [Volo.Abp.EntityFrameworkCore.SQLite](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.SQLite) 包.
## 替换模块依赖项
`.EntityFrameworkCore` 项目中找到 **YourProjectName*EntityFrameworkCoreModule** 类, 删除 `DependsOn` attribute 上的`typeof(AbpEntityFrameworkCoreSqlServerModule)`, 添加 `typeof(AbpEntityFrameworkCoreSqliteModule)` (或者替换 `using Volo.Abp.EntityFrameworkCore.SqlServer;``using Volo.Abp.EntityFrameworkCore.Sqlite;`).
## UseSqlite()
查找你的解决方案中 `UseSqlServer()`调用,替换为 `UseSqlite()`. 检查下列文件:
* `.EntityFrameworkCore` 项目中的*YourProjectName*EntityFrameworkCoreModule.cs.
* `.EntityFrameworkCore` 项目中的*YourProjectName*MigrationsDbContextFactory.cs.
> 根据你的解决方案的结构,你可能发现更多需要改变代码的文件.
## 更改连接字符串
SQLite连接字符串与SQL Server连接字符串不同. 所以检查你的解决方案中所有的 `appsettings.json` 文件,更改其中的连接字符串. 有关SQLite连接字符串选项的详细内容请参见[connectionstrings.com](https://www.connectionstrings.com/sqlite/).
通常需要更改 `.DbMigrator``.Web` 项目里面的 `appsettings.json` ,但它取决于你的解决方案结构.
## 重新生成迁移
启动模板使用[Entity Framework Core的Code First迁移](https://docs.microsoft.com/zh-cn/ef/core/managing-schemas/migrations/). EF Core迁移取决于所选的DBMS提供程序. 因此更改DBMS提供程序会导致迁移失败.
* 删除 `.EntityFrameworkCore.DbMigrations` 项目下的Migrations文件夹,并重新生成解决方案.
* 在包管理控制台中运行 `Add-Migration "Initial"`(在解决方案资源管理器选择 `.DbMigrator` (或 `.Web`) 做为启动项目并且选择 `.EntityFrameworkCore.DbMigrations` 做为默认项目).
这将创建一个配置所有数据库对象(表)的数据库迁移.
运行 `.DbMigrator` 项目创建数据库和初始种子数据.
## 运行应用程序
它已准备就绪, 只需要运行该应用程序与享受编码.

58
docs/zh-Hans/Entity-Framework-Core.md

@ -1,8 +1,8 @@
## Entity Framework Core 集成
# Entity Framework Core 集成
本文介绍了如何将EF Core作为ORM提供程序集成到基于ABP的应用程序以及如何对其进行配置.
### 安装
## 安装
`Volo.Abp.EntityFrameworkCore` 是EF Core 集成的主要nuget包. 将其安装到你的项目中(在分层应用程序中适用于 数据访问/基础设施层):
@ -26,7 +26,22 @@ namespace MyCompany.MyProject
}
````
### 创建 DbContext
> 注: 你可以直接下载预装EF Core的[启动模板](https://abp.io/Templates).
### 数据库管理系统选择
EF Core支持多种数据库管理系统([查看全部](https://docs.microsoft.com/en-us/ef/core/providers/)). ABP框架和本文档不依赖于任何特定的DBMS.
如果要创建一个可重用的库,应避免依赖于特定的DBMS包.但在最终的应用程序中,始终会选择一个DBMS.
ABP框架为一些常见的DBMS提供了集成包,使配置变得更加简单. [启动模板](Startup-Templates/Index.md)附带**预先配置的SQL Server (localdb)**.请参阅以下文档,了解如何配置其他DBMS提供程序:
* [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)
## 创建 DbContext
你可以平常一样创建DbContext,它需要继承自 `AbpDbContext<T>`. 如下所示:
@ -48,7 +63,22 @@ namespace MyCompany.MyProject
}
````
### 将DbContext注册到依赖注入
### 配置连接字符串选择
如果你的应用程序有多个数据库,你可以使用 `connectionStringName]` Attribute为你的DbContext配置连接字符串名称.
例:
```csharp
[ConnectionStringName("MySecondConnString")]
public class MyDbContext : AbpDbContext<MyDbContext>
{
}
```
如果不进行配置,则使用`Default`连接字符串. 如果你配置特定的连接字符串的名称,但在应用程序配置中没有定义这个连接字符串名称,那么它会回退到`Default`连接字符串(参阅[连接字符串文档](Connection-Strings.md)了解更多信息).
## 将DbContext注册到依赖注入
在module中的ConfigureServices方法使用 `AddAbpDbContext` 在[依赖注入](Dependency-Injection.md)系统注册DbContext类.
@ -72,7 +102,7 @@ namespace MyCompany.MyProject
}
````
#### 添加默认仓储
### 添加默认仓储
ABP会自动为DbContext中的实体创建[默认仓储](Repositories.md). 需要在注册的时使用options添加`AddDefaultRepositories()`:
@ -151,7 +181,7 @@ public interface IBookRepository : IRepository<Book, Guid>
}
````
你通常希望从IRepository派生以继承标准存储库方法. 然而,你没有必要这样做. 仓储接口在分层应用程序的领域层中定义,它在数据访问/基础设施层([启动模板](https://cn.abp.io/Templates)中的`EntityFrameworkCore`项目)中实现
你通常希望从IRepository派生以继承标准存储库方法. 然而,你没有必要这样做. 仓储接口在分层应用程序的领域层中定义,它在数据访问/基础设施层([启动模板](https://abp.io/Templates)中的`EntityFrameworkCore`项目)中实现
IBookRepository接口的实现示例:
@ -165,7 +195,7 @@ public class BookRepository : EfCoreRepository<BookStoreDbContext, Book, Guid>,
public async Task DeleteBooksByType(BookType type)
{
await DbContext.Database.ExecuteSqlCommandAsync(
await DbContext.Database.ExecuteSqlRawAsync(
$"DELETE FROM Books WHERE Type = {(int)type}"
);
}
@ -174,7 +204,7 @@ public class BookRepository : EfCoreRepository<BookStoreDbContext, Book, Guid>,
现在可以在需要时[注入](Dependency-Injection.md)`IBookRepository`并使用`DeleteBooksByType`方法.
##### 覆盖默认通用仓储
#### 覆盖默认通用仓储
即使创建了自定义仓储,仍可以注入使用默认通用仓储(在本例中是 `IRepository<Book, Guid>`). 默认仓储实现不会使用你创建的自定义仓储类.
@ -200,7 +230,7 @@ public override async Task DeleteAsync(
}
````
#### 访问 EF Core API
### 访问 EF Core API
大多数情况下应该隐藏仓储后面的EF Core API(这也是仓储的设计目地). 但是如果想要通过仓储访问DbContext实现,则可以使用`GetDbContext()`或`GetDbSet()`扩展方法. 例:
@ -226,9 +256,9 @@ public class BookService
> 要点: 你必须在使用`DbContext`的项目里引用`Volo.Abp.EntityFrameworkCore`包. 这会破坏封装,但在这种情况下,这就是你需要的.
#### 高级主题
### 高级主题
##### 设置默认仓储类
#### 设置默认仓储类
默认的通用仓储的默认实现是`EfCoreRepository`类,你可以创建自己的实现,并将其做为默认实现
@ -273,7 +303,7 @@ context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
});
```
#### 为默认仓储设置Base DbContext类或接口
### 为默认仓储设置Base DbContext类或接口
如果你的DbContext继承了另外一个DbContext或实现了一个接口,你可以使用这个基类或接口作为默认仓储的DbContext. 例:
@ -305,7 +335,7 @@ public class BookRepository : EfCoreRepository<IBookStoreDbContext, Book, Guid>,
使用DbContext接口的一个优点是它可以被其他实现替换.
#### 替换其他仓储
### 替换其他仓储
正确定义并使用DbContext接口后,任何其他实现都可以使用以下ReplaceDbContext options 替换它:
@ -317,4 +347,4 @@ context.Services.AddAbpDbContext<OtherDbContext>(options =>
});
````
在这个例子中,`OtherDbContext`实现了`IBookStoreDbContext`. 此功能允许你在开发时使用多个DbContext(每个模块一个),但在运行时可以使用单个DbContext(实现所有DbContext的所有接口).
在这个例子中,`OtherDbContext`实现了`IBookStoreDbContext`. 此功能允许你在开发时使用多个DbContext(每个模块一个),但在运行时可以使用单个DbContext(实现所有DbContext的所有接口).

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)

2
docs/zh-Hans/Getting-Started-AspNetCore-MVC-Template.md

@ -2,7 +2,7 @@
### 创建新项目
本教程使用 **ABP CLI** 创建一个新项目. 更多选项, 请参阅[入门](https://cn.abp.io/get-started)页面.
本教程使用 **ABP CLI** 创建一个新项目. 更多选项, 请参阅[入门](https://abp.io/get-started)页面.
如果你之前未安装,请使用命令行安装ABP CLI:

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的,它可以在任何类型的应用程序中使用.

2
docs/zh-Hans/Microservice-Architecture.md

@ -23,7 +23,7 @@ ABP框架的主要目标之一就是提供**便捷的基础设施来创建微服
然而开发一个良好的模块化应用程序不是那么简单,因为很难像微服务那样**保持模块之间的隔离** (参阅 [Stefan Tilkov的文章](https://martinfowler.com/articles/dont-start-monolith.html)). 微服务架构会自然的让你开发隔离的服务,但是在模块化的单体应用程序中,模块很容易彼此紧密耦合并设计出**弱模块边界**和API约定.
ABP可以帮助你,它提供了与**与微服务兼容的严格模块架构** 在这个架构中你的模块被分割成多个层/项目,在自己的VS解决方案中进行开发,该解决方案完独立于其它模块. 这种方式开发的模块是一种天然的微服务,但是它可以很容易的插入到单体应用程序中. 请参阅**微服务优先的模块设计**的[模块开发最佳实践指南](Best-Practices/Index.md). 所有[标准的ABP模块](https://github.com/abpframework/abp/tree/master/modules)都是基于本指南开发的. 因此你可以将这些模块嵌入到单体解决方案中使用它们,也可以单独部署通过远程API调用. 它们可以共享一个数据库,也可以通过简单配置使用自己的数据库.
ABP可以帮助你,它提供了与**与微服务兼容的严格模块架构** 在这个架构中你的模块被分割成多个层/项目,在自己的VS解决方案中进行开发,该解决方案完独立于其它模块. 这种方式开发的模块是一种天然的微服务,但是它可以很容易的插入到单体应用程序中. 请参阅**微服务优先的模块设计**的[模块开发最佳实践指南](Best-Practices/Index.md). 所有[标准的ABP模块](https://github.com/abpframework/abp/tree/master/modules)都是基于本指南开发的. 因此你可以将这些模块嵌入到单体解决方案中使用它们,也可以单独部署通过远程API调用. 它们可以共享一个数据库,也可以通过简单配置使用自己的数据库.
## 微服务解决方案示例

7
docs/zh-Hans/Modules/Audit-Logging.md

@ -0,0 +1,7 @@
# 审计日志模块
审计日志模块实现了 `IAuditingStore` 将审计日志对象保存到数据库中.
> [启动模板](../Startup-Templates/Index.md)已经安装并配置了审计日志模块,所以你不需要手动安装到你的应用程序.
参阅[审计日志系统](../Audit-Logging.md)文档了解更多关于审计日志的内容.

146
docs/zh-Hans/Modules/Docs.md

@ -14,21 +14,19 @@
### 版本
当你使用GitHub存储文档时,文档模块支持多版本. 如果你的文档具有多个版本, UI上有一个组合框,用于切换版本. 如果你选择使用文件系统存储文档, 那么它不支持多版本.
当你使用GitHub存储文档时,文档模块支持多版本. 如果你的文档具有多个版本, UI上有一个组合框,用于切换版本. 如果你选择使用文件系统存储文档, 那么它不支持多版本.
ABP框架的[文档](https://abp.io/documents/)也是使用的此模块.
ABP框架的[文档](docs.abp.io)也是使用的此模块.
> 文档模块遵循 [模块化架构最佳实践](../Best-Practices/Module-Architecture.md) 指南.
## 安装
### 1- 下载
如果你没有现有的ABP项目, 这个步骤向你展示如何在[abp.io](https://cn.abp.io)创建一个新项目并添加文档模块. 如果你本地已经有了一个ABP项目, 那么你可以跳过这一步.
如果你没有现有的ABP项目, 这个步骤向你展示如何在[abp.io](https://abp.io)创建一个新项目并添加文档模块. 如果你本地已经有了一个ABP项目, 那么你可以跳过这一步.
打开 https://cn.abp.io/Templates. 输入项目名称为 `Acme.MyProject`, 选择 `ASP.NET Core Mvc Application` 和选择 `Entity Framework Core` 做为数据库提供者.
打开 https://abp.io/Templates. 输入项目名称为 `Acme.MyProject`, 选择 `ASP.NET Core Mvc Application` 和选择 `Entity Framework Core` 做为数据库提供者.
请注意,本文档包含了 `Entity Framework Core` 提供者 不过你也可以选择 `MongoDB` 做为数据库提供者.
@ -36,7 +34,7 @@ ABP框架的[文档](https://abp.io/documents/)也是使用的此模块.
### 2- 运行这个空项目
下载项目后, 解压压缩文档并且打开 `Acme.MyProject.sln`. 你可以看到这个解决方案包含了 `Application`, `Domain `, `EntityFrameworkCore``Web` 项目. 右键选择 `Acme.MyProject.Web` 项目**设置为启动项目**.
下载项目后, 解压压缩文档并且打开 `Acme.MyProject.sln`. 你可以看到这个解决方案包含了 `Application`, `Domain`, `EntityFrameworkCore``Web` 项目. 右键选择 `Acme.MyProject.Web` 项目**设置为启动项目**.
![创建新项目](../images/docs-module_solution-explorer.png)
@ -67,31 +65,32 @@ ABP框架的[文档](https://abp.io/documents/)也是使用的此模块.
```csharp
<PackageReference Include="Volo.Docs.Domain" Version="0.9.0" />
```
* [Volo.Docs.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Docs.EntityFrameworkCore/) 需要安装到 `Acme.MyProject.EntityFrameworkCore` 项目.
- 修改 `Acme.MyProject.EntityFrameworkCore.csproj`文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本.
* 修改 `Acme.MyProject.EntityFrameworkCore.csproj` 文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本.
```csharp
<PackageReference Include="Volo.Docs.EntityFrameworkCore" Version="0.9.0" />
```
* [Volo.Docs.Application](https://www.nuget.org/packages/Volo.Docs.Application/) 需要安装到 `Acme.MyProject.Application` 项目.
* 修改 `Acme.MyProject.Application.csproj`文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本.
* 修改 `Acme.MyProject.Application.csproj` 文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本.
```csharp
<PackageReference Include="Volo.Docs.Application" Version="0.9.0" />
```
* [Volo.Docs.Web ](https://www.nuget.org/packages/Volo.Docs.Web/) 需要安装到 `Acme.MyProject.Web` 项目.
- 修改 `Acme.MyProject.Web.csproj`文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本.
* [Volo.Docs.Web](https://www.nuget.org/packages/Volo.Docs.Web/) 需要安装到 `Acme.MyProject.Web` 项目.
* 修改 `Acme.MyProject.Web.csproj` 文件并且添加以下行. 需要注意它要设置(v0.9.0)为Latest版本.
```csharp
<PackageReference Include="Volo.Docs.Web" Version="0.9.0" />
```
### 3- 添加模块添加
### 3- 添加模块依赖
一个ABP模块必须声明 `[DependsOn]` attribute 如果它依赖于另一个模块. 每个模块都必须在相关的项目的`[DependsOn]`Attribute 中添加.
@ -155,7 +154,6 @@ ABP框架的[文档](https://abp.io/documents/)也是使用的此模块.
}
```
* 打开 `MyProjectWebModule.cs`并且添加 `typeof(DocsWebModule)` 如下所示;
```csharp
@ -174,15 +172,13 @@ ABP框架的[文档](https://abp.io/documents/)也是使用的此模块.
}
```
### 4- 数据库集成
#### 4.1- Entity Framework 集成
如果你选择了Entity Framework 做为数据库供应者,你需要在DbContext中配置文档模块. 做以下操作;
- 打开 `MyProjectDbContext.cs` 并且添加 `modelBuilder.ConfigureDocs()``OnModelCreating()` 方法中
* 打开 `MyProjectDbContext.cs` 并且添加 `modelBuilder.ConfigureDocs()``OnModelCreating()` 方法中
```csharp
[ConnectionStringName("Default")]
@ -195,7 +191,7 @@ ABP框架的[文档](https://abp.io/documents/)也是使用的此模块.
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
{
//...
modelBuilder.ConfigureDocs();
}
@ -218,7 +214,6 @@ ABP框架的[文档](https://abp.io/documents/)也是使用的此模块.
最后你可以查看数据库中创建的新表,例如你可以看到 `DocsProjects` 表已经添加到数据库中.
### 5- 链接文档模块
文档模块的默认路由是;
@ -262,7 +257,7 @@ ABP框架的[文档](https://abp.io/documents/)也是使用的此模块.
"texts": {
"Menu:Home": "首页",
"Welcome": "欢迎",
"LongWelcomeMessage": "欢迎来到该应用程序. 这是一个基于ABP框架的启动项目. 有关更多信息, 请访问 cn.abp.io.",
"LongWelcomeMessage": "欢迎来到该应用程序. 这是一个基于ABP框架的启动项目. 有关更多信息, 请访问 abp.io.",
"Menu:Docs": "文档"
}
}
@ -326,7 +321,7 @@ There are no projects yet!
对于 `SQL` 数据库,你可以使用下面的 `T-SQL` 命令将指定的示例插入到 `DocsProjects` 表中:
```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/zh-Hans/","GitHubAccessToken":"***"}', N'/', N'master')
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName]) 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', N'')
```
请注意,`GitHubAccessToken` 被屏蔽了.它是一个私人令牌,你必须获得自己的令牌并替换 `***` 字符串.
@ -352,10 +347,10 @@ INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocume
- ExtraProperties:
```json
{"Path":"C:\\Github\\abp\\docs\\zh-Hans"}
{"Path":"C:\\Github\\abp\\docs"}
```
请注意 `Path` 必须使用本地docs目录替换. 你可以从https://github.com/abpframework/abp/tree/master/docs/zh-hans获取ABP Framework的文档并且复制到该目录 `C:\\Github\\abp\\docs\\zh-Hans` 使其正常工作.
请注意 `Path` 必须使用本地docs目录替换. 你可以从https://github.com/abpframework/abp/tree/master/docs获取ABP Framework的文档并且复制到该目录 `C:\\Github\\abp\\docs` 使其正常工作.
- MainWebsiteUrl: `/`
@ -364,7 +359,7 @@ INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocume
对于 `SQL` 数据库,你可以使用下面的 `T-SQL` 命令将指定的示例插入到 `DocsProjects` 表中:
```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\\zh-Hans"}', N'/', NULL)
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName]) 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, N'')
```
添加上面的一个示例项目后运行该应用程序. 在菜单中你会看到`文档` 链接,点击菜单链接打开文档页面.
@ -408,6 +403,101 @@ public class Person
[https://github.com/abpframework/abp/blob/master/docs/zh-Hans/](https://github.com/abpframework/abp/blob/master/docs/zh-Hans/)
#### 有条件的部分功能(使用Scriban)
文档模块使用[Scriban](<https://github.com/lunet-io/scriban/tree/master/doc>)有条件的显示或隐藏文档的某些部分. 使用该功能你需要为每一种语言创建一个JSON文件做为**参数文档**. 它包含所有键值以及它们的显示名称.
例如 [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"
}
}]
}
```
因为并不是项目中的每个文档都有章节或者不需要所有的参数,你必须声明哪些参数将用于对文档进行分段,在文档的任何地方都可以使用JSON块.
例如 [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"]
}
​````
........
```
这个部分会在渲染时自动删除.前提是这些键值必须与**参数文档**中的键值匹配.
![Interface](../images/docs-section-ui.png)
现在你可以使用 **Scriban** 语法在文档中创建章节.
示例 :
````
{{ 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 }}
````
还可以在文本中使用变量,在其键中添加 **_Value** 后缀:
````
This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider.
````
如果你想要得到的当前文档的语言或版本,可以使用预定义的 **Document_Language_Code****DOCUMENT_VERSION** 键(这对于创建重定向到另一个地区中另一个文档系统的链接很有用).
------
**重要提示**: Scriban 的语法是 "{{" and "}}". 如果要在文档(如Angular文档)中使用转义,则必须使用转义块. 参阅 [Scriban文档](<https://github.com/lunet-io/scriban/blob/master/doc/language.md#13-escape-block> ) 了解更多信息.
### 8- 创建文档导航
导航文档是文档页面的主菜单. 它位于页面的左侧,是一个`JSON` 文件. 请查看以下示例导航文档以了解结构.
@ -464,4 +554,8 @@ public class Person
![Navigation menu](../images/docs-module_download-sample-navigation-menu.png)
最后,为您的项目添加了一个新的Docs模块, 该模块由GitHub提供.
最后,为您的项目添加了一个新的Docs模块, 该模块由GitHub提供.
## 下一步
文档模块也可以做为独立的应用程序. 查看 [VoloDocs](../Apps/VoloDocs).

18
docs/zh-Hans/Modules/Index.md

@ -11,16 +11,20 @@ ABP是一个 **模块化的应用程序框架** 由十多个 **nuget packages**
有一些由ABP社区开发和维护的 **开源免费** 的应用程序模块:
* **Account**: 用于用户登录/注册应用程序.
* **Audit Logging**: 用于将审计日志持久化到数据库.
* **Account**: 提供账户管理UI,并允许用户登录/注册应用程序.
* [**Audit Logging**](Audit-Logging.md): 用于将审计日志持久化到数据库.
* **Background Jobs**: 用于在使用默认后台作业管理器时保存后台作业.
* **Blogging**: 用于创建精美的博客. ABP的[博客](https://abp.io/blog/abp/) 就使用了此模块.
* **Blogging**: 用于创建精美的博客. ABP的[博客](https://blog.abp.io/) 就使用了此模块.
* [**Docs**](Docs.md): 用于创建技术文档页面. ABP的[文档](https://abp.io/documents/) 就使用了此模块.
* **Identity**: 用于管理角色,用户和他们的权限.
* **Identity**: 基于Microsoft Identity管理角色,用户和他们的权限.
* **Identity Server**: 集成了IdentityServer4.
* **Permission Management**: 用于保存权限.
* **Setting Management**: 用于保存设置.
* **Tenant Management**: 用于管理[多租户](../Multi-Tenancy.md)应用程序的租户.
* **Users**: 用于抽象用户, 因此其他模块可以依赖此模块而不是Identity模块.
* **Tenant Management**: 管理[多租户](../Multi-Tenancy.md)应用程序的租户.
* **Users**: 抽象用户, 因此其他模块可以依赖此模块而不是Identity模块.
模块化文档正在编写中. 请参阅[这个仓库](https://github.com/abpframework/abp/tree/master/modules)获取所有模块的源代码.
模块化文档正在编写中. 请参阅[这个仓库](https://github.com/abpframework/abp/tree/master/modules)获取所有模块的源代码.
## 商业应用模块
[ABP商业](https://commercial.abp.io/)许可证在ABP框架上提供了额外的预构建应用程序模块. 参见ABP商业版提供的[模块列表](https://commercial.abp.io/module).

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

@ -1,3 +1,86 @@
# 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");
}
}
}
````
你可以从不同的设置值提供程序中(默认,全局,用户,租户...等)中获取或设定设置值.
> 如果只需要读取设置值,建议使用 `ISettingProvider` 而不是`ISettingManager`,因为它实现了缓存并支持所有部署场景. 如果要创建设置管理UI,可以使用ISettingManager.
### Setting Cache
设置值缓存在 [分布式缓存](../Caching.md) 系统中. 建议始终使用 `ISettingManager` 更改设置值.
## Setting Management Providers
设置管理模块是可扩展的,像[设置系统](../Settings.md)一样. 你可以通过自定义设置管理提供程序进行扩展. 有5个预构建的设置管理程序程序按以下顺序注册:
* `DefaultValueSettingManagementProvider`: 从设置定义的默认值中获取值,由于默认值是硬编码在设置定义上的,所以无法更改默认值.
* `ConfigurationSettingManagementProvider`:从 [IConfiguration 服务](../Configuration.md)中获取值. 由于无法在运行时更改配置值,所以无法更改配置值.
* `GlobalSettingManagementProvider`: 获取或设定设置的全局 (系统范围)值.
* `TenantSettingManagementProvider`: 获取或设定租户的设置值.
* `UserSettingManagementProvider`: 获取或设定用户的设置值.
`ISettingManager``get/set` 方法中使用设置管理提供程序. 通常每个设置程序提供程序都在 `ISettingManagement` 服务上定义了模块方法 (比如用户设置管理程序提供定义了 `SetForUserAsync` 方法).

8
docs/zh-Hans/Multi-Tenancy.md

@ -99,7 +99,7 @@ Volo.Abp.MultiTenancy只提供了用于确定当前租户的抽象(称为租户
##### 自定义租户解析器
你可以像下面这样,在你模块的ConfigureServices方法中将自定义解析器并添加到 **TenantResolveOptions**中:
你可以像下面这样,在你模块的ConfigureServices方法中将自定义解析器并添加到 **AbpTenantResolveOptions**中:
````C#
using Microsoft.Extensions.DependencyInjection;
@ -113,7 +113,7 @@ namespace MyCompany.MyProject
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<TenantResolveOptions>(options =>
Configure<AbpTenantResolveOptions>(options =>
{
options.TenantResolvers.Add(new MyCustomTenantResolveContributor());
});
@ -323,7 +323,7 @@ services.Configure<AbpAspNetCoreMultiTenancyOptions>(options =>
##### 域名租户解析器
实际项目中,大多数情况下你想通过子域名(如mytenant1.mydomain.com)或全域名(如mytenant.com)中确定当前租户.如果是这样,你可以配置TenantResolveOptions添加一个域名租户解析器.
实际项目中,大多数情况下你想通过子域名(如mytenant1.mydomain.com)或全域名(如mytenant.com)中确定当前租户.如果是这样,你可以配置AbpTenantResolveOptions添加一个域名租户解析器.
###### 例子:添加子域名解析器
@ -340,7 +340,7 @@ namespace MyCompany.MyProject
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<TenantResolveOptions>(options =>
Configure<AbpTenantResolveOptions>(options =>
{
//子域名格式: {0}.mydomain.com (作为最高优先级解析器添加)
options.TenantResolvers.Insert(0, new DomainTenantResolver("{0}.mydomain.com"));

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

Loading…
Cancel
Save