Browse Source

Merge branch 'dev' into liangshiwei/multi-lingual-entities

pull/5265/head
liangshiwei 6 years ago
parent
commit
a5431d0863
  1. 1
      .github/ISSUE_TEMPLATES/feature.md
  2. 2
      .github/workflows/build-and-test.yml
  3. 71
      .github/workflows/codeql-analysis.yml
  4. 4
      .gitignore
  5. 7
      NuGet.Config
  6. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hans.json
  7. 43
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ar.json
  8. 116
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hans.json
  9. 31
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/ar.json
  10. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
  11. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json
  12. 35
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json
  13. 7
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
  14. 68
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json
  15. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
  16. 149
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json
  17. 161
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ar.json
  18. 30
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  19. 36
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json
  20. 6
      build/common.ps1
  21. 6
      common.props
  22. 15
      docs/en/.vscode/settings.json
  23. 35
      docs/en/API/Auto-API-Controllers.md
  24. 2
      docs/en/API/Dynamic-CSharp-API-Clients.md
  25. 62
      docs/en/Application-Services.md
  26. 8
      docs/en/AspNet-Boilerplate-Migration-Guide.md
  27. 5
      docs/en/Best-Practices/Application-Services.md
  28. 2
      docs/en/Blob-Storing.md
  29. 262
      docs/en/Blog-Posts/2020-09-17 v3_2_Preview/POST.md
  30. BIN
      docs/en/Blog-Posts/2020-09-17 v3_2_Preview/abp-community-20200917.png
  31. BIN
      docs/en/Blog-Posts/2020-09-17 v3_2_Preview/account-profile-picture.jpg
  32. BIN
      docs/en/Blog-Posts/2020-09-17 v3_2_Preview/blazor-role-management.png
  33. BIN
      docs/en/Blog-Posts/2020-09-17 v3_2_Preview/blazorise-github.png
  34. BIN
      docs/en/Blog-Posts/2020-09-17 v3_2_Preview/file-management-module-angular.png
  35. BIN
      docs/en/Blog-Posts/2020-09-17 v3_2_Preview/host-features.png
  36. BIN
      docs/en/Blog-Posts/2020-09-17 v3_2_Preview/visual-studio-solution-with-blazor.png
  37. 47
      docs/en/Blog-Posts/2020-10-01 v3_2_Release_Stable/POST.md
  38. 271
      docs/en/Blog-Posts/2020-10-15 v3_3_Preview/POST.md
  39. BIN
      docs/en/Blog-Posts/2020-10-15 v3_3_Preview/abp-blazor-ui.png
  40. BIN
      docs/en/Blog-Posts/2020-10-15 v3_3_Preview/abp-commercial-blazor-ui.png
  41. BIN
      docs/en/Blog-Posts/2020-10-15 v3_3_Preview/abp-commercial-linked-users.png
  42. BIN
      docs/en/Blog-Posts/2020-10-15 v3_3_Preview/abp-commercial-setting-account-external-logins.png
  43. 47
      docs/en/Blog-Posts/2020-10-27 v3_3_Release_Stable/POST.md
  44. 67
      docs/en/CLI-BuildCommand.md
  45. 32
      docs/en/CLI.md
  46. 119
      docs/en/CSRF-Anti-Forgery.md
  47. 258
      docs/en/Caching.md
  48. 477
      docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/POST.md
  49. BIN
      docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/bee.gif
  50. BIN
      docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/db-migrator-1.jpg
  51. BIN
      docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/db-migrator-2.jpg
  52. BIN
      docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/db-migrator-3.jpg
  53. BIN
      docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/email-last.jpg
  54. BIN
      docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/embedded-resource-2.jpg
  55. BIN
      docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/embedded-resource.jpg
  56. BIN
      docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/inline-content.png
  57. BIN
      docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/message.jpg
  58. BIN
      docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/settings.jpg
  59. BIN
      docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/template-definitions.png
  60. 122
      docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/POST.md
  61. BIN
      docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/app-login.JPG
  62. BIN
      docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/auth-diagram.jpeg
  63. BIN
      docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/azure-app-authentication.jpg
  64. BIN
      docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/azure-app-overview.jpg
  65. BIN
      docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/azure-app-register.JPG
  66. BIN
      docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/azure-app-registration.jpg
  67. BIN
      docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/azure-app-secret.jpg
  68. 317
      docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/Using-DevExtremeAngularComponents-With-The-ABP-Framework.md
  69. BIN
      docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/dev-extreme-page.png
  70. BIN
      docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/devextreme-final.gif
  71. BIN
      docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/devextreme-first.png
  72. BIN
      docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/devextreme-second.png
  73. BIN
      docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/localhost-running.png
  74. BIN
      docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/login-screen.png
  75. BIN
      docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/project-setup.png
  76. BIN
      docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/users-on-dev-extreme.png
  77. BIN
      docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/users.png
  78. 160
      docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md
  79. BIN
      docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/added-new-migration.png
  80. BIN
      docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/custom-identity-user-list.png
  81. BIN
      docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/initial-project.png
  82. BIN
      docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/new-user.png
  83. BIN
      docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/nuget-package-manager.png
  84. BIN
      docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/user-table.png
  85. 35
      docs/en/Customizing-Application-Modules-Overriding-Services.md
  86. 53
      docs/en/Data-Filtering.md
  87. 4
      docs/en/Distributed-Event-Bus-Kafka-Integration.md
  88. 65
      docs/en/Distributed-Event-Bus-Rebus-Integration.md
  89. 7
      docs/en/Distributed-Event-Bus.md
  90. 12
      docs/en/Entity-Framework-Core-SQLite.md
  91. 79
      docs/en/Getting-Started-React-Native.md
  92. 168
      docs/en/Getting-Started.md
  93. 3
      docs/en/JavaScript/Dynamic-JavaScript-API-Clients.md
  94. 100
      docs/en/Localization.md
  95. 117
      docs/en/Migration-Guides/Abp-4_0.md
  96. 14
      docs/en/Migration-Guides/BlazorUI-3_3.md
  97. BIN
      docs/en/Migration-Guides/images/route-4.png
  98. BIN
      docs/en/Migration-Guides/images/route-before-4.png
  99. 4
      docs/en/Module-Development-Basics.md
  100. 2
      docs/en/Modules/Identity.md

1
.github/ISSUE_TEMPLATES/feature.md

@ -0,0 +1 @@
Please describe the feature need!

2
.github/workflows/build-and-test.yml

@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-dotnet@master
with:
dotnet-version: 3.1.102
dotnet-version: 5.0.100-rc.2.20479.15
- name: Build All
run: .\build-all.ps1

71
.github/workflows/codeql-analysis.yml

@ -0,0 +1,71 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"
on:
push:
branches: [dev, rel-1.0, rel-1.1, rel-2.0, rel-2.1, rel-2.2, rel-2.3, rel-2.4, rel-2.5, rel-2.6, rel-2.7, rel-2.8, rel-2.9, rel-3.0, rel-3.1, rel-3.2]
pull_request:
# The branches below must be a subset of the branches above
branches: [dev]
schedule:
- cron: '0 8 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['csharp', 'javascript']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

4
.gitignore

@ -303,4 +303,8 @@ modules/virtual-file-explorer/app/Volo.Abp.VirtualFileExplorer.DemoApp/Logs/
/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/package-lock.json
/templates/app/angular/package-lock.json
/modules/client-simulation/demo/Volo.ClientSimulation.Demo/package-lock.json
abp-build-config.json
/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/Pages/Test/
# Identity Server temp signature file
tempkey.jwk

7
NuGet.Config

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="BlazoriseMyGet" value="https://www.myget.org/F/blazorise/api/v3/index.json" />
</packageSources>
</configuration>

3
abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/zh-Hans.json

@ -8,6 +8,7 @@
"FrameworkDocumentation": "框架文档",
"OfficialBlog": "官方博客",
"CommercialHomePage": "商业版首页",
"CommercialSupportWebSite": "商业版支持网站"
"CommercialSupportWebSite": "商业版支持网站",
"CommunityWebSite": "ABP社区网站"
}
}

43
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ar.json

@ -41,6 +41,16 @@
"ApplicationType": "نوع التطبيق",
"Target": "استهداف",
"TargetFilter": "استهداف",
"ModuleClass": "Module class",
"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": "قاعدة بيانات مونجو",
"Edit": "تعديل",
"Delete": "حذف",
"Refresh": "تحديث",
@ -54,8 +64,8 @@
"CreateAModule": "إنشاء وحدة",
"CreateANugetPackage": "أنشاء حزمة Nuget",
"AddNew": "اضف جديد",
"PackageAlreadyExist{0}": "",
"ModuleAlreadyExist{0}": "",
"PackageAlreadyExist{0}": "حزمة \"{0}\" تمت إضافتها من قبل.",
"ModuleAlreadyExist{0}": "وحدة \"{0}\" مضافة بالفعل.",
"ClearCache": "مسح ذاكرة التخزين المؤقت",
"SuccessfullyCleared": "تم محوه بنجاح",
"Menu:NpmPackages": "حزم NPM",
@ -93,7 +103,7 @@
"MasterModules": "الوحدات الرئيسية",
"OrganizationName": "اسم المنظمة",
"CreationDate": "تاريخ الإنشاء",
"LicenseStart": "تاريخ بدء الرخصة",
"LicenseStartDate": "تاريخ بدء الترخيص",
"LicenseEndDate": "تاريخ إنتهاء الرخصة",
"OrganizationNamePlaceholder": "اسم المنظمة ...",
"TotalQuestionCountPlaceholder": "إجمالي عدد الأسئلة ...",
@ -156,6 +166,31 @@
"TotalQuestionMustBeGreaterWarningMessage": "يجب أن يكون TotalQuestionCount أكبر من RemainingQuestionCount!",
"QuestionCountsMustBeGreaterThanZero": "يجب أن يكون TotalQuestionCount و RemainingQuestionCount صفرًا أو أكبر من الصفر!",
"UnlimitedQuestionCount": "عدد أسئلة غير محدود",
"Notes": "ملاحظات"
"Notes": "ملاحظات",
"Menu:Community": "المجتمع",
"Menu:Articles": "مقالات",
"Wait": "انتظر",
"Approve": "موافقة",
"Reject": "رفض",
"Details": "تفاصيل",
"Url": "عنوان الموقع",
"Title": "عنوان",
"ContentSource": "مصدر المحتوى",
"Status": "الحالة",
"ReadArticle": "إقرأ المقال",
"ArticleHasBeenWaiting": "تم إيقاف المقال",
"ArticleHasBeenApproved": "تم الموافقة على المقال",
"ArticleHasBeenRejected": "تم رفض المقال",
"Permission:Community": "المجتمع",
"Permission:CommunityArticle": "مقال",
"Link": "رابط",
"Enum:ContentSource:0": "Github",
"Enum:ContentSource:1": "خارجى",
"Enum:Status:0": "انتظار",
"Enum:Status:1": "مرفوض",
"Enum:Status:2": "تمت الموافقة",
"Summary": "مُلخص",
"AuthorName": "اسم المؤلف",
"CoverImage": "صورة الغلاف"
}
}

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

@ -3,6 +3,12 @@
"texts": {
"Permission:Organizations": "组织",
"Permission:Manage": "管理组织",
"Permission:DiscountRequests": "折扣请求",
"Permission:DiscountManage": "管理折扣请求",
"Permission:Disable": "禁用",
"Permission:Enable": "启动",
"Permission:EnableSendEmail": "启用发送邮件",
"Permission:SendEmail": "发送邮件",
"Permission:NpmPackages": "NPM包",
"Permission:NugetPackages": "Nuget包",
"Permission:Maintenance": "维护",
@ -13,8 +19,13 @@
"Permission:Edit": "编辑",
"Permission:Delete": "删除",
"Permission:Create": "创建",
"Permission:Accounting": "账单",
"Permission:Accounting:Quotation": "报价",
"Permission:Accounting:Invoice": "发票",
"Menu:Organizations": "组织",
"Menu:Accounting": "账单",
"Menu:Packages": "包",
"Menu:DiscountRequests": "折扣请求",
"NpmPackageDeletionWarningMessage": "该NPM包将会被删除. 你确定吗?",
"NugetPackageDeletionWarningMessage": "该Nuget包将会被删除. 你确定吗?",
"ModuleDeletionWarningMessage": "该模块将会被删除. 你确定吗?",
@ -24,6 +35,7 @@
"NameFilter": "名称",
"CreationTime": "创建时间",
"IsPro": "是否为专业版",
"ShowOnModuleList": "展示模块列表",
"EfCoreConfigureMethodName": "配置方法法",
"IsProFilter": "是否为专业版",
"ApplicationType": "应用程序类型",
@ -53,6 +65,7 @@
"CreateANugetPackage": "创建Nuget包",
"AddNew": "新建",
"PackageAlreadyExist{0}": "\"{0}\"已经被添加.",
"ModuleAlreadyExist{0}": "\"{0}\" 模块已经添加.",
"ClearCache": "清除缓存",
"SuccessfullyCleared": "清除成功",
"Menu:NpmPackages": "NPM包",
@ -63,6 +76,7 @@
"Organizations": "组织",
"LongName": "完整名称",
"LicenseType": "授权类型",
"MissingLicenseTypeField": "许可证类型字段是必需的!",
"LicenseStartTime": "授权开始时间",
"LicenseEndTime": "授权结束时间",
"AllowedDeveloperCount": "允许的开发人员数量",
@ -74,14 +88,112 @@
"AddDeveloper": "添加开发者",
"Create": "创建",
"UserNotFound": "用户不存在",
"{0}WillBeRemovedFromMembers": "{0} 将从成员中删除",
"{0}WillBeRemovedFromDevelopers": "{0} 将从开发者中移除, 你确定吗?",
"{0}WillBeRemovedFromOwners": "{0} 将从所有者中移除, 你确定吗?",
"Computers": "计算机",
"UniqueComputerId": "计算机唯一ID",
"LastSeenDate": "上次查看日期",
"{0}Computer{1}WillBeRemovedFromRecords": "计算机 {0} ({1}) 将从记录中删除",
"OrganizationDeletionWarningMessage": "组织将被删除",
"DeletingLastOwnerWarningMessage": "一个组织必须至少有一个所有者!因此你不能删除此所有者",
"This{0}AlreadyExistInThisOrganization": "该组织中已经存在此 {0}",
"AreYouSureYouWantToDeleteAllComputers": "您确定要删除所有计算机吗?",
"DeleteAll": "删除所有"
"DeleteAll": "删除所有",
"DoYouWantToCreateNewUser": "你想要创建一个新用户吗",
"MasterModules": "主模块",
"OrganizationName": "组织名称",
"CreationDate": "创建时间",
"LicenseStartDate": "许可开始时间",
"LicenseEndDate": "许可结束时间",
"OrganizationNamePlaceholder": "组织名称...",
"TotalQuestionCountPlaceholder": "问题总数...",
"RemainingQuestionCountPlaceholder": "剩下的问题数...",
"LicenseTypePlaceholder": "许可类型...",
"CreationDatePlaceholder": "创建时间...",
"LicenseStartDatePlaceholder": "许可开始时间...",
"LicenseEndDatePlaceholder": "许可结束时间...",
"UsernameOrEmail": "用户名或邮箱",
"UsernameOrEmailPlaceholder": "用户名或邮箱...",
"Member": "成员",
"PurchaseOrderNo": "订单编号",
"QuotationDate": "报价日期",
"CompanyName": "公司名称",
"CompanyAddress": "公司地址",
"Price": "价格",
"DiscountText": "折扣文字",
"DiscountQuantity": "折扣数量",
"DiscountPrice": "折扣价格",
"Quotation": "报价单",
"ExtraText": "额外文字",
"ExtraAmount": "额外金额",
"DownloadQuotation": "下载报价单",
"Invoice": "发票",
"TaxNumber": "税号",
"InvoiceNumber": "发票数字",
"InvoiceDate": "发票日期",
"InvoiceNote": "发票说明",
"Quantity": "数量",
"AddProduct": "添加产品",
"AddProductWarning": "你需要添加产品",
"TotalPrice": "总价",
"Generate": "生成",
"MissingQuantityField": "数量字段为必填项!",
"MissingPriceField": "价格字段为必填项!",
"CodeUsageStatus": "状态",
"Country": "国家",
"DeveloperCount": "开发者数量",
"RequestCode": "请求码",
"WebSite": "网站",
"GithubUsername": "Github用户名",
"PhoneNumber": "手机号",
"ProjectDescription": "产品描述",
"Referrer": "推荐人",
"DiscountRequests": "折扣请求",
"Copylink": "拷贝链接",
"Disable": "禁用",
"Enable": "启用",
"EnableSendEmail": "启用发送邮件",
"SendEmail": "发送邮件",
"SuccessfullyDisabled": "禁用成功",
"SuccessfullyEnabled": "启用成功",
"EmailSent": "邮件发送",
"SuccessfullySent": "发送成功",
"SuccessfullyDeleted": "删除成功",
"DiscountRequestDeletionWarningMessage": "折扣成功将被删除",
"BusinessType": "商业类型",
"TotalQuestionCount": "问题总数",
"RemainingQuestionCount": "剩余问题数",
"TotalQuestionMustBeGreaterWarningMessage": "TotalQuestionCount必须大于RemainingQuestionCount!",
"QuestionCountsMustBeGreaterThanZero": "TotalQuestionCount和RemainingQuestionCount必须为0或大于0",
"UnlimitedQuestionCount": "无限的问题计数",
"Notes": "笔记",
"Menu:Community": "社区",
"Menu:Articles": "文章",
"Wait": "等待",
"Approve": "批准",
"Reject": "拒绝",
"Details": "详情",
"Url": "Url",
"Title": "标题",
"ContentSource": "内容源",
"Status": "状态",
"ReadArticle": "阅读文章",
"ArticleHasBeenWaiting": "文章还在等待",
"ArticleHasBeenApproved": "文章已被批准",
"ArticleHasBeenRejected": "文章已被拒绝",
"Permission:Community": "社区",
"Permission:CommunityArticle": "文字",
"Link": "链接",
"Enum:ContentSource:0": "Github",
"Enum:ContentSource:1": "外部",
"Enum:Status:0": "等待中",
"Enum:Status:1": "已拒绝",
"Enum:Status:2": "已批准",
"Summary": "概要",
"AuthorName": "作者名称",
"CoverImage": "封面图片",
"RemoveCacheConfirmationMessage": "你确定要删除\"{0}\" 文章缓存?",
"SuccessfullyRemoved": "清除成功",
"RemoveCache": "删除缓存"
}
}

31
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/ar.json

@ -0,0 +1,31 @@
{
"culture": "ar",
"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": "لا يمكن أن يكون عدد المطورين المسموح لهم أقل من 0!",
"Volo.AbpIo.Domain:010010": "تم تجاوز الحد الأقصى لعدد عناوين mac!",
"Volo.AbpIo.Domain:010011": "لا يمكن أن تحتوي الرخصة الشخصية على أكثر من مطور واحد!",
"Volo.AbpIo.Domain:010012": "لا يمكن تمديد الترخيص بعد شهر واحد من انتهاء صلاحية الترخيص!",
"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": "GitHub أعطنى تنبيه على",
"Features": "خصائص",
"GetStarted": "دعنا نبدأ",
"Documents": "وثائق",
"Community": "مجتمع",
"ContributionGuide": "دليل المساهمة",
"Blog": "المدونة",
"Commercial": "تجارى",
"SeeDocuments": "انظر للوثائق"
}
}

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

@ -27,6 +27,7 @@
"Blog": "Blog",
"Commercial": "Commercial",
"MyAccount": "My account",
"SeeDocuments": "See Documents"
"SeeDocuments": "See Documents",
"Samples": "Samples"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json

@ -26,6 +26,8 @@
"ContributionGuide": "贡献指南",
"Blog": "博客",
"Commercial": "商业版",
"SeeDocuments": "查看文档"
"MyAccount": "我的账户",
"SeeDocuments": "查看文档",
"Samples": "示例"
}
}

35
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json

@ -0,0 +1,35 @@
{
"culture": "ar",
"texts": {
"OrganizationManagement": "إدارة المنظمة",
"OrganizationList": "قائمة المنظمات",
"Volo.AbpIo.Commercial:010003": "لست مالك هذه المنظمة!",
"OrganizationNotFoundMessage": "لا توجد أى منظمة!",
"DeveloperCount": "المحجوز / إجمالى المطورين",
"QuestionCount": "المتبقى / إجمالى الأسئلة",
"Unlimited": "غير محدود",
"Owners": "مُلاّك",
"AddMember": "تسجيل عضو",
"AddOwner": "تسجيل مالك",
"AddDeveloper": "تسجيل مطور",
"UserName": "اسم المستخدم",
"Name": "الاسم",
"EmailAddress": "البريد الإلكترونى",
"Developers": "مطورون",
"LicenseType": "نوع الرخصة",
"Manage": "إدارة",
"StartDate": "تاريخ البداية",
"EndDate": "تاريخ الإنتهاء",
"Modules": "Modules",
"LicenseExtendMessage": "تم تمديد تاريخ انتهاء الترخيص الخاص بك إلى {0}",
"LicenseUpgradeMessage": "تمت ترقية ترخيصك إلى {0}",
"LicenseAddDeveloperMessage": "تمت إضافة {0} من المطورين إلى ترخيصك",
"Volo.AbpIo.Commercial:010004": "لا يمكن العثور على المستخدم المحدد! يجب أن يكون المستخدم قد سجل بالفعل.",
"MyOrganizations": "منظماتى",
"ApiKey": "مفتاح API",
"UserNameNotFound": "لا يوجد مستخدم باسم {0}",
"SuccessfullyAddedToNewsletter": "شكرا لك على الاشتراك في النشرة الإخبارية لدينا!",
"MyProfile": "ملفي",
"EmailNotValid": "من فضلك أدخل بريد أليكترونى صحيح."
}
}

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

@ -6,6 +6,8 @@
"Volo.AbpIo.Commercial:010003": "你不是该组织的所有者!",
"OrganizationNotFoundMessage": "找不到任何组织!",
"DeveloperCount": "开发者数量",
"QuestionCount": "剩余 / 问题总数",
"Unlimited": "无限制",
"Owners": "所有者",
"AddMember": "添加成员",
"AddOwner": "添加所有者",
@ -25,6 +27,9 @@
"Volo.AbpIo.Commercial:010004": "不能找到指定的用户! 用户必须已经注册.",
"MyOrganizations": "我的组织",
"ApiKey": "API key",
"UserNameNotFound": "没有用户名为{0}的用户"
"UserNameNotFound": "没有用户名为{0}的用户",
"SuccessfullyAddedToNewsletter": "感谢你订阅我们的新闻通讯!",
"MyProfile": "我的资料",
"EmailNotValid": "请输入有效的电子邮件地址"
}
}

68
abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ar.json

@ -0,0 +1,68 @@
{
"culture": "ar",
"texts": {
"Permission:CommunityArticle": "مقالة المجتمع",
"Permission:Edit": "تعديل",
"Waiting": "انتظار",
"Approved": "تمت الموافقة",
"Rejected": "مرفوض",
"Wait": "انتظر",
"Approve": "موافق",
"Reject": "رفض",
"ReadArticle": "إقرأ المقال",
"Status": "الحالة",
"ContentSource": "مصدر المحتوى",
"Details": "التفاصيل",
"Url": "عنوان الموقع",
"Title": "العنوان",
"CreationTime": "وقت الإنشاء",
"Save": "حفظ",
"SameUrlAlreadyExist": "نفس عنوان الموقع موجود بالفعل إذا كنت تريد إضافة هذه المقالة ، يجب عليك تغيير عنوانها!",
"UrlIsNotValid": "عنوان الموقع غير صحيح.",
"UrlNotFound": "عنوان الموقع غير موجود.",
"UrlContentNotFound": "محتوى الموقع غير موجود.",
"Summary": "الخلاصة",
"MostRead": "الأكثر قراءة",
"Latest": "آخر",
"ContributeAbpCommunity": "المساهمة في مجتمع ABP",
"SubmitYourArticle": "إرسال مقالتك",
"ContributionGuide": "دليل المساهمة",
"BugReport": "الإبلاغ عن خطأ",
"SeeAllArticles": "انظر جميع المقالات",
"WelcomeToABPCommunity!": "مرحبًا بك في مجتمع ABP!",
"MyProfile": "ملفى",
"MyOrganizations": "منظماتي",
"EmailNotValid": "من فضلك أدخل بريد أليكترونى صحيح.",
"FeatureRequest": "طلب خاصية جديدة",
"CreateArticleTitleInfo": "عنوان المقال الذي سيظهر في قائمة المقالات.",
"CreateArticleUrlInfo": "الأصل GitHub / عنوان URL خارجي للمقالة.",
"CreateArticleSummaryInfo": "ملخص قصير للمقال ليتم عرضه في قائمة المقالات.",
"CreateArticleCoverInfo": "لإنشاء مقال فعال ، أضف صورة غلاف. لن يتم قبول سوى صور بنسبة عرض إلى ارتفاع تبلغ 9:16!",
"ThisExtensionIsNotAllowed": "امتداد الملف غير مسموح.",
"TheFileIsTooLarge": "مسار الملف طويل جداً",
"GoToTheArticle": "الذهاب للمقال",
"Contribute": "ساهم",
"OverallProgress": "التقدم الكلى",
"Done": "تم",
"Open": "افتح",
"Closed": "أُغلق",
"LatestQuestionOnThe": "آخر سؤال فى",
"Stackoverflow": "Stackoverflow",
"Votes": "تصويتات",
"Answer": "إجابة",
"Views": "مشاهدة",
"Answered": "تمت الإجابة عنه",
"WaitingForYourAnswer": "بانتظار إجابتك",
"Asked": "تم السؤال",
"AllQuestions": "كل الأسئلة",
"NextVersion": "الإصدار القادم",
"MilestoneErrorMessage": "تعذر الحصول على تفاصيل المعالم الحالية من Github.",
"QuestionItemErrorMessage": "تعذر الحصول على أحدث تفاصيل السؤال من Stackoverflow.",
"Oops": "عفواً!",
"CreateArticleSuccessMessage": "تم تقديم المقال بنجاح. سيتم نشره بعد مراجعة من إدارة الموقع.",
"ChooseCoverImage": "اختر صورة الغلاف...",
"CoverImage": "صورة الغلاف",
"ShareYourExperiencesWithTheABPFramework": "شارك خبراتك مع إطار عمل برنامج ABP!",
"Optional": "اختيارى"
}
}

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

@ -82,6 +82,9 @@
"SeeAllAnnouncements": "See All Announcements",
"LatestBlogPost": "Latest Blog Post",
"Edit": "Edit",
"ProfileImageChange": "Change the profile image"
"ProfileImageChange": "Change the profile image",
"BlogItemErrorMessage": "Could not get the latest blog post details from ABP.",
"PlannedReleaseDate": "Planned release date",
"CommunityArticleRequestErrorMessage": "Could not get the latest article request from Github."
}
}

149
abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json

@ -1,64 +1,89 @@
{
"culture": "zh-Hans",
"texts": {
"Permission:CommunityArticle": "社区文章",
"Permission:Edit": "修改",
"Waiting": "等待中",
"Approved": "已批准",
"Rejected": "已拒绝",
"Wait": "等待",
"Approve": "批准",
"Reject": "拒绝",
"ReadArticle": "阅读文章",
"Status": "状态",
"ContentSource": "内容来源",
"Details": "详情",
"Url": "url",
"Title": "标题",
"CreationTime": "创建时间",
"Save": "保存",
"SameUrlAlreadyExist": "url已存在,如果你想要添加这篇文章,你需要更改url!",
"UrlIsNotValid": "Url无效.",
"UrlNotFound" : "Url未找到.",
"UrlContentNotFound": "Url内容未找到.",
"Summary": "摘要",
"MostRead": "阅读最多",
"Latest": "最新",
"ContributeAbpCommunity": "为ABP社区做贡献",
"SubmitYourArticle": "提交你的文章",
"ContributionGuide": "贡献指南",
"BugReport": "Bug报告",
"SeeAllArticles": "查看所有的文章",
"WelcomeToABPCommunity!": "欢迎来到ABP社区!",
"MyProfile": "我的资料",
"MyOrganizations": "我的组织",
"EmailNotValid": "请输入有效的电子邮箱地址.",
"FeatureRequest": "功能请求",
"CreateArticleTitleInfo": "文章标题显示在文章列表中.",
"CreateArticleUrlInfo": "文章的原始GitHub/外部URL.",
"CreateArticleSummaryInfo": "文章的简短摘要将显示在文章列表中.",
"CreateArticleCoverInfo": "为了创建有效的文章,请添加封面图. 仅支持16:9的图片!",
"ThisExtensionIsNotAllowed": "不允许此扩展名.",
"TheFileIsTooLarge": "文件过大.",
"GoToTheArticle": "转到文章",
"Contribute": "贡献",
"OverallProgress": "总体流程",
"Done": "完成",
"Open": "打开",
"Closed": "关闭",
"LatestQuestionOnThe": "有关的最新问题",
"Stackoverflow": "Stackoverflow",
"Votes": "票数",
"Answer": "回答",
"Views": "观看次数",
"Answered": "已回答",
"WaitingForYourAnswer": "等待你的回答",
"Asked": "提问",
"AllQuestions": "所有的问题",
"NextVersion": "下一个版本",
"MilestoneErrorMessage": "无法从Github获取当前的里程碑详细信息.",
"QuestionItemErrorMessage": "无法从Stackoverflow获取最新的问题详细信息.",
"Oops": "哎呀!"
}
"culture": "zh-Hans",
"texts": {
"Permission:CommunityArticle": "社区文章",
"Permission:Edit": "修改",
"Waiting": "等待中",
"Approved": "已批准",
"Rejected": "已拒绝",
"Wait": "等待",
"Approve": "批准",
"Reject": "拒绝",
"ReadArticle": "阅读文章",
"Status": "状态",
"ContentSource": "内容来源",
"Details": "详情",
"Url": "url",
"Title": "标题",
"CreationTime": "创建时间",
"Save": "保存",
"SameUrlAlreadyExist": "url已存在,如果你想要添加这篇文章,你需要更改url!",
"UrlIsNotValid": "Url无效.",
"UrlNotFound": "Url未找到.",
"UrlContentNotFound": "Url内容未找到.",
"Summary": "摘要",
"MostRead": "阅读最多",
"Latest": "最新",
"ContributeAbpCommunity": "为ABP社区做贡献",
"SubmitYourArticle": "提交你的文章",
"ContributionGuide": "贡献指南",
"BugReport": "Bug报告",
"SeeAllArticles": "查看所有的文章",
"WelcomeToABPCommunity!": "欢迎来到ABP社区!",
"MyProfile": "我的资料",
"MyOrganizations": "我的组织",
"EmailNotValid": "请输入有效的电子邮箱地址.",
"FeatureRequest": "功能请求",
"CreateArticleTitleInfo": "文章标题显示在文章列表中.",
"CreateArticleUrlInfo": "文章的原始GitHub/外部URL.",
"CreateArticleSummaryInfo": "文章的简短摘要将显示在文章列表中.",
"CreateArticleCoverInfo": "为了创建有效的文章,请添加封面图. 仅支持16:9的图片!",
"ThisExtensionIsNotAllowed": "不允许此扩展名.",
"TheFileIsTooLarge": "文件过大.",
"GoToTheArticle": "转到文章",
"Contribute": "贡献",
"OverallProgress": "总体流程",
"Done": "完成",
"Open": "打开",
"Closed": "关闭",
"LatestQuestionOnThe": "有关的最新问题",
"Stackoverflow": "Stackoverflow",
"Votes": "票数",
"Answer": "回答",
"Views": "观看次数",
"Answered": "已回答",
"WaitingForYourAnswer": "等待你的回答",
"Asked": "提问",
"AllQuestions": "所有的问题",
"NextVersion": "下一个版本",
"MilestoneErrorMessage": "无法从Github获取当前的里程碑详细信息.",
"QuestionItemErrorMessage": "无法从Stackoverflow获取最新的问题详细信息.",
"Oops": "哎呀!",
"CreateArticleSuccessMessage": "文章提交成功. 网站管理员审核通过后将被发布.",
"ChooseCoverImage": "选项一张封面图片",
"CoverImage": "封面图片",
"ShareYourExperiencesWithTheABPFramework": "分享你的ABP Framework经验!",
"Optional": "可选的",
"UpdateUserWebSiteInfo": "示例: https://johndoe.com",
"UpdateUserTwitterInfo": "示例: johndoe",
"UpdateUserGithubInfo": "示例: johndoe",
"UpdateUserLinkedinInfo": "示例: https://www.linkedin.com/...",
"UpdateUserCompanyInfo": "示例v: Volosoft",
"UpdateUserJobTitleInfo": "示例: Software Developer",
"UserName": "用户名",
"Company": "公司",
"PersonalWebsite": "个人网站",
"RegistrationDate": "注册时间",
"Social": "社交",
"Biography": "传记",
"HasNoPublishedArticlesYet": "尚未发表文章",
"Author": "作者",
"LatestGithubAnnouncements": "最新的Github公告",
"SeeAllAnnouncements": "查看所有公告",
"LatestBlogPost": "最新博客文章",
"Edit": "修改",
"ProfileImageChange": "更改资料图片",
"BlogItemErrorMessage": "无法从ABP获取最新的博客文章详细信息.",
"PlannedReleaseDate": "计划发布日期"
}
}

161
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ar.json

@ -0,0 +1,161 @@
{
"culture": "ar",
"texts": {
"GetStarted": "ابدأ - قوالب بدء التشغيل",
"Create": "إنشاء",
"NewProject": "مشروع جديد",
"DirectDownload": "تحميل مباشر",
"ProjectName": "اسم المشروع",
"ProjectType": "نوع المشروع",
"DatabaseProvider": "مزود قاعدة البيانات",
"NTier": "N- الطبقة",
"IncludeUserInterface": "تشمل واجهة المستخدم",
"CreateNow": "إنشاء جديد",
"TheStartupProject": "مشروع بدء التشغيل",
"Tutorial": "الدورة التعليمية",
"UsingCLI": "باستخدام CLI",
"SeeDetails": "انظر التفاصيل",
"AbpShortDescription": "ABP Framework بنية أساسية كاملة لإنشاء تطبيقات ويب حديثة باتباع أفضل ممارسات واتفاقيات تطوير البرامج.",
"SourceCodeUpper": "شفرة المصدر",
"LatestReleaseLogs": "أحدث سجلات الإصدار",
"Infrastructure": "البنية التحتية",
"Architecture": "الهيكلة",
"Modular": "معياري",
"DontRepeatYourself": "لا تكرر نفسك",
"DeveloperFocused": "تركيز المطور",
"FullStackApplicationInfrastructure": "البنية التحتية الكاملة للتطبيق.",
"DomainDrivenDesign": "Domain Driven Design",
"DomainDrivenDesignExplanation": "تم تصميمه وتطويره بناءً على أنماط ومبادئ DDD. يوفر نموذجًا متعدد الطبقات لتطبيقك.",
"Authorization": "تفويض",
"AuthorizationExplanation": "إذن متقدم مع نظام أذونات مستخدم ودور ودقيق. مبني على مكتبة هوية Microsoft.",
"MultiTenancy": "متعدد الايجار",
"MultiTenancyExplanationShort": "جعلت تطبيقات SaaS سهلة! متعدد الإيجارات المتكاملة من قاعدة البيانات إلى واجهة المستخدم.",
"CrossCuttingConcerns": "اهتمامات مشتركة",
"CrossCuttingConcernsExplanationShort": "بنية تحتية كاملة للتفويض والتحقق من الصحة ومعالجة الاستثناءات والتخزين المؤقت وتسجيل التدقيق وإدارة المعاملات والمزيد.",
"BuiltInBundlingMinification": "تجميع وتصغير مدمج",
"BuiltInBundlingMinificationExplanation": "لا حاجة لاستخدام أدوات خارجية للتجميع والتصغير. تقدم ABP طريقة أبسط وديناميكية وقوية ومتكاملة ومدمجة!",
"VirtualFileSystem": "نظام الملفات الافتراضي",
"VirtualFileSystemExplanation": "قم بتضمين العروض والنصوص والأنماط والصور ... في الحزم / المكتبات وإعادة استخدامها في تطبيقات مختلفة.",
"Theming": "تصميم",
"ThemingExplanationShort": "استخدم وتخصيص سمة واجهة المستخدم القياسية القائمة على التمهيد أو قم بإنشاء سمة خاصة بك.",
"BootstrapTagHelpersDynamicForms": "أدوات مساعدة علامة التمهيد والنماذج الديناميكية",
"BootstrapTagHelpersDynamicFormsExplanation": "بدلاً من كتابة التفاصيل المتكررة لمكونات التمهيد يدويًا ، استخدم مساعدي علامات ABP لتبسيطها والاستفادة من التحسس. أنشئ نماذج واجهة مستخدم بسرعة استنادًا إلى نموذج C # باستخدام مساعد علامة النموذج الديناميكي.",
"HTTPAPIsDynamicProxies": "HTTP APIs & Dynamic Proxies",
"HTTPAPIsDynamicProxiesExplanation": "كشف خدمات التطبيقات تلقائيًا على أنها واجهات برمجة تطبيقات HTTP بنمط REST ، واستهلكها باستخدام وكلاء 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 من خلال اصطلاحات التسمية.",
"ConventionOverConfigurationExplanationList3": "يقوم بإنشاء وكلاء عميل HTTP ديناميكي لـ C # و JavaScript.",
"ConventionOverConfigurationExplanationList4": "يوفر المستودعات الافتراضية للكيانات الخاصة بك.",
"ConventionOverConfigurationExplanationList5": "إدارة وحدة العمل حسب طلب الويب أو طريقة خدمة التطبيق.",
"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": "استكشف ميزات إطار عمل ABP",
"ABPCLI": "ABP CLI",
"Modularity": "النمطية",
"BootstrapTagHelpers": "مساعدي علامة التمهيد",
"DynamicForms": "شاشات ديناميكية",
"BundlingMinification": "التجميع والتصغير",
"BackgroundJobs": "وظائف الخلفية",
"DDDInfrastructure": "البنية التحتية DDD",
"DomainDrivenDesignInfrastructure": "البنية التحتية للتصميم يحركها المجال",
"AutoRESTAPIs": "واجهات برمجة تطبيقات Auto REST",
"DynamicClientProxies": "وكلاء العميل الديناميكي",
"DistributedEventBus": "حافلة الحدث الموزعة",
"DistributedEventBusWithRabbitMQIntegration": "حافلة الحدث الموزعة مع تكامل RabbitMQ",
"TestInfrastructure": "اختبار البنية التحتية",
"AuditLoggingEntityHistories": "سجل التدقيق وتاريخ الكيان",
"ObjectToObjectMapping": "مطابقة كائن إلى كائن",
"EmailSMSAbstractions": "التجريد من البريد الإلكتروني والرسائل النصية القصيرة",
"EmailSMSAbstractionsWithTemplatingSupport": "تجريدات البريد الإلكتروني والرسائل النصية القصيرة مع دعم القوالب",
"Localization": "التعريب",
"SettingManagement": "إدارة الإعدادات",
"ExtensionMethods": "طرق التمديد",
"ExtensionMethodsHelpers": "طرق التمديد والمساعدين",
"AspectOrientedProgramming": "البرمجة الموجهة",
"DependencyInjection": "حقن التبعية",
"DependencyInjectionByConventions": "حقن التبعية بالاتفاقيات",
"ABPCLIExplanation": "ABP CLI (واجهة سطر الأوامر) هي أداة سطر أوامر لإجراء بعض العمليات الشائعة للحلول المستندة إلى ABP.",
"ModularityExplanation": "يوفر ABP بنية أساسية كاملة لبناء وحدات التطبيق الخاصة بك والتي قد تحتوي على كيانات وخدمات وتكامل قواعد البيانات وواجهات برمجة التطبيقات ومكونات واجهة المستخدم وما إلى ذلك ..",
"MultiTenancyExplanation": "لا يدعم إطار عمل ABP تطوير التطبيقات متعددة المستأجرين فحسب ، بل يجعل الكود الخاص بك في الغالب غير مدرك للتعددية المستأجرة.",
"MultiTenancyExplanation2": "يمكن تحديد المستأجر الحالي تلقائيًا ، وعزل بيانات المستأجرين المختلفين عن بعضهم البعض.",
"MultiTenancyExplanation3": "يدعم قاعدة بيانات واحدة وقاعدة بيانات لكل مستأجر ونهج مختلطة.",
"MultiTenancyExplanation4": "أنت تركز على رمز عملك وتدع إطار العمل للتعامل مع عقود الإيجار المتعددة نيابة عنك.",
"BootstrapTagHelpersExplanation": "بدلاً من كتابة التفاصيل المتكررة لمكونات التمهيد يدويًا ، استخدم مساعدي علامات ABP لتبسيطها والاستفادة من التحسس. يمكنك بالتأكيد استخدام Bootstrap متى احتجت إليه.",
"DynamicFormsExplanation": "يمكن لمساعدي النموذج الديناميكي وعلامات الإدخال إنشاء النموذج الكامل من فئة C # كنموذج.",
"AuthenticationAuthorizationExplanation": "خيارات المصادقة والترخيص الغنية المدمجة في ASP.NET Core Identity & IdentityServer4. يوفر نظام إذن موسع ومفصل.",
"CrossCuttingConcernsExplanation": "لا تكرر نفسك لتنفيذ كل هذه الأشياء الشائعة مرارًا وتكرارًا. ركز على رمز عملك ودع برنامج ABP يقوم بأتمتة ذلك من خلال الاتفاقيات.",
"DatabaseConnectionTransactionManagement": "اتصال قاعدة البيانات وإدارة المعاملات",
"CorrelationIdTracking": "تتبع معرف الارتباط",
"BundlingMinificationExplanation": "تقدم ABP نظام تجميع وتقليل بسيط وديناميكي وقوي ونمطي ومدمج.",
"VirtualFileSystemnExplanation": "يتيح نظام الملفات الظاهري إدارة الملفات غير الموجودة فعليًا على نظام الملفات (القرص). يتم استخدامه بشكل أساسي لتضمين ملفات (js ، css ، image ، cshtml ...) في التجميعات واستخدامها مثل الملفات الفعلية في وقت التشغيل.",
"ThemingExplanation": "يسمح نظام Theming بتطوير سمة التطبيق والوحدات النمطية الخاصة بك بشكل مستقل عن طريق تحديد مجموعة من المكتبات الأساسية المشتركة والتخطيطات ، بناءً على أحدث إطار عمل Bootstrap.",
"DomainDrivenDesignInfrastructureExplanation": "بنية تحتية كاملة لإنشاء تطبيقات متعددة الطبقات بناءً على أنماط ومبادئ التصميم المدفوع بالمجال ؛",
"Specification": "تخصيص",
"Repository": "مخزن",
"DomainService": "خدمة المجال",
"ValueObject": "كائن القيمة",
"ApplicationService": "خدمة التطبيق",
"DataTransferObject": "كائن نقل البيانات",
"AggregateRootEntity": "تجميع الجذر والكيان",
"AutoRESTAPIsExplanation": "يمكن لـ ABP تكوين خدمات التطبيقات الخاصة بك تلقائيًا كوحدات تحكم API حسب الاصطلاح.",
"DynamicClientProxiesExplanation": "استهلك واجهات برمجة التطبيقات الخاصة بك بسهولة من عملاء JavaScript و C#.",
"DistributedEventBusWithRabbitMQIntegrationExplanation": "انشر واستهلك الأحداث الموزعة بسهولة باستخدام ناقل الأحداث الموزع المدمج مع توفر تكامل RabbitMQ.",
"TestInfrastructureExplanation": "تم تطوير إطار العمل واختبار الوحدة والتكامل في الاعتبار. يوفر لك الفئات الأساسية لتسهيل الأمر. تأتي قوالب بدء التشغيل مع تكوين مسبق للاختبار.",
"AuditLoggingEntityHistoriesExplanation": "تسجيل تدقيق مدمج للتطبيقات المهمة للأعمال. الطلب والخدمة وتسجيل التدقيق على مستوى الطريقة وتاريخ الكيان مع تفاصيل مستوى الملكية.",
"EmailSMSAbstractionsWithTemplatingSupportExplanation": "تفصل تجريدات IEmailSender و ISmsSender منطق التطبيق الخاص بك عن البنية التحتية. يسمح نظام قوالب البريد الإلكتروني المتقدم بإنشاء قوالب البريد الإلكتروني وتعريبها واستخدامها بسهولة عند الحاجة.",
"LocalizationExplanation": "يسمح نظام التعريب بإنشاء موارد في ملفات JSON عادية واستخدامها لتعريب واجهة المستخدم الخاصة بك. وهو يدعم السيناريوهات المتقدمة مثل الوراثة والإضافات وتكامل JavaScript بينما يتوافق تمامًا مع نظام توطين AspNet Core.",
"SettingManagementExplanation": "حدد إعدادات التطبيق الخاص بك واحصل على القيم في وقت التشغيل بناءً على التكوين الحالي والمستأجر والمستخدم.",
"ExtensionMethodsHelpersExplanation": "لا تكرر نفسك حتى مع أجزاء التعليمات البرمجية البسيطة. الإضافات والمساعدات للأنواع القياسية تجعل التعليمات البرمجية أكثر وضوحًا وسهولة في الكتابة.",
"AspectOrientedProgrammingExplanation": "يوفر بنية تحتية مريحة لإنشاء وكلاء ديناميكيين وتنفيذ البرمجة الموجهة نحو الجانب. اعترض أي فئة وقم بتنفيذ التعليمات البرمجية الخاصة بك قبل وبعد تنفيذ كل طريقة.",
"DependencyInjectionByConventionsExplanation": "لا حاجة لتسجيل فصولك في حقن التبعية يدويًا. يسجل تلقائيًا أنواع الخدمات الشائعة حسب الاصطلاح. بالنسبة لأنواع الخدمات الأخرى ، يمكنك استخدام الواجهات والسمات لتسهيل الأمر ووضعه في مكانه.",
"DataFilteringExplanation": "تحديد واستخدام عوامل تصفية البيانات التي يتم تطبيقها تلقائيًا عند الاستعلام عن الكيانات من قاعدة البيانات. يتم توفير مرشحات Soft Delete & MultiTenant خارج الصندوق عند تنفيذ واجهات بسيطة.",
"PublishEvents": "نشر الأحداث",
"HandleEvents": "معالجة الأحداث",
"AndMore": "وأكثر من ذلك ...",
"Code": "شفرة",
"Result": "النتيجة",
"SeeTheDocumentForMoreInformation": "راجع الـ <a href=\"{1}\">{0} الوثيقة</a> لمزيد من المعلومات",
"IndexPageHeroSection": "<span class=\"first-line shine\"><strong>فتح المصدر</strong></span><span class=\"second-line text-uppercase\">تطبيق الويب<br />إطار </span><span class=\"third-line shine2\"><strong>لـ asp.net core</strong></span>",
"UiFramework": "إطار عمل واجهة المستخدم",
"EmailAddress": "البريد الإلكترونى",
"Mobile": "المحمول",
"ReactNative": "React Native"
}
}

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

@ -93,6 +93,7 @@
"DynamicForms": "Dynamic Forms",
"BundlingMinification": "Bundling & Minification",
"BackgroundJobs": "Background Jobs",
"BackgroundJobsExplanation": "Define simple classes to execute jobs in background as queued. Use built-in job manager or integrate your own. <a href=\"{0}\">Hangfire</a> & <a href=\"{1}\">RabbitMQ</a> integrations are already available.",
"DDDInfrastructure": "DDD Infrastructure",
"DomainDrivenDesignInfrastructure": "Domain Driven Design Infrastructure",
"AutoRESTAPIs": "Auto REST APIs",
@ -102,6 +103,7 @@
"TestInfrastructure": "Test Infrastructure",
"AuditLoggingEntityHistories": "Audit Logging & Entity Histories",
"ObjectToObjectMapping": "Object to Object Mapping",
"ObjectToObjectMappingExplanation": "<a href=\"{0}\">Object to object mapping</a> abstraction with AutoMapper integration.",
"EmailSMSAbstractions": "Email & SMS Abstractions",
"EmailSMSAbstractionsWithTemplatingSupport": "Email & SMS Abstractions with Templating Support",
"Localization": "Localization",
@ -156,6 +158,32 @@
"UiFramework": "UI Framework",
"EmailAddress": "Email address",
"Mobile": "Mobile",
"ReactNative": "React Native"
"ReactNative": "React Native",
"Strong": "Strong",
"Complete": "Complete",
"BasedLayeringModel": "Based Layering Model",
"Microservice": "Microservice",
"Compatible": "Compatible",
"MeeTTheABPCommunityInfo": "Our mission is to create an environment where developers can help each other with articles, tutorials, case studies, etc. and meet like-minded people.",
"JoinTheABPCommunityInfo": "Get involved with a vibrant community and become a contributor to the ABP Framework!",
"AllArticles": "All Articles",
"SubmitYourArticle": "Submit Your Article",
"DynamicClientProxyDocument": "See the dynamic client proxy documentations for <a href=\"{0}\">JavaScript</a> & <a href=\"{1}\">C#</a>.",
"EmailSMSAbstractionsDocument": "See the <a href=\"{0}\">emailing</a> and <a href=\"{1}\">SMS sending</a> documents for more information.",
"CreateProjectWizard": "This wizard creates a new project from the startup template which is properly configured to jump start to your project.",
"TieredOption": "Creates a tiered solution where Web and Http API layers are physically separated. If not checked, creates a layered solution which is less complex and suitable for most scenarios.",
"SeparateIdentityServerOption": "Separates server side into two applications: First one is for the identity server and the second one is for your server side HTTP API.",
"UseslatestPreVersion": "Uses latest pre-release version",
"ReadTheDocumentation": "<span class=\"text-primary\">Read</span><span class=\"text-success\">The Documentation</span>",
"Documentation": "Documentation",
"GettingStartedTutorial": "Getting Started Tutorial",
"ApplicationDevelopmentTutorial": "Application Development Tutorial",
"TheStartupTemplate": "The Startup Template",
"InstallABPCLIInfo": "ABP CLI is the fastest way to start a new solution with the ABP framework. Install the ABP CLI using a command line window:",
"DifferentLevelOfNamespaces": "You can use different level of namespaces; e.g. BookStore, Acme.BookStore or Acme.Retail.BookStore.",
"ABPCLIExamplesInfo": "<strong>new</strong> command creates a <strong>layered MVC application</strong> with <strong>Entity Framework Core</strong> as the database provider. However, it has additional options. Examples:",
"SeeCliDocumentForMoreInformation": "See the <a href=\"{0}\">ABP CLI document</a> for more options or select the \"Direct Download\" tab above.",
"Optional": "Optional",
"LocalFrameworkRef": "Keep local project reference for the framework packages."
}
}

36
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json

@ -89,10 +89,11 @@
"Features": "功能",
"ABPCLI": "ABP CLI",
"Modularity": "模块化",
"BootstrapTagHelpers": "Bootstrap Tag Helpers",
"BootstrapTagHelpers": "Bootstrap 标签助手",
"DynamicForms": "动态表单",
"BundlingMinification": "Bundling & Minification",
"BackgroundJobs": "后台作业",
"BackgroundJobsExplanation": "定义简单的类以在队列中在后台执行作业. 使用内置的作业管理器或集成你自己的作业管理器. <a href=\"{0}\">Hangfire</a> & <a href=\"{1}\">RabbitMQ</a>集成已经可用.",
"DDDInfrastructure": "DDD基础设施",
"DomainDrivenDesignInfrastructure": "Domain Driven Design基础设施",
"AutoRESTAPIs": "自动REST APIs",
@ -102,6 +103,7 @@
"TestInfrastructure": "测试基础设施",
"AuditLoggingEntityHistories": "审计日志和实体历史",
"ObjectToObjectMapping": "对象映射",
"ObjectToObjectMappingExplanation": "<a href=\"{0}\">对象到对象映射</a> 抽象AutoMapper集成.",
"EmailSMSAbstractions": "电子邮件和短信抽象",
"EmailSMSAbstractionsWithTemplatingSupport": "具有模板支持的电子邮件和短信抽象",
"Localization": "本土化",
@ -112,7 +114,7 @@
"DependencyInjection": "依赖注入",
"DependencyInjectionByConventions": "依据约定的依赖注入",
"ABPCLIExplanation": "ABP CLI(命令行界面)是用于对ABP解决方案执行常见操作的命令行工具.",
"ModularityExplanation": "ABP提供了一个完整的基础设施来构建你自己的应用程序模块,这些模块可能具有实体,服务,数据库集成,API,UI组件等.", //TODO: strong "your own application modules",-
"ModularityExplanation": "ABP提供了一个完整的基础设施来构建你自己的应用程序模块,这些模块可能具有实体,服务,数据库集成,API,UI组件等.",
"MultiTenancyExplanation": "ABP框架不仅支持开发多租户应用程序,而且使你的代码几乎无需知道多租户.",
"MultiTenancyExplanation2": "可以自动确定当前租户,将不同租户的数据相互隔离.",
"MultiTenancyExplanation3": "支持单一数据库,或每个租户单独数据库或者混合方式.",
@ -154,6 +156,34 @@
"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": "电子邮件地址"
"EmailAddress": "电子邮件地址",
"Mobile": "移动",
"ReactNative": "React Native",
"Strong": "强大的",
"Complete": "完整的",
"BasedLayeringModel": "基于分层模型",
"Microservice": "微服务",
"Compatible": "兼容",
"MeeTTheABPCommunityInfo": "我们的使命是创建一个环境使开发人员可以在文章,教程,案例研究等方面互相帮助并结识志趣相投的人.",
"JoinTheABPCommunityInfo": "参与充满活力的社区并成为ABP框架的贡献者",
"AllArticles": "所有的文章",
"SubmitYourArticle": "提交你的文章",
"DynamicClientProxyDocument": "参阅<a href=\"{0}\">JavaScript</a> & <a href=\"{1}\">C#</a>的动态客户端代理文档.",
"EmailSMSAbstractionsDocument": "参阅<a href=\"{0}\">emailing</a> 和 <a href=\"{1}\">SMS sending</a> 文档获得更多信息.",
"CreateProjectWizard": "此向导让你从启动模板创建一个新项目,该启动模板已正确配置为可以快速启动你的项目.",
"TieredOption": "创建一个分层解决方案,其中Web和Http API层在物理上是分离的. 如果没有选中则创建一个不那么复杂且适合大多数场景的分层解决方案.",
"SeparateIdentityServerOption": "将服务器端分离为两个应用程序:第一个应用程序用于身份服务器,第二个应用程序用于服务器端HTTP API.",
"UseslatestPreVersion": "使用最新的预发布版本",
"ReadTheDocumentation": "<span class=\"text-primary\">阅读</span><span class=\"text-success\">文档</span>",
"Documentation": "文档",
"GettingStartedTutorial": "入门教程",
"ApplicationDevelopmentTutorial": "应用程序开发教程",
"TheStartupTemplate": "启动模板",
"InstallABPCLIInfo": "ABP CLI是使用ABP框架启动新解决方案的最快方式. 使用命令行窗口安装ABP CLI:",
"DifferentLevelOfNamespaces": "你可以使用不同级别的名称空间. 例如 BookStore, Acme.BookStore 或 Acme.Retail.BookStore",
"ABPCLIExamplesInfo": "<strong>new</strong>命令创建一个 <strong>分层的MVC应用程序</strong> 使用 <strong>Entity Framework Core</strong> 做为数据库提供程序. 它还有其他选项. 示例:",
"SeeCliDocumentForMoreInformation": "参阅 <a href=\"{0}\">ABP CLI 文档</a> 获得更多选项或选择上方的 \"直接下载\" 标签.",
"Optional": "可选的",
"LocalFrameworkRef": "保留框架包的本地项目引用."
}
}

6
build/common.ps1

@ -16,7 +16,9 @@ $solutionPaths = @(
"../modules/tenant-management",
"../modules/audit-logging",
"../modules/background-jobs",
"../modules/account"
"../modules/account",
"../modules/cms-kit",
"../modules/blob-storing-database"
)
if ($full -eq "-f")
@ -29,6 +31,8 @@ if ($full -eq "-f")
"../modules/blogging",
"../templates/module/aspnet-core",
"../templates/app/aspnet-core",
"../templates/console",
"../templates/wpf",
"../abp_io/AbpIoLocalization"
)
}else{

6
common.props

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

15
docs/en/.vscode/settings.json

@ -0,0 +1,15 @@
{
"grammarly.userWords": [
"api",
"apiName",
"cli",
"defaultProject",
"formatter",
"md",
"monorepo",
"ngsw",
"npx",
"pwa",
"rootNamespace"
]
}

35
docs/en/API/Auto-API-Controllers.md

@ -75,17 +75,48 @@ Configure<AbpAspNetCoreMvcOptions>(options =>
Then the route for getting a book will be '**/api/volosoft/book-store/book/{id}**'. This sample uses two-level root path, but you generally use a single level depth.
* Continues with the **normalized controller/service name**. Normalization removes 'AppService', 'ApplicationService' and 'Service' postfixes and converts it to **camelCase**. If your application service class name is 'BookAppService' then it becomes only '/book'.
* Continues with the **normalized controller/service name**. Normalization removes 'AppService', 'ApplicationService' and 'Service' postfixes and converts it to **kebab-case**. If your application service class name is 'ReadingBookAppService' then it becomes only '/reading-book'.
* If you want to customize naming, then set the `UrlControllerNameNormalizer` option. It's a func delegate which allows you to determine the name per controller/service.
* If the method has an '**id**' parameter then it adds '**/{id}**' ro the route.
* Then it adds the action name if necessary. Action name is obtained from the method name on the service and normalized by;
* Removing '**Async**' postfix. If the method name is 'GetPhonesAsync' then it becomes 'GetPhones'.
* Removing **HTTP method prefix**. 'GetList', 'GetAll', 'Get', 'Put', 'Update', 'Delete', 'Remove', 'Create', 'Add', 'Insert', 'Post' and 'Patch' prefixes are removed based on the selected HTTP method. So, 'GetPhones' becomes 'Phones' since 'Get' prefix is a duplicate for a GET request.
* Converting the result to **camelCase**.
* Converting the result to **kebab-case**.
* If the resulting action name is **empty** then it's not added to the route. If it's not empty, it's added to the route (like '/phones'). For 'GetAllAsync' method name it will be empty, for 'GetPhonesAsync' method name it will be 'phones'.
* Normalization can be customized by setting the `UrlActionNameNormalizer` option. It's an action delegate that is called for every method.
* If there is another parameter with 'Id' postfix, then it's also added to the route as the final route segment (like '/phoneId').
#### Customizing the Route Calculation
`IConventionalRouteBuilder` is used to build the route. It is implemented by the `ConventionalRouteBuilder` by default and works as explained above. You can replace/override this service to customize the route calculation strategy.
#### Version 3.x Style Route Calculation
The route calculation was different before the version 4.0. It was using camelCase conventions, while the ABP Framework version 4.0+ uses kebab-case. If you use the old route calculation strategy, follow one of the approaches;
* Set `UseV3UrlStyle` to `true` in the options of the `options.ConventionalControllers.Create(...)` method. Example:
````csharp
options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.UseV3UrlStyle = true;
});
````
This approach effects only the controllers for the `BookStoreApplicationModule`.
* Set `UseV3UrlStyle` to `true` for the `AbpConventionalControllerOptions` to set it globally. Example:
```csharp
Configure<AbpConventionalControllerOptions>(options =>
{
options.UseV3UrlStyle = true;
});
```
Setting it globally effects all the modules in a modular application.
## Service Selection
Creating conventional HTTP API controllers are not unique to application services actually.

2
docs/en/API/Dynamic-CSharp-API-Clients.md

@ -162,4 +162,4 @@ context.Services.AddHttpClientProxies(
Using `asDefaultServices: false` may only be needed if your application has already an implementation of the service and you do not want to override/replace the other implementation by your client proxy.
> If you disable `asDefaultServices`, you can only use `IHttpClientProxy<T>` interface to use the client proxies (see the related section above).
> If you disable `asDefaultServices`, you can only use `IHttpClientProxy<T>` interface to use the client proxies. See the *IHttpClientProxy Interface* section above.

62
docs/en/Application-Services.md

@ -445,6 +445,68 @@ These methods are used to convert Entities to DTOs and vice verse. They uses the
* `MapToEntityAsync(TCreateInput)` is used to create an entity from `TCreateInput`.
* `MapToEntityAsync(TUpdateInput, TEntity)` is used to update an existing entity from `TUpdateInput`.
## Miscellaneous
### Working with Streams
`Stream` object itself is not serializable. So, you may have problems if you directly use `Stream` as the parameter or the return value for your application service. ABP Framework provides a special type, `IRemoteStreamContent` to be used to get or return streams in the application services.
**Example: Application Service Interface that can be used to get and return streams**
````csharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Content;
namespace MyProject.Test
{
public interface ITestAppService : IApplicationService
{
Task Upload(Guid id, IRemoteStreamContent streamContent);
Task<IRemoteStreamContent> Download(Guid id);
}
}
````
**Example: Application Service Implementation that can be used to get and return streams**
````csharp
using System;
using System.IO;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Content;
namespace MyProject.Test
{
public class TestAppService : ApplicationService, ITestAppService
{
public Task<IRemoteStreamContent> Download(Guid id)
{
var fs = new FileStream("C:\\Temp\\" + id + ".blob", FileMode.OpenOrCreate);
return Task.FromResult(
(IRemoteStreamContent) new RemoteStreamContent(fs) {
ContentType = "application/octet-stream"
}
);
}
public async Task Upload(Guid id, IRemoteStreamContent streamContent)
{
using (var fs = new FileStream("C:\\Temp\\" + id + ".blob", FileMode.Create))
{
await streamContent.GetStream().CopyToAsync(fs);
await fs.FlushAsync();
}
}
}
}
````
`IRemoteStreamContent` is compatible with the [Auto API Controller](API/Auto-API-Controllers.md) and [Dynamic C# HTTP Proxy](API/Dynamic-CSharp-API-Clients.md) systems.
## Lifetime
Lifetime of application services are [transient](Dependency-Injection.md) and they are automatically registered to the dependency injection system.

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

@ -364,9 +364,9 @@ ABP Framework doesn't have the same service. Instead, use `ICurrentUser` and `IC
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
#### AbpAuthorize vs Authorize
Use the standard `[Autorize]` and `[AllowAnonymous]` attributes instead of ASP.NET Boilerplate's custom `[AbpAutorize]` and `[AbpAllowAnonymous]` attributes.
Use the standard `[Authorize]` and `[AllowAnonymous]` attributes instead of ASP.NET Boilerplate's custom `[AbpAuthorize]` and `[AbpAllowAnonymous]` attributes.
#### IPermissionChecker vs IAuthorizationService
@ -672,9 +672,9 @@ 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.
In ASP.NET Boilerplate 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.
In 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:

5
docs/en/Best-Practices/Application-Services.md

@ -213,6 +213,11 @@ This method votes a question and returns the current score of the question.
* **Do** always get all the related entities from repositories to perform the operations on them.
* **Do** call repository's Update/UpdateAsync method after updating an entity. Because, not all database APIs support change tracking & auto update.
#### Handle files
* **Do not** use any web components like `IFormFile` or `Stream` in the application services. If you want to serve a file you can use `byte[]`.
* **Do** use a `Controller` to handle file uploading then pass the `byte[]` of the file to the application service method.
#### Using Other Application Services
* **Do not** use other application services of the same module/application. Instead;

2
docs/en/Blob-Storing.md

@ -20,7 +20,7 @@ The ABP Framework has already the following storage provider implementations;
* [Database](Blob-Storing-Database.md): Stores BLOBs in a database.
* [Azure](Blob-Storing-Azure.md): Stores BLOBs on the [Azure BLOB storage](https://azure.microsoft.com/en-us/services/storage/blobs/).
* [Aliyun](Blob-Storing-Aliyun.md): Stores BLOBs on the [Aliyun Storage Service](https://help.aliyun.com/product/31815.html).
* [Ninio](Blob-Storing-Minio.md): Stores BLOBs on the [MinIO Object storage](https://min.io/).
* [Minio](Blob-Storing-Minio.md): Stores BLOBs on the [MinIO Object storage](https://min.io/).
* [Aws](Blob-Storing-Aws.md): Stores BLOBs on the[Amazon Simple Storage Service](https://min.io/).
More providers will be implemented by the time. You can [request](https://github.com/abpframework/abp/issues/new) it for your favorite provider or [create it yourself](Blob-Storing-Custom-Provider.md) and [contribute](Contribution/Index.md) to the ABP Framework.

262
docs/en/Blog-Posts/2020-09-17 v3_2_Preview/POST.md

@ -0,0 +1,262 @@
# ABP Framework & ABP Commercial 3.2 RC With The New Blazor UI
We are extremely excited today to release the [ABP Framework](https://abp.io/) Release Candidate (and the [ABP Commercial](https://commercial.abp.io/), as always). This release includes an early preview version of the **Blazor UI** for the ABP.IO Platform.
## The Blazor UI
While the Blazor UI **should be considered as experimental** for now, it is possible to start to develop your application today.
### Fundamental Services
Currently, implemented some important framework features;
* **Authentication** through the MVC backend using the OpenId Connect authorization code flow. So, all the current login options (login, register, forgot password, external/social logins...) are supported.
* **Authorization**, using the ABP Framework **permissions** as well as the standard authorization system.
* **Localization** just works like the MVC UI.
* **Basic Theme** with top main menu.
* **Dynamic C# HTTP API proxies**, so you can directly consume your backend API by injecting the application service interfaces.
* Some other **fundamental services** like `ISettingProvider`, `IFeatureChecker`, `ICurrentUser`...
Also, the standard .net services are already available, like caching, logging, validation and much more. Since the ABP Framework is layered itself, all the non MVC UI related features are already usable for the Blazor UI.
### Pre-Built Modules
Some modules have been implemented;
* **Identity** module is pre-installed and provides **user, role and permission management**.
* **Profile management** page is implemented to allow to change password and personal settings.
### About the Blazorise Library
We've selected the [Blazorise](https://blazorise.com/) as a fundamental UI library for the Blazor UI. It already supports different HTML/CSS frameworks (like Bootstrap, Bulma, Ant Design...) and significantly increases the developer productivity.
![blazorise-github](blazorise-github.png)
We also have a good news: **[Mladen Macanović](https://github.com/stsrki)**, the creator of the Blazorise, is **joining to the core ABP Framework team** in the next weeks. We are excited to work with him to bring the power of these two successful projects together.
### The Tutorial
We've **updated** the [web application development tutorial](https://docs.abp.io/en/abp/3.2/Tutorials/Part-1?UI=Blazor) for the **Blazor UI**. You can start to develop applications today! The **source code** of the BookStore application developed with this tutorial is [here](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore).
### Get started with the Blazor UI
If you want to try the Blazor UI today, follow the instructions below.
#### Upgrade the ABP CLI
Install the latest [ABP CLI](https://docs.abp.io/en/abp/3.2/CLI) preview version:
````bash
dotnet tool update Volo.Abp.Cli -g --version 3.2.0-rc.2
````
#### Create a new Solution
Then you can create a new solution using the *abp new* command:
````bash
abp new AbpBlazorDemo -u blazor --preview
````
Also specify the `-t app-pro` parameter if you are an ABP Commercial user.
> See the ABP CLI documentation for the additional options, like MongoDB database or separated authentication server.
#### Open the Solution
Open the generated solution using the latest Visual Studio 2019. You will see a solution structure like the picture below:
![visual-studio-solution-with-blazor](visual-studio-solution-with-blazor.png)
#### Run the Application
* Run the `DbMigrator` project to create the database and seed the initial data.
* Run the `HttpApi.Host` project for the server side.
* Run the `Blazor` project to start the Blazor UI.
Use `admin` as the username and `1q2w3E*` as the password to login to the application.
Here, a screenshot from the role management page of the Blazor UI:
![blazor-role-management](blazor-role-management.png)
## What's New with the ABP Framework 3.2
Beside the Blazor UI, there are a lot of issues have been closed with [the milestone 3.2](https://github.com/abpframework/abp/milestone/39?closed=1). I will highlight some of the major features and changes released with this version.
### MongoDB ACID Transactions
[MongoDB integration](https://docs.abp.io/en/abp/3.2/MongoDB) now supports multi-document transactions that comes with the MongoDB 4.x.
We've **disabled transactions** for solutions use the MongoDB, inside the `YourProjectMongoDbModule.cs` file in the MongoDB project. If your MongoDB server **supports transactions**, you should manually enable it in this class:
```csharp
Configure<AbpUnitOfWorkDefaultOptions>(options =>
{
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Auto;
});
```
> Or you can delete this code since this is already the default behavior.
#### Upgrade Notes
If you are upgrading an existing solution and your MongoDB server doesn't support transactions, please disable it:
```csharp
Configure<AbpUnitOfWorkDefaultOptions>(options =>
{
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled;
});
```
See the [Unit Of Work document](https://docs.abp.io/en/abp/3.2/Unit-Of-Work) to learn more about UOW and transactions.
Also, add [this file](https://github.com/abpframework/abp/blob/rel-3.2/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MongoDb/MongoDbMyProjectNameDbSchemaMigrator.cs) into your MongoDB project (remember to change `MongoDbMyProjectNameDbSchemaMigrator` and `IMyProjectNameDbSchemaMigrator` with your own project name).
#### Integration Tests
> Transactions are also **disabled for automated integration tests** coming with the application startup template, since the [Mongo2Go](https://github.com/Mongo2Go/Mongo2Go) library (we use in the test projects) has a problem with the transactions. We've sent a [Pull Request](https://github.com/Mongo2Go/Mongo2Go/pull/101) to fix it and will enable the transactions again when they merge & release it.
>
> If you are upgrading an existing solution and using MongoDB, please disable transactions for the test projects just as described above.
### Kafka Integration for the Distributed Event Bus
ABP Framework's [distributed event system](https://docs.abp.io/en/abp/3.2/Distributed-Event-Bus) has been [integrated to RabbitMQ](https://docs.abp.io/en/abp/3.2/Distributed-Event-Bus-RabbitMQ-Integration) before. By the version 3.2, it has a Kafka integration package, named [Volo.Abp.EventBus.Kafka](https://www.nuget.org/packages/Volo.Abp.EventBus.Kafka).
See the [Kafka integration documentation](https://docs.abp.io/en/abp/3.2/Distributed-Event-Bus-Kafka-Integration) to learn how to install and configure it.
### Host Features
[ABP Feature System](https://docs.abp.io/en/abp/3.2/Features) allows you to define features in your application. Then you can enable/disable a feature dynamically on the runtime. It is generally used in a [multi-tenant](https://docs.abp.io/en/abp/3.2/Multi-Tenancy) system to restrict features for tenants, so you can charge extra money for some features in a SaaS application.
In some cases, you may want to use the same features in the host side (host is you as you are managing the tenants). For this case, we've added a "**Manage Host Features**" button to the Tenant Management page so you can open a modal dialog to select the features for the host side.
![host-features](host-features.png)
### AbpHttpClientBuilderOptions
ABP Framework provides a system to dynamically create C# proxies to consume HTTP APIs from your client applications. `AbpHttpClientBuilderOptions` is a new option class to configure the `HttpClient`s used by the proxy system.
**Example: Use the [Polly](https://github.com/App-vNext/Polly) library to retry up to 3 times for a failed HTTP request**
````csharp
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<AbpHttpClientBuilderOptions>(options =>
{
options.ProxyClientBuildActions.Add((remoteServiceName, clientBuilder) =>
{
clientBuilder.AddTransientHttpErrorPolicy(policyBuilder =>
policyBuilder.WaitAndRetryAsync(
3,
i => TimeSpan.FromSeconds(Math.Pow(2, i))
)
);
});
});
}
````
See the issue [#5304](https://github.com/abpframework/abp/issues/5304) for the details.
### ABP Build Command
We are using **mono repository** approach and the [abp repository](https://github.com/abpframework/abp) has tens of solutions and hundreds of projects (the framework, modules, tooling, templates...) with all of them are referencing to each other.
It gets a significant time to build the whole repository for every Git push. To **optimize** this process, we've created the **abp build** command in the [ABP CLI](https://docs.abp.io/en/abp/3.2/CLI):
````bash
abp build
````
We will use this command to build the abp repository or a solution inside it. However it is available to everyone in case of need.
> **Most of the people will not need it**. If you need it, see the [ABP CLI](https://docs.abp.io/en/abp/3.2/CLI) document to learn all the details and options.
### Other Features, Improvements and Changes
* Introduced the `DynamicRangeAttribute` that can be used to determine the range values on runtime, just like the `DynamicStringLengthAttribute` was introduced before.
* Improved the feature management modal for multi-tenant applications to group features on the UI and show hierarchically.
* Added `--skip-cli-version-check` option to ABP CLI to improve the performance by bypassing the online version check.
* Angular UI now redirect to MVC UI (the authentication server side) for profile management page, if the authorization code flow is used (which is the default).
* Account module profile management page is now extensible. You can implement the `IProfileManagementPageContributor` interface and register it using the `ProfileManagementPageOptions` class.
* Improvements and optimizations for the [Angular service proxy generation](https://blog.abp.io/abp/Introducing-the-Angular-Service-Proxy-Generation).
And a lot of minor improvements and bug fixes. You can see [the milestone 3.2](https://github.com/abpframework/abp/milestone/39?closed=1) for all issues & PRs closed with this version.
## What's New with the ABP Commercial 3.2
### Breaking Changes
The new *profile picture management* feature uses the [BLOB storing](https://docs.abp.io/en/abp/3.2/Blob-Storing) system, so it needs a Storage Provider. The new **startup template comes with the [Database BLOB Provider](https://docs.abp.io/en/abp/3.2/Blob-Storing-Database) pre-installed**. You can change it if you want to use another BLOB provider (like Azure, AWS or a simple file system).
**Existing solutions must configure a BLOB provider** after upgrading to the version 3.2. Follow the [BLOB Storing document](https://docs.abp.io/en/abp/3.2/Blob-Storing#blob-storage-providers) to configure the provider yourself.
### The Blazor UI
The **experimental** Blazor UI is also available for the ABP Commercial. The [Lepton Theme](https://commercial.abp.io/themes) hasn't been implemented with this initial preview, however we are working on it with the highest priority.
You can use the [ABP Suite](https://docs.abp.io/en/commercial/latest/abp-suite/index) or the following ABP CLI command to create a new solution with the Blazor UI:
````bash
abp new AbpBlazorDemo -u blazor -t app-pro --preview
````
Please try it and provide feedback to us. Thanks in advance.
> See the instructions in the *Get started with the Blazor UI* section above to properly create and run your application.
### File Management Angular UI
Angular UI for the [File Management](https://commercial.abp.io/modules/Volo.FileManagement) module is available with the version 3.2. You can add it to your solution using the ABP Suite.
![file-management-module-angular](file-management-module-angular.png)
### Profile Picture Management
We've added profile picture management for the account module, so a user can select one of the options below for her profile picture;
* Use the default placeholder as the avatar.
* Use [Gravatar](https://gravatar.com/) service to get the picture matching the email address of the user.
* Upload a file as the profile picture.
![account-profile-picture](account-profile-picture.jpg)
### Two Factor Authentication Features
Created [features](https://docs.abp.io/en/abp/3.2/Features) and [settings](https://docs.abp.io/en/abp/3.2/Settings) to disable, enable or force to use 2FA on login for the tenants and users.
### Upgrading the ABP Suite
You can use the following command to upgrade the ABP Suite to the latest preview version:
````
abp suite update --preview
````
## Other News
### The ABP Community
**ABP Community** web site is constantly being improved and new articles are added. We will add "**commenting**" and "**rating**" features to the articles soon to increase the interactivity between the people.
![abp-community-20200917](abp-community-20200917.png)
If you have something to share with the ABP community or want to follow the project progress, please check the **[community.abp.io](https://community.abp.io/)**!
### CMS Kit Project
We are silently working on a project, named [CMS Kit](https://github.com/abpframework/abp/tree/dev/modules/cms-kit), for a few months. CMS Kit is a set of reusable CMS (Content Management System) components based on the ABP Framework. Some of the components currently being developed:
* **Comments**; Allows users to comment under something (a blog post, a document, an image... etc).
* **Reactions**; Allows users to give reactions to something (a comment, a picture... etc.) using simple emoji icons.
* **Rating**; Allows users to rate some content from 1 to 5.
* **Newsletter**; Allows you to put a newsletter box to your web site to collect emails from users.
* **Contact**; Put a form to get message from the web site visitors.
There are more planned components like articles, tags, votes, favorites, portfolio, image gallery, FAQ... etc. We will document and deploy these components when they get matured and ready to use. Some of them will be open source & free while some of them are paid (included in the [ABP Commercial](https://commercial.abp.io/) license).
## Feedback
Please try the ABP Framework 3.2.0 RC and [provide feedback](https://github.com/abpframework/abp/issues/new) to help us to release a more stable version. The planned release date for the [3.2.0 final](https://github.com/abpframework/abp/milestone/43) version is October 01.

BIN
docs/en/Blog-Posts/2020-09-17 v3_2_Preview/abp-community-20200917.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 KiB

BIN
docs/en/Blog-Posts/2020-09-17 v3_2_Preview/account-profile-picture.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
docs/en/Blog-Posts/2020-09-17 v3_2_Preview/blazor-role-management.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
docs/en/Blog-Posts/2020-09-17 v3_2_Preview/blazorise-github.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

BIN
docs/en/Blog-Posts/2020-09-17 v3_2_Preview/file-management-module-angular.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
docs/en/Blog-Posts/2020-09-17 v3_2_Preview/host-features.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
docs/en/Blog-Posts/2020-09-17 v3_2_Preview/visual-studio-solution-with-blazor.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

47
docs/en/Blog-Posts/2020-10-01 v3_2_Release_Stable/POST.md

@ -0,0 +1,47 @@
# ABP Framework 3.2 Final Has Been Released
ABP Framework & ABP Commercial 3.2 have been released today.
Since all the new features are already explained in details with the [3.2 RC Announcement Post](https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-3.2-RC-With-The-New-Blazor-UI), I will not repeat all the details again. Please read [the RC post](https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-3.2-RC-With-The-New-Blazor-UI) for **new feature and changes** you may need to do for your solution while upgrading to the version 3.2.
## Creating New Solutions
You can create a new solution with the ABP Framework version 3.2 by either using the `abp new` command or using the **direct download** tab on the [get started page](https://abp.io/get-started).
> See the [getting started document](https://docs.abp.io/en/abp/latest/Getting-Started) for details.
## How to Upgrade an Existing Solution
### Install/Update the ABP CLI
First of all, install the ABP CLI or upgrade to the latest version.
If you haven't installed yet:
````bash
dotnet tool install -g Volo.Abp.Cli
````
To update an existing installation:
```bash
dotnet tool update -g Volo.Abp.Cli
```
### ABP UPDATE Command
[ABP CLI](https://docs.abp.io/en/abp/latest/CLI) provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:
````bash
abp update
````
After the update command, check [the RC blog post](https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-3.2-RC-With-The-New-Blazor-UI) to learn if you need to make any changes in your solution.
> You may want to see the new [upgrading document](https://docs.abp.io/en/abp/latest/Upgrading).
## About the Next Versions
The next two versions (3.3 & 4.0) will be mostly related to completing the Blazor UI features and upgrading the ABP Framework & ecosystem to the .NET 5.0.
The ultimate goal is to complete the version 4.0 with a stable Blazor UI with the fundamental features implemented and publish it just after the Microsoft lunches .NET 5 in this November.

271
docs/en/Blog-Posts/2020-10-15 v3_3_Preview/POST.md

@ -0,0 +1,271 @@
# ABP Framework 3.3 RC Has Been Published
We have released the [ABP Framework](https://abp.io/) (and the [ABP Commercial](https://commercial.abp.io/)) `3.3.0-rc.1` today. This blog post introduces the new features and important changes in the new version.
## Get Started with the 3.3 RC.1
If you want to try the version `3.3.0-rc.1` today, follow the steps below;
1) **Upgrade** the ABP CLI to the version `3.3.0-rc.1` using a command line terminal:
````bash
dotnet tool update Volo.Abp.Cli -g --version 3.3.0-rc.1
````
**or install** if you haven't installed before:
````bash
dotnet tool install Volo.Abp.Cli -g --version 3.3.0-rc.1
````
2) Create a **new application** with the `--preview` option:
````bash
abp new BookStore --preview
````
See the [ABP CLI documentation](https://docs.abp.io/en/abp/3.3/CLI) for all the available options.
> You can also use the *Direct Download* tab on the [Get Started](https://abp.io/get-started) page by selecting the Preview checkbox.
## What's new with the ABP Framework 3.3
### The Blazor UI
We had released an experimental early preview version of the Blazor UI with the [previous version](https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-3.2-RC-With-The-New-Blazor-UI). In this version, we've completed most of the fundamental infrastructure features and the application modules (like identity and tenant management).
It currently has almost the same functionalities as the other UI types (Angular & MVC / Razor Pages).
**Example screenshot**: User management page of the Blazor UI
![abp-blazor-ui](abp-blazor-ui.png)
> We've adapted the [Lepton Theme](https://commercial.abp.io/themes) for the ABP Commercial, see the related section below.
We are still working on the fundamentals. So, the next version may introduce breaking changes of the Blazor UI. We will work hard to keep them with the minimal effect on your application code.
#### Breaking Changes on the Blazor UI
There are some breaking changes with the Blazor UI. If you've built an application and upgrade it, your application might not properly work. See [the migration guide](https://docs.abp.io/en/abp/3.3/Migration-Guides/BlazorUI-3_3) for the changes you need to do after upgrading your application.
### Automatic Validation for AntiForgery Token for HTTP APIs
Starting with the version 3.3, all your HTTP API endpoints are **automatically protected** against CSRF attacks, unless you disable it for your application. So, no configuration needed, just upgrade the ABP Framework.
[See the documentation](https://docs.abp.io/en/abp/3.3/CSRF-Anti-Forgery) to if you want to understand why you need it and how ABP Framework solves the problem.
### Rebus Integration Package for the Distributed Event Bus
[Rebus](https://github.com/rebus-org/Rebus) describes itself as "Simple and lean service bus implementation for .NET". There are a lot of integration packages like RabbitMQ and Azure Service Bus for the Rebus. The new [Volo.Abp.EventBus.Rebus](https://www.nuget.org/packages/Volo.Abp.EventBus.Rebus) package allows you to use the Rebus as the [distributed event bus](https://docs.abp.io/en/abp/latest/Distributed-Event-Bus) for the ABP Framework.
See [the documentation](https://docs.abp.io/en/abp/3.3/Distributed-Event-Bus-Rebus-Integration) to learn how to use Rebus with the ABP Framework.
### Async Repository LINQ Extension Methods
You have a problem when you want to use **Async LINQ Extension Methods** (e.g. `FirstOrDefaultAsync(...)`) in your **domain** and **application** layers. These async methods are **not included in the standard LINQ extension methods**. Those are defined by the [Microsoft.EntityFrameworkCore](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) NuGet package (see [the code](https://github.com/dotnet/efcore/blob/main/src/EFCore/Extensions/EntityFrameworkQueryableExtensions.cs)). To be able to use these `async` methods, you need to reference to the `Microsoft.EntityFrameworkCore` package.
If you don't want to depend on the EF Core in your business layer, then ABP Framework provides the `IAsyncQueryableExecuter` service to execute your queries asynchronously without depending on the EF Core package. You can see [the documentation](https://docs.abp.io/en/abp/latest/Repositories#option-3-iasyncqueryableexecuter) to get more information about this service.
ABP Framework version 3.3 takes this one step further and allows you to directly execute the async LINQ extension methods on the `IRepository` interface.
**Example: Use `CountAsync` and `FirstOrDefaultAsync` methods on the repositories**
````csharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace MyCompanyName.MyProjectName
{
public class BookAppService : ApplicationService, IBookAppService
{
private readonly IRepository<Book, Guid> _bookRepository;
public BookAppService(IRepository<Book, Guid> bookRepository)
{
_bookRepository = bookRepository;
}
public async Task DemoAsync()
{
var countAll = await _bookRepository
.CountAsync();
var count = await _bookRepository
.CountAsync(x => x.Name.Contains("A"));
var book1984 = await _bookRepository
.FirstOrDefaultAsync(x => x.Name == "1984");
}
}
}
````
All the standard LINQ methods are supported: *AllAsync, AnyAsync, AverageAsync, ContainsAsync, CountAsync, FirstAsync, FirstOrDefaultAsync, LastAsync, LastOrDefaultAsync, LongCountAsync, MaxAsync, MinAsync, SingleAsync, SingleOrDefaultAsync, SumAsync, ToArrayAsync, ToListAsync*.
This approach still has a limitation. You need to execute the extension method directly on the repository object. For example, the below usage is **not supported**:
````csharp
var count = await _bookRepository.Where(x => x.Name.Contains("A")).CountAsync();
````
This is because the object returned from the `Where` method is not a repository object, it is a standard `IQueryable`. In such cases, you can still use the `IAsyncQueryableExecuter`:
````csharp
var count = await AsyncExecuter.CountAsync(
_bookRepository.Where(x => x.Name.Contains("A"))
);
````
`AsyncExecuter` has all the standard extension methods, so you don't have any restriction here. See [the repository documentation](https://docs.abp.io/en/abp/latest/Repositories#iqueryable-async-operations) for all the options you have.
> ABP Framework does its best to not depend on the EF Core and still be able to use the async LINQ extension methods. However, there is no problem to depend on the EF Core for your application, you can add the `Microsoft.EntityFrameworkCore` NuGet package and use the native methods.
### Stream Support for the Application Service Methods
[Application services](https://docs.abp.io/en/abp/latest/Application-Services) are consumed by clients and the parameters and return values (typically [Data Transfer Objects](https://docs.abp.io/en/abp/latest/Data-Transfer-Objects)). In case of the client is a remote application, then these objects should be serialized & deserialized.
Until the version 3.3, we hadn't suggest to use the `Stream` in the application service contracts, since it is not serializable/deserializable. However, with the version 3.3, ABP Framework properly supports this scenario by introducing the new `IRemoteStreamContent` interface.
Example: An application service that can get or return streams
````csharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Content;
namespace MyProject.Test
{
public interface ITestAppService : IApplicationService
{
Task Upload(Guid id, IRemoteStreamContent streamContent);
Task<IRemoteStreamContent> Download(Guid id);
}
}
````
The implementation can be as shown below:
````csharp
using System;
using System.IO;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Content;
namespace MyProject.Test
{
public class TestAppService : ApplicationService, ITestAppService
{
public Task<IRemoteStreamContent> Download(Guid id)
{
var fs = new FileStream("C:\\Temp\\" + id + ".blob", FileMode.OpenOrCreate);
return Task.FromResult(
(IRemoteStreamContent) new RemoteStreamContent(fs) {
ContentType = "application/octet-stream"
}
);
}
public async Task Upload(Guid id, IRemoteStreamContent streamContent)
{
using (var fs = new FileStream("C:\\Temp\\" + id + ".blob", FileMode.Create))
{
await streamContent.GetStream().CopyToAsync(fs);
await fs.FlushAsync();
}
}
}
}
````
> This is just a demo code. Do it better in your production code :)
Thanks to [@alexandru-bagu](https://github.com/alexandru-bagu) for the great contribution!
### Other Changes
* Upgraded all the .NET Core / ASP.NET Core related packages to the version 3.1.8. If you have additional dependencies to the .NET Core / ASP.NET Core related packages, we suggest you to updates your packages to the version 3.1.8 to have the latest bug and security fixes published by Microsoft.
* The blogging module now uses the [BLOB Storing](https://docs.abp.io/en/abp/latest/Blob-Storing) system to store images & files of the blog posts. If you are using this module, then you need to manually migrate the local files to the BLOB Storing system after the upgrade.
* The Angular UI is now redirecting to the profile management page of the MVC UI instead of using its own UI, if you've configured the authorization code flow (which is default since the version 3.2.0).
## What's new with the ABP Commercial 3.3
### The Blazor UI
We have good news for the ABP Commercial Blazor UI too. We have implemented the [Lepton Theme](https://commercial.abp.io/themes) integration, so it is now available with the Blazor UI. Also, implemented most of the fundamental [modules](https://commercial.abp.io/modules).
**A screenshot from the ABP Commercial startup template with the Blazor UI**
![abp-commercial-blazor-ui](abp-commercial-blazor-ui.png)
There are still missing features and modules. However, we are working on it to have a more complete version in the next release.
#### Breaking Changes on the Blazor UI
There are some breaking changes with the Blazor UI. If you've built an application and upgrade it, your application might not properly work. See the [ABP Commercial Blazor UI v 3.3 Migration Guide](https://docs.abp.io/en/commercial/3.3/migration-guides/blazor-ui-3_3) for the changes you need to do after upgrading your application.
#### Known Issues
When you create a new project, profile management doesn't work, you get an exception because it can't find the `/libs/cropperjs/css/cropper.min.css` file. To fix the issue;
* Add `"@volo/account": "^3.3.0-rc.1"` to the `package.json` in the `.Host` project.
* Run `yarn` (or `npm install`), then `gulp` on a command line terminal in the root folder of the `.Host` project.
### Multi-Tenant Social Logins
[Account module](https://commercial.abp.io/modules/Volo.Account.Pro) now supports to manage the social/external logins in the UI. You can **enable/disable** and **set options** in the settings page. It also supports to use **different credentials for the tenants** and it is also **configured on the runtime**.
![abp-commercial-setting-account-external-logins](abp-commercial-setting-account-external-logins.png)
### Linked Accounts
Linked user system allows you to link other accounts (including account in a different tenant) with your account, so you can switch between different accounts with a single-click. It is practical since you no longer need to logout and login again with entering the credentials of the target account.
To manage the linked accounts, go to the profile management page from the user menu;
![abp-commercial-linked-users](abp-commercial-linked-users.png)
### Paypal & Stripe Integrations
The [Payment Module](https://commercial.abp.io/modules/Volo.Payment) was supporting PayU and 2Checkout providers until the version 3.3. It's now integrated to PayPal and Stripe. See the [technical documentation](https://docs.abp.io/en/commercial/latest/modules/payment) to learn how to use it.
### ABP Suite Improvements
We've done a lot of small improvements for the [ABP Suite](https://commercial.abp.io/tools/suite). Some of the enhancements are;
* Show the previously installed modules as *installed* on the module list.
* Switch between the latest stable, the latest [preview](https://docs.abp.io/en/abp/latest/Previews) and the latest [nightly build](https://docs.abp.io/en/abp/latest/Nightly-Builds) versions of the ABP related packages.
* Moved the file that stores the *previously created entities* into the solution folder to allow you to store it in your source control system.
### Others
* Added an option to the Account Module to show reCAPTCHA on the login & the registration forms.
Besides the new features introduced in this post, we've done a lot of small other enhancements and bug fixes to provide a better development experience and increase the developer productivity.
## New Articles
The core ABP Framework team & the community continue to publish new articles on the [ABP Community](https://community.abp.io/) web site. The recently published articles are;
* [Replacing Email Templates and Sending Emails](https://community.abp.io/articles/replacing-email-templates-and-sending-emails-jkeb8zzh) (by [@EngincanV](https://community.abp.io/members/EngincanV))
* [How to Add Custom Properties to the User Entity](https://community.abp.io/articles/how-to-add-custom-property-to-the-user-entity-6ggxiddr) (by [@berkansasmaz](https://community.abp.io/members/berkansasmaz))
* [Using the AdminLTE Theme with the ABP Framework MVC / Razor Pages UI](https://community.abp.io/articles/using-the-adminlte-theme-with-the-abp-framework-mvc-razor-pages-ui-gssbhb7m) (by [@mucahiddanis](https://community.abp.io/members/mucahiddanis))
* [Using DevExtreme Angular Components With the ABP Framework](https://community.abp.io/articles/using-devextreme-angular-components-with-the-abp-framework-x5nyvj3i) (by [@bunyamin](https://community.abp.io/members/bunyamin))
It is appreciated if you want to [submit an article](https://community.abp.io/articles/submit) related to the ABP Framework.
## About the Next Release
The next version will be `4.0.0`. We are releasing a major version, since we will move the ABP Framework to .NET 5.0. We see that for most of the applications this will not be a breaking change and we hope you easily upgrade to it.
The planned 4.0.0-rc.1 (Release Candidate) version date is **November 11**, just after the Microsoft releases the .NET 5.0 final. The planned 4.0.0 final release date is **November 26**.
Follow the [GitHub milestones](https://github.com/abpframework/abp/milestones) for all the planned ABP Framework version release dates.
## Feedback
Please check out the ABP Framework 3.3.0 RC and [provide feedback](https://github.com/abpframework/abp/issues/new) to help us to release a more stable version. The planned release date for the [3.3.0 final](https://github.com/abpframework/abp/milestone/44) version is October 27th.

BIN
docs/en/Blog-Posts/2020-10-15 v3_3_Preview/abp-blazor-ui.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
docs/en/Blog-Posts/2020-10-15 v3_3_Preview/abp-commercial-blazor-ui.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

BIN
docs/en/Blog-Posts/2020-10-15 v3_3_Preview/abp-commercial-linked-users.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/en/Blog-Posts/2020-10-15 v3_3_Preview/abp-commercial-setting-account-external-logins.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

47
docs/en/Blog-Posts/2020-10-27 v3_3_Release_Stable/POST.md

@ -0,0 +1,47 @@
# ABP Framework & ABP Commercial 3.3 Final Have Been Released
ABP Framework & ABP Commercial 3.3.0 have been released today.
Since all the new features are already explained in details with the [3.3 RC Announcement Post](https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-v3.3-RC-Have-Been-Released), I will not repeat all the details again. Please read [the RC post](https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-v3.3-RC-Have-Been-Released) for **new feature and changes** you may need to do for your solution while upgrading to the version 3.3.
## Creating New Solutions
You can create a new solution with the ABP Framework version 3.3 by either using the `abp new` command or using the **direct download** tab on the [get started page](https://abp.io/get-started).
> See the [getting started document](https://docs.abp.io/en/abp/latest/Getting-Started) for details.
## How to Upgrade an Existing Solution
### Install/Update the ABP CLI
First of all, install the ABP CLI or upgrade to the latest version.
If you haven't installed yet:
````bash
dotnet tool install -g Volo.Abp.Cli
````
To update an existing installation:
```bash
dotnet tool update -g Volo.Abp.Cli
```
### ABP UPDATE Command
[ABP CLI](https://docs.abp.io/en/abp/latest/CLI) provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:
````bash
abp update
````
Run this command in the root folder of your solution. After the update command, check [the RC blog post](https://blog.abp.io/abp/ABP-Framework-ABP-Commercial-v3.3-RC-Have-Been-Released) to learn if you need to make any changes in your solution.
> You may want to see the new [upgrading document](https://docs.abp.io/en/abp/latest/Upgrading).
## About the Next Version: 4.0
The next version will be 4.0 and it will be mostly related to completing the Blazor UI features and upgrading the ABP Framework & ecosystem to the .NET 5.0.
The goal is to complete the version 4.0 with a stable Blazor UI with the fundamental features implemented and publish it just after the Microsoft lunches .NET 5 in this November. The planned 4.0 preview release date is November 11th.

67
docs/en/CLI-BuildCommand.md

@ -0,0 +1,67 @@
# Build Command
Building a .NET project is hard when the project references a project reference outside of the solution or even from a different GIT repository. This command builds a GIT repository and it's depending repositories or a single .NET solution File. In order ```build``` command to work, its **executing directory** or passed ```--working-directory``` parameter's directory must contain one of;
* A .NET solution file (*.sln)
* abp-build-config.json
When the executing directory (or ```--working-directory``` parameter's directory) contains a .NET solution file, ```build``` command builds all the projects in the related solution file and all project references on building project files recursively.
When the executing directory (or ```--working-directory``` parameter's directory) contains a ```abp-build-config.json```, ```build``` command builds all changed projects form its last build and all project references on building project files recursively.
# Build Command Config
```abp-build-config.json``` contains properties below;
* ```Name```: Name of the GIT repository. This can be friendly name of your GIT repository or any other unique string for the repository.
* ```RootPath```: Root path of the repository which contains ```.git``` folder.
* ```DependingRepositories```: Depending repository list of a repository. Each depending repository item contains same fields as a repository.
* ```IgnoredDirectories```: Relative directory paths to ignore while building a GIT repository.
A sample ```abp-build-config.json``` looks like for a Windows OS;
````json
{
"Name": "main-repository",
"RootPath": "D:\\GitHub\\main-repository",
"DependingRepositories": [{
"Name": "module-repository",
"RootPath": "D:\\GitHub\\module-repository"
}],
"IgnoredDirectories": [
"utils"
]
}
````
# Build Status
ABP CLI stores a build status file for builds using the repository friendly names and current branch names in the;
* ```%USERPROFILE%\.abp\build\``` for Windows.
* ```$HOME/.abp/build/``` for Linux/macOS.
and uses this file when building same repository next time and only builds affected projects and decreases the total build time. A sample build status file content looks like;
````json
{
"RepositoryName": "main-repository",
"BranchName": "dev",
"CommitId": "84ecde8ba275aeeb14d24a87ad46a1e941adf8ba",
"SucceedProjects": [{
"CsProjPath": "D:\\GitHub\\main-repository\\BookStore\\BookStore.Web.csproj",
"CommitId": "84ecde8ba275aeeb14d24a87ad46a1e941adf8ba"
}],
"DependingRepositories": [{
"RepositoryName": "module-repository",
"BranchName": "dev",
"CommitId": "0598b8e45af9507fc9ba8abf304e78fc7d434e04",
"SucceedProjects": [{
"CsProjPath": "D:\\GitHub\\module-repository\\identity-module\Identity\\Identity.Web.csproj",
"CommitId": "0598b8e45af9507fc9ba8abf304e78fc7d434e04"
}],
"DependingRepositories": []
}]
}
````

32
docs/en/CLI.md

@ -40,6 +40,7 @@ Here, the list of all available commands before explaining their details:
* **`translate`**: Simplifies to translate localization files when you have multiple JSON [localization](Localization.md) files in a source control repository.
* **`login`**: Authenticates on your computer with your [abp.io](https://abp.io/) username and password.
* **`logout`**: Logouts from your computer if you've authenticated before.
* **`build`**: Builds a GIT repository and depending repositories or a single .NET solution.
### help
@ -179,7 +180,8 @@ abp add-module Volo.Blogging
* `--solution` or `-s`: Specifies the solution (.sln) file path. If not specified, CLI tries to find a .sln file in the current directory.
* `--skip-db-migrations`: For EF Core database provider, it automatically adds a new code first migration (`Add-Migration`) and updates the database (`Update-Database`) if necessary. Specify this option to skip this operation.
* `-sp` or `--startup-project`: Relative path to the project folder of the startup project. Default value is the current folder.
* `--with-source-code`: Add source code of the module instead of NuGet/NPM packages.
* `--with-source-code`: Downloads the source code of the module to your solution folder and uses local project references instead of NuGet/NPM packages.
* `--add-to-solution-file`: Adds the downloaded module to your solution file, so you will also see the projects of the module when you open the solution on a IDE. (only available when `--with-source-code` is used.)
### get-source
@ -360,3 +362,31 @@ Logs you out by removing the session token from your computer.
abp logout
```
### build
This command builds a GIT repository and it's depending repositories or a single .NET solution File. In order ```build``` command to work, its **executing directory** or passed ```--working-directory``` parameter's directory must contain one of;
* A .NET solution file (*.sln)
* abp-build-config.json (suggested to add this to .gitignore)
Usage:
````bash
abp build [options]
````
Example:
```
abp build --build-name "prod" --dotnet-build-arguments "\"--no-dependencies\""
```
#### Options
* ```--working-directory``` or ```-w```: Specifies the working directory. This option is useful when the command is executed outside of a GIT repository or when executing directory doesn't contain a .NET solution file.
* ```--build-name``` or ```-n```: Specifies a name for the build. This option is useful when same repository is used for more than one different builds.
* ```--dotnet-build-arguments``` or ```-a```: Arguments to pass ```dotnet build``` when building project files. This parameter must be passed like ```"\"{params}\""``` .
* ```--force``` or ```-f```: Forces to build projects even they are not changed from the last successful build.
For more details, see [build command documentation](CLI-BuildCommand.md).

119
docs/en/CSRF-Anti-Forgery.md

@ -0,0 +1,119 @@
# CSRF/XSRF & Anti Forgery System
"*Cross-Site Request Forgery (CSRF) is a type of attack that occurs when a malicious web site, email, blog, instant message, or program causes a user’s web browser to perform an unwanted action on a trusted site for which the user is currently authenticated*" ([OWASP](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet)).
**ABP Framework completely automates CSRF preventing** and works out of the box without any configuration. Read this documentation only if you want to understand it better or need to customize.
## The Problem
ASP.NET Core [provides infrastructure](https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery) to prevent CSRF attacks by providing a system to **generate** and **validate antiforgery tokens**. However, the standard implementation has a few drawbacks;
Antiforgery token validation is only **enabled for razor pages by default** and not enabled for **HTTP APIs**. You need to enable it yourself for the Controllers. You can use the `[ValidateAntiForgeryToken]` attribute for a specific API Controller/Action or the `[AutoValidateAntiforgeryToken]` attribute to prevent attacks globally.
Once you enable it;
* You need to manually add an HTTP header, named `RequestVerificationToken` to every **AJAX request** made in your application. You should care about obtaining the token, saving in the client side and adding to the HTTP header on every HTTP request.
* All your clients, including **non-browser clients**, should care about obtaining and sending the antiforgery token in every request. In fact, non-browser clients has no CSRF risk and should not care about this.
Especially, the second point is a pain for your clients and unnecessarily consumes your server resources.
> You can read more about the ASP.NET Core antiforgery system in its own [documentation](https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery).
## The Solution
ABP Framework provides `[AbpValidateAntiForgeryToken]` and `[AbpAutoValidateAntiforgeryToken]` attributes, just like the attributes explained above. `[AbpAutoValidateAntiforgeryToken]` is already added to the global filters, so you should do nothing to enable it for your application.
ABP Framework also automates the following infrastructure;
* Server side sets a **special cookie**, named `XSRF-TOKEN` by default, that is used make the antiforgery token value available to the browser. This is **done automatically** (by the [application configuration](Application-Configuration.md) endpoint). Nothing to do in the client side.
* In the client side, it reads the token from the cookie and sends it in the **HTTP header** (named `RequestVerificationToken` by default). This is implemented for all the supported UI types.
* Server side validates the antiforgery token **only for same and cross site requests** made by the browser. It bypasses the validation for non-browser clients.
That's all. The systems works smoothly.
## Configuration / Customization
### AbpAntiForgeryOptions
`AbpAntiForgeryOptions` is the main [options class](Options.md) to configure the ABP Antiforgery system. It has the following properties;
* `TokenCookie`: Can be used to configure the cookie details. This cookie is used to store the antiforgery token value in the client side, so clients can read it and sends the value as the HTTP header. Default cookie name is `XSRF-TOKEN`, expiration time is 10 years (yes, ten years! It should be a value longer than the authentication cookie max life time, for the security).
* `AuthCookieSchemaName`: The name of the authentication cookie used by your application. Default value is `Identity.Application` (which becomes `AspNetCore.Identity.Application` on runtime). The default value properly works with the ABP startup templates. **If you change the authentication cookie name, you also must change this.**
* `AutoValidate`: The single point to enable/disable the ABP automatic antiforgery validation system. Default value is `true`.
* `AutoValidateFilter`: A predicate that gets a type and returns a boolean. ABP uses this predicate to check a controller type. If it returns false for a controller type, the controller is excluded from the automatic antiforgery token validation.
* `AutoValidateIgnoredHttpMethods`: A list of HTTP Methods to ignore on automatic antiforgery validation. Default value: "GET", "HEAD", "TRACE", "OPTIONS". These HTTP Methods are safe to skip antiforgery validation since they don't change the application state.
If you need to change these options, do it in the `ConfigureServices` method of your [module](Module-Development-Basics.md).
**Example: Configuring the AbpAntiForgeryOptions**
```csharp
Configure<AbpAntiForgeryOptions>(options =>
{
options.TokenCookie.Expiration = TimeSpan.FromDays(365);
options.AutoValidateIgnoredHttpMethods.Remove("GET");
options.AutoValidateFilter =
type => !type.Namespace.StartsWith("MyProject.MyIgnoredNamespace");
});
```
This configuration;
* Sets the antiforgery token expiration time to ~1 year.
* Enables antiforgery token validation for GET requests too.
* Ignores the controller types in the specified namespace.
### AntiforgeryOptions
`AntiforgeryOptions` is the standard [options class](Options.md) of the ASP.NET Core. **You can find all the information about this class in its [own documentation](https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery)**.
`HeaderName` option is especially important for the ABP Framework point of view. Default value of this value is `RequestVerificationToken` and the clients uses this name while sending the token value in the header. So, if you change this option, you should also arrange your clients to align the change. If you don't have a good reason, leave it as default.
### AbpValidateAntiForgeryToken Attribute
If you disable the automatic validation or want to perform the validation for an endpoint that is not validated by default (for example, an endpoint with HTTP GET Method), you can use the `[AbpValidateAntiForgeryToken]` attribute for a **controller type or method** (action).
**Example: Add `[AbpValidateAntiForgeryToken]` to a HTTP GET method**
```csharp
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.AntiForgery;
namespace MyCompanyName.MyProjectName.Controllers
{
[Route("api/products")]
public class ProductController : AbpController
{
[HttpGet]
[AbpValidateAntiForgeryToken]
public async Task GetAsync()
{
//TODO: ...
}
}
}
```
### Angular UI
Angular supports CSRF Token out of box, but the token header name is `X-XSRF-TOKEN`. Since ABP Framework follows the ASP.NET Core conventions, it changes this value to `RequestVerificationToken` in the core package.
You don't need to make anything unless you need to change the `AntiforgeryOptions.HeaderName` as explained before. If you change it, remember to change the header name for the Angular application too. To do that, add an import declaration for the `HttpClientXsrfModule` into your root module.
**Example: Change the header name to *MyCustomHeaderName***
```typescript
@NgModule({
// ...
imports: [
//...
HttpClientXsrfModule.withOptions({
cookieName: 'XSRF-TOKEN',
headerName: 'MyCustomHeaderName'
})
],
})
export class AppModule {}
```

258
docs/en/Caching.md

@ -1,154 +1,167 @@
# Caching
ABP framework extends ASP.NET Core's distributed caching system.
ABP Framework extends the [ASP.NET Core distributed cache](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed).
## Volo.Abp.Caching Package
## Installation
> This package is already installed by default with the startup template. So, most of the time, you don't need to install it manually.
> This package is already installed by default with the [application startup template](Startup-Templates/Application.md). 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):
[Volo.Abp.Caching](https://www.nuget.org/packages/Volo.Abp.Caching) is the main package of the caching system. You can install it a project using the add-package command of the [ABP CLI](CLI.md):
```
Install-Package Volo.Abp.Caching
abp add-package Volo.Abp.Caching
```
Then you can add **AbpCachingModule** dependency to your module:
You need to run this command on a command line terminal in a folder containing a `csproj` file (see [other options](https://abp.io/package-detail/Volo.Abp.Caching) to install).
```c#
using Volo.Abp.Modularity;
using Volo.Abp.Caching;
## Usage
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpCachingModule))]
public class MyModule : AbpModule
{
//...
}
}
```
## `IDistributedCache` Interface
### `IDistributedCache` Interface
ASP.NET Core defines the `IDistributedCache` interface to get/set cache values. But it has some difficulties:
ASP.NET Core defines the `IDistributedCache` interface to get/set the cache values. But it has some difficulties:
* It works with **byte arrays** rather than .NET objects. So, you need to **serialize/deserialize** the objects you need to cache.
* It provides a **single key pool** for all cache items, so;
* You need to care about the keys to distinguish **different type of objects**.
* You need to care about the cache items of **different tenants** (see [multi-tenancy](Multi-Tenancy.md)).
* You need to care about the cache items of **different tenants** in a [multi-tenant](Multi-Tenancy.md) system.
> `IDistributedCache` is defined in the `Microsoft.Extensions.Caching.Abstractions` package. That means it is not only usable for ASP.NET Core applications, but also available to **any type of applications**.
> Default implementation of the `IDistributedCache` interface is the `MemoryDistributedCache` which works **in-memory**. See [ASP.NET Core's documentation](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) to see how to switch to **Redis** or another cache provider.
> Default implementation of the `IDistributedCache` interface is the `MemoryDistributedCache` which works **in-memory**. See [ASP.NET Core's documentation](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) to see how to switch to Redis or another cache provider. Also, see the [Redis Cache](Redis-Cache.md) document if you want to use the Redis as the distributed cache server.
See [ASP.NET Core's distributed caching document](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) for more information.
## `IDistributedCache<TCacheItem>` Interface
### `IDistributedCache<TCacheItem>` Interface
ABP framework defines the generic `IDistributedCache<TCacheItem>` interface in the [Volo.Abp.Caching](https://www.nuget.org/packages/Volo.Abp.Caching/) package. `TCacheItem` is the type of the object stored in the cache.
`IDistributedCache<TCacheItem>` solves the difficulties explained above;
* It internally **serializes/deserializes** the cached objects. Uses **JSON** serialization by default, but can be overridden by replacing the `IDistributedCacheSerializer` service in the [dependency injection](Dependency-Injection.md) system.
* It automatically adds a **cache name** prefix to the cache keys based on the object type stored in the cache. Default cache name is the full name of the cache item class (`CacheItem` postfix is removed if your cache item class ends with it). You can use the `CacheName` attribute on the cache item class to set the cache name.
* It automatically adds the **current tenant id** to the cache key to distinguish cache items for different tenants (only works if your application is [multi-tenant](Multi-Tenancy.md)). Define `IgnoreMultiTenancy` attribute on the cache item class to disable this if you want to share the cached objects among all tenants in a multi-tenant application.
* Allows to define a **global cache key prefix** per application, so different applications can use their isolated key pools in a shared distributed cache source.
* It automatically adds a **cache name** prefix to the cache keys based on the object type stored in the cache. Default cache name is the full name of the cache item class (`CacheItem` postfix is removed if your cache item class ends with it). You can use the **`CacheName` attribute** on the cache item class to set the cache name.
* It automatically adds the **current tenant id** to the cache key to distinguish cache items for different tenants (if your application is [multi-tenant](Multi-Tenancy.md)). Define `IgnoreMultiTenancy` attribute on the cache item class to disable this if you want to share the cached objects among all tenants in a multi-tenant application.
* Allows to define a **global cache key prefix** per application, so different applications can use their isolated key pools in a shared distributed cache server.
* It **can tolerate errors** wherever possible and bypasses the cache. This is useful when you have temporary problems on the cache server.
* It has methods like `GetManyAsync` and `SetManyAsync` which significantly improve the performance on **batch operations**.
### Usage
An example class to store an item in the cache:
**Example: Store Book names and prices in the cache**
````csharp
public class BookCacheItem
namespace MyProject
{
public string Name { get; set; }
public class BookCacheItem
{
public string Name { get; set; }
public float Price { get; set; }
public float Price { get; set; }
}
}
````
You can inject and use the `IDistributedCache<BookCacheItem>` service to get/set `BookCacheItem` objects.
Example usage:
You can inject and use the `IDistributedCache<BookCacheItem>` service to get/set `BookCacheItem` objects:
````csharp
public class BookService : ITransientDependency
{
private readonly IDistributedCache<BookCacheItem> _cache;
public BookService(IDistributedCache<BookCacheItem> cache)
{
_cache = cache;
}
public async Task<BookCacheItem> GetAsync(Guid bookId)
{
return await _cache.GetOrAddAsync(
bookId.ToString(), //Cache key
async () => await GetBookFromDatabaseAsync(bookId),
() => new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddHours(1)
}
);
}
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
private Task<BookCacheItem> GetBookFromDatabaseAsync(Guid bookId)
namespace MyProject
{
public class BookService : ITransientDependency
{
//TODO: get from database
private readonly IDistributedCache<BookCacheItem> _cache;
public BookService(IDistributedCache<BookCacheItem> cache)
{
_cache = cache;
}
public async Task<BookCacheItem> GetAsync(Guid bookId)
{
return await _cache.GetOrAddAsync(
bookId.ToString(), //Cache key
async () => await GetBookFromDatabaseAsync(bookId),
() => new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddHours(1)
}
);
}
private Task<BookCacheItem> GetBookFromDatabaseAsync(Guid bookId)
{
//TODO: get from database
}
}
}
````
* This sample service uses the `GetOrAddAsync()` method to get a book item from the cache.
* This sample service uses the `GetOrAddAsync()` method to get a book item from the cache. `GetOrAddAsync` is an additional method that was added by the ABP Framework to the standard ASP.NET Core distributed cache methods.
* If the book was not found in the cache, it calls the factory method (`GetBookFromDatabaseAsync` in this case) to retrieve the book item from the original source.
* `GetOrAddAsync` optionally gets a `DistributedCacheEntryOptions` which can be used to set the lifetime of the cached item.
Other methods of the `IDistributedCache<BookCacheItem>` are same as ASP.NET Core's `IDistributedCache` interface, so you can refer [it's documentation](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed).
`IDistributedCache<BookCacheItem>` supports the same methods of the ASP.NET Core's standard `IDistributedCache` interface, so you can refer [it's documentation](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed).
## `IDistributedCache<TCacheItem, TCacheKey>` Interface
### `IDistributedCache<TCacheItem, TCacheKey>` Interface
`IDistributedCache<TCacheItem>` interface assumes that the type of your cache key is `string` (so, you need to manually convert your key to string if you need to use a different kind of cache key). `IDistributedCache<TCacheItem, TCacheKey>` can be used when your cache key type is not `string`.
`IDistributedCache<TCacheItem>` interface assumes that the type of your **cache key** is `string` (so, you need to manually convert your key to string if you need to use a different kind of cache key). While this is not a big deal, `IDistributedCache<TCacheItem, TCacheKey>` can be used when your cache key type is not `string`.
### Usage
An example class to store an item in the cache:
**Example: Store Book names and prices in the cache**
````csharp
public class BookCacheItem
using Volo.Abp.Caching;
namespace MyProject
{
public string Name { get; set; }
[CacheName("Books")]
public class BookCacheItem
{
public string Name { get; set; }
public float Price { get; set; }
public float Price { get; set; }
}
}
````
Example usage (assumes that your cache key type is `Guid`):
* This example uses the `CacheName` attribute for the `BookCacheItem` class to set the cache name.
````csharp
public class BookService : ITransientDependency
{
private readonly IDistributedCache<BookCacheItem, Guid> _cache;
You can inject and use the `IDistributedCache<BookCacheItem, Guid>` service to get/set `BookCacheItem` objects:
public BookService(IDistributedCache<BookCacheItem, Guid> cache)
{
_cache = cache;
}
````csharp
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
public async Task<BookCacheItem> GetAsync(Guid bookId)
{
return await _cache.GetOrAddAsync(
bookId, //Guid type used as the cache key
async () => await GetBookFromDatabaseAsync(bookId),
() => new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddHours(1)
}
);
}
private Task<BookCacheItem> GetBookFromDatabaseAsync(Guid bookId)
namespace MyProject
{
public class BookService : ITransientDependency
{
//TODO: get from database
private readonly IDistributedCache<BookCacheItem, Guid> _cache;
public BookService(IDistributedCache<BookCacheItem, Guid> cache)
{
_cache = cache;
}
public async Task<BookCacheItem> GetAsync(Guid bookId)
{
return await _cache.GetOrAddAsync(
bookId, //Guid type used as the cache key
async () => await GetBookFromDatabaseAsync(bookId),
() => new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddHours(1)
}
);
}
private Task<BookCacheItem> GetBookFromDatabaseAsync(Guid bookId)
{
//TODO: get from database
}
}
}
````
@ -156,6 +169,8 @@ public class BookService : ITransientDependency
* This sample service uses the `GetOrAddAsync()` method to get a book item from the cache.
* Since cache explicitly implemented as using `Guid` as cache key, `Guid` value passed to `_cache_GetOrAddAsync()` method.
#### Complex Types as the Cache Key
`IDistributedCache<TCacheItem, TCacheKey>` internally uses `ToString()` method of the key object to convert it to a string. If you need to use a complex object as the cache key, you need to override `ToString` method of your class.
An example class that is used as a cache key:
@ -192,7 +207,66 @@ public class BookService : ITransientDependency
}
````
### DistributedCacheOptions
## Configuration
### AbpDistributedCacheOptions
`AbpDistributedCacheOptions` is the main [options class](Options.md) to configure the caching.
**Example: Set the cache key prefix for the application**
```csharp
Configure<AbpDistributedCacheOptions>(options =>
{
options.KeyPrefix = "MyApp1";
});
```
> Write that code inside the `ConfigureServices` method of your [module class](Module-Development-Basics.md).
#### Available Options
* `HideErrors` (`bool`, default: `true`): Enables/disables hiding the errors on writing/reading values from the cache server.
* `KeyPrefix` (`string`, default: `null`): If your cache server is shared by multiple applications, you can set a prefix for the cache keys for your application. In this case, different applications can not overwrite each other's cache items.
* `GlobalCacheEntryOptions` (`DistributedCacheEntryOptions`): Used to set default distributed cache options (like `AbsoluteExpiration` and `SlidingExpiration`) used when you don't specify the options while saving cache items. Default value uses the `SlidingExpiration` as 20 minutes.
## Error Handling
When you design a cache for your objects, you typically try to get the value from cache first. If not found in the cache, you query the object from the **original source**. It may be located in a **database** or may require to perform an HTTP call to a remote server.
In most cases, you want to **tolerate the cache errors**; If you get error from the cache server you don't want to cancel the operation. Instead, you silently hide (and log) the error and **query from the original source**. This is what the ABP Framework does by default.
ABP's Distributed Cache [handle](Exception-Handling.md), log and hide errors by default. There is an option to change this globally (see the options below).
In addition, all of the `IDistributedCache<TCacheItem>` (and `IDistributedCache<TCacheItem, TCacheKey>`) methods have an optional `hideErrors` parameter, which is `null` by default. The global value is used if this parameter left as `null`, otherwise you can decide to hide or throw the exceptions for individual method calls.
## Batch Operations
ABP's distributed cache interfaces provide methods to perform batch get/set methods those improves the performance when you want to get or set multiple cache items in a single method call.
* `SetManyAsync` and `SetMany` methods can be used to set multiple values to the cache.
* `GetManyAsync` and `GetMany` methods can be used to retrieve multiple values from the cache.
> These are not standard methods of the ASP.NET Core caching. So, some providers may not support them. They are supported by the [ABP Redis Cache integration package](Redis-Cache.md). If the provider doesn't support, it fallbacks to `SetAsync` and `GetAsync` methods (called once for each item).
## Advanced Topics
### Unit Of Work Level Cache
Distributed cache service provides an interesting feature. Assume that you've updated the price of a book in the database, then set the new price to the cache, so you can use the cached value later. What if you have an exception after setting the cache and you **rollback the transaction** that updates the price of the book? In this case, cache value will be incorrect.
`IDistributedCache<..>` methods gets an optional parameter, named `considerOuw`, which is `false` by default. If you set it to `true`, then the changes you made for the cache are not actually applied to the real cache store, but associated with the current [unit of work](Unit-Of-Work.md). You get the value you set in the same unit of work, but the changes are applied **only if the current unit of work succeed**.
### IDistributedCacheSerializer
`IDistributedCacheSerializer` service is used to serialize and deserialize the cache items. Default implementation is the `Utf8JsonDistributedCacheSerializer` class that uses `IJsonSerializer` service to convert objects to [JSON](Json.md) and vice verse. Then it uses UTC8 encoding to convert the JSON string to a byte array which is accepted by the distributed cache.
You can [replace](Dependency-Injection.md) this service by your own implementation if you want to implement your own serialization logic.
### IDistributedCacheKeyNormalizer
`IDistributedCacheKeyNormalizer` is implemented by the `DistributedCacheKeyNormalizer` class by default. It adds cache name, application cache prefix and current tenant id to the cache key. If you need a more advanced key normalization, you can [replace](Dependency-Injection.md) this service by your own implementation.
TODO
## See Also
* [Redis Cache](Redis-Cache.md)

477
docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/POST.md

@ -0,0 +1,477 @@
# Replacing Email Templates and Sending Emails
## Introduction
Hi, in this step by step article, we will send an email by using standard email template and then we will replace the standard email template with our new created template, thanks to [Text Templating System](https://docs.abp.io/en/abp/latest/Text-Templating#replacing-the-existing-templates) and [Virtual File System](https://docs.abp.io/en/abp/latest/Virtual-File-System). Let's start by explaining what these systems do.
* ABP framework provides a strong and flexible [Text Templating System](https://docs.abp.io/en/abp/latest/Text-Templating). So, we can use the text templating system to create dynamic email contents on a template and a model.
* In this article, we will use `StandardEmailTemplates.Message` as standard email template. Then we will create a new template and replace the standard email template with our new template by using [Virtual File System](https://docs.abp.io/en/abp/latest/Virtual-File-System).
* The `Virtual File System` makes it possible to manage files that do not physically exist on the file system. That means we can override `StandardEmailTemplates.Message` template by changing it's path with our new template's path.
## Creating the Solution
> ABP Framework offers startup templates to get into the business faster.
In this article, I will create a new startup template and perform the operations on this template. But if you already have a project you don't need to create a new startup template, you can implement the following steps to your existing project. (These steps can be applied to any project. (MVC, Angular etc.))
> If you have already a project you can skip this section.
Before starting to development, we will create a solution named `TemplateReplace` (or whatever you want). We can create a new startup template by using [ABP CLI](https://docs.abp.io/en/abp/latest/CLI) :
````bash
abp new TemplateReplace
````
Our project boilerplate will be ready after the download is finished. Then, open the solution in the Visual Studio (or your favorite IDE).
Run the `TemplateReplace.DbMigrator` application as below to create the database and seed initial data (which creates the admin user, admin role, permissions etc.).
![db-migrator-1](db-migrator-1.jpg)
* Right click to `TemplateReplace.DbMigrator` and choose the `Debug`.
![db-migrator-2](db-migrator-2.jpg)
* After that, click the `Start new instance` option to start the database migrations.
![db-migrator-3](db-migrator-3.jpg)
Then we can run the `TemplateReplace.Web` project to see our application working.
> _Default login credentials for admin: username is **admin** and password is **1q2w3E\***_
## Starting the Development
First thing we need to do is, creating a email service to sending emails. ABP Framework provides `IEmailSender` service that is used to send emails.
### Step - 1
Create an `Emailing` folder in the `TemplateReplace.Domain` project and add a class named `EmailService` inside of it.
```csharp
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Emailing;
using Volo.Abp.Emailing.Templates;
using Volo.Abp.TextTemplating;
namespace TemplateReplace.Emailing
{
public class EmailService : ITransientDependency
{
private readonly IEmailSender _emailSender;
private readonly ITemplateRenderer _templateRenderer;
public EmailService(IEmailSender emailSender, ITemplateRenderer templateRenderer)
{
_emailSender = emailSender;
_templateRenderer = templateRenderer;
}
public async Task SendAsync(string targetEmail)
{
var emailBody = await _templateRenderer.RenderAsync(
StandardEmailTemplates.Message,
new
{
message = "ABP Framework provides IEmailSender service that is used to send emails."
}
);
await _emailSender.SendAsync(
targetEmail,
"Subject",
emailBody
);
}
}
}
```
* To create an email content, we need to inject `ITemplateRenderer` and use the `RenderAsync` method to render a template.
* We've used `StandardEmailTemplates.Message` as standart email template. This provides us a standard and simple message template to send mails.
* The resulting email body should be like shown below:
```html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
</head>
<body>
ABP Framework provides IEmailSender service that is used to send emails.
</body>
</html>
```
### Step - 2 (Configuring Email Settings)
* Now, we need to configure some email settings by following [settings documentation](https://docs.abp.io/en/abp/latest/Settings#setting-values-in-the-application-configuration). For achieve this, open the `appsettings.json` file under `TemplateReplace.Web` and configure your email settings in **settings** section like below.
![appsettings.json](settings.jpg)
* Here, I used Google's SMTP settings to send emails via Gmail. You can change these setting values by your need.
> **Note:** If you want to use Google's SMTP server settings and send emails via Gmail, you should confirm [this](https://myaccount.google.com/u/0/lesssecureapps).
### Step - 3
* After that we need to open `TemplateReplaceDomainModule.cs` file and change its contents as below to sending real-time emails.
```csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using TemplateReplace.MultiTenancy;
using Volo.Abp.AuditLogging;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Emailing;
using Volo.Abp.FeatureManagement;
using Volo.Abp.Identity;
using Volo.Abp.IdentityServer;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.PermissionManagement.Identity;
using Volo.Abp.PermissionManagement.IdentityServer;
using Volo.Abp.SettingManagement;
using Volo.Abp.TenantManagement;
namespace TemplateReplace
{
[DependsOn(
typeof(TemplateReplaceDomainSharedModule),
typeof(AbpAuditLoggingDomainModule),
typeof(AbpBackgroundJobsDomainModule),
typeof(AbpFeatureManagementDomainModule),
typeof(AbpIdentityDomainModule),
typeof(AbpPermissionManagementDomainIdentityModule),
typeof(AbpIdentityServerDomainModule),
typeof(AbpPermissionManagementDomainIdentityServerModule),
typeof(AbpSettingManagementDomainModule),
typeof(AbpTenantManagementDomainModule),
typeof(AbpEmailingModule)
)]
public class TemplateReplaceDomainModule : AbpModule
{
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var settingManager = context.ServiceProvider.GetService<SettingManager>();
//encrypts the password on set and decrypts on get
settingManager.SetGlobalAsync(EmailSettingNames.Smtp.Password, "your_password");
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpMultiTenancyOptions>(options =>
{
options.IsEnabled = MultiTenancyConsts.IsEnabled;
});
// #if DEBUG
// context.Services.Replace(ServiceDescriptor.Singleton<IEmailSender, NullEmailSender>());
// #endif
}
}
}
```
* `NullEmailSender` is a built-in class that implements the `IEmailSender`, but writes email contents to the standard log system, rather than actually sending the emails. This class can be useful especially in development time where you generally don't want to send real emails. Therefore ABP framework defined this by default. But in our case we want to send real emails, so we must remove these lines or we must take it to the comment line.
* `Abp.Mailing.Smtp.Password` must be an encrypted value. Therefore we used `SettingManager` in here to set the password. It internally **encrypts** the values on set and **decrypts** on get.
* After all these steps, whenever we want to send an email, we can do it by using our `EmailService` class. We can inject this class and invoke the `SendAsync` method to sending email where its needed.
After sending the email we should see the template like below.
![email-message](message.jpg)
### Step - 4 (Defining New Template)
* So far we've sent mail by using standard email template of ABP. But we may want to replace the email template with the new one. We can achieve this by following the `Text Templating` [documentation](https://docs.abp.io/en/abp/latest/Text-Templating#replacing-the-existing-templates).
* In this article, I will create a email template by using free template generator named **Bee**. You can reach the free templates from [here](https://beefree.io/templates/free/).
* When we find a template for our purpose, we can hover the link and click the **get started** button to edit the template. (I chose a template named "gdpr".)
* Here, you can edit your template as below. (You can delete or add sections, edit texts, and so on.)
![bee](bee.gif)
> **Note:** After editing our template, we need to export it to reach our created template's content. You can see the **export** button top-right of the template editing page.
* After choosing and editing our free template, we can create a new **email template** in our project. For this, create a folder named `Templates` under `Emailing` folder in `TemplateReplace.Domain` and add `EmailTemplate.tpl` file inside of it. And copy-paste the below content or your template's content.
```tpl
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<meta content="width=device-width" name="viewport"/>
<meta content="IE=edge" http-equiv="X-UA-Compatible"/>
<style type="text/css">
body {
margin: 0;
padding: 0;
}
table,
td,
tr {
vertical-align: top;
border-collapse: collapse;
}
* {
line-height: inherit;
}
a[x-apple-data-detectors=true] {
color: inherit !important;
text-decoration: none !important;
}
</style>
<style id="media-query" type="text/css">
@media (max-width: 670px) {
.block-grid,
.col {
min-width: 320px !important;
max-width: 100% !important;
display: block !important;
}
.block-grid {
width: 100% !important;
}
.col {
width: 100% !important;
}
.col>div {
margin: 0 auto;
}
img.fullwidth,
img.fullwidthOnMobile {
max-width: 100% !important;
}
.no-stack .col {
min-width: 0 !important;
display: table-cell !important;
}
.no-stack.two-up .col {
width: 50% !important;
}
.no-stack .col.num2 {
width: 16.6% !important;
}
.no-stack .col.num3 {
width: 25% !important;
}
.no-stack .col.num4 {
width: 33% !important;
}
.no-stack .col.num5 {
width: 41.6% !important;
}
.no-stack .col.num6 {
width: 50% !important;
}
.no-stack .col.num7 {
width: 58.3% !important;
}
.no-stack .col.num8 {
width: 66.6% !important;
}
.no-stack .col.num9 {
width: 75% !important;
}
.no-stack .col.num10 {
width: 83.3% !important;
}
.video-block {
max-width: none !important;
}
.mobile_hide {
min-height: 0px;
max-height: 0px;
max-width: 0px;
display: none;
overflow: hidden;
font-size: 0px;
}
.desktop_hide {
display: block !important;
max-height: none !important;
}
}
</style>
</head>
<body class="clean-body" style="margin: 0; padding: 0; -webkit-text-size-adjust: 100%; background-color: #3d1554;">
<table bgcolor="#3d1554" cellpadding="0" cellspacing="0" class="nl-container" role="presentation" style="table-layout: fixed; vertical-align: top; min-width: 320px; border-spacing: 0; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; background-color: #3d1554; width: 100%;" valign="top" width="100%">
<tbody>
<tr style="vertical-align: top;" valign="top">
<td style="word-break: break-word; vertical-align: top;" valign="top">
<div style="background-color:transparent;overflow:hidden">
<div class="block-grid" style="min-width: 320px; max-width: 650px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; Margin: 0 auto; width: 100%; background-color: transparent;">
<div style="border-collapse: collapse;display: table;width: 100%;background-color:transparent;">
<div class="col num12" style="min-width: 320px; max-width: 650px; display: table-cell; vertical-align: top; width: 650px;">
<div style="width:100% !important;">
<div style="border-top:0px solid transparent; border-left:0px solid transparent; border-bottom:0px solid transparent; border-right:0px solid transparent; padding-top:35px; padding-bottom:0px; padding-right: 0px; padding-left: 0px;">
<div align="center" class="img-container center autowidth" style="padding-right: 0px;padding-left: 0px;"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div style="background-color:transparent;overflow:hidden">
<div class="block-grid" style="min-width: 320px; max-width: 650px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; Margin: 0 auto; width: 100%; background-color: transparent;">
<div style="border-collapse: collapse;display: table;width: 100%;background-color:transparent;">
<div class="col num12" style="min-width: 320px; max-width: 650px; display: table-cell; vertical-align: top; width: 642px;">
<div style="width:100% !important;">
<div style="border-top:0px solid transparent; border-left:4px solid #57366E; border-bottom:0px solid transparent; border-right:4px solid #57366E; padding-top:55px; padding-bottom:60px; padding-right: 0px; padding-left: 0px;">
<div style="color:#fbd711;font-family:Poppins, Arial, Helvetica, sans-serif;line-height:1.2;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
<div style="line-height: 1.2; font-size: 12px; color: #fbd711; font-family: Poppins, Arial, Helvetica, sans-serif; mso-line-height-alt: 14px;">
<p style="font-size: 14px; line-height: 1.2; word-break: break-word; text-align: center; mso-line-height-alt: 17px; margin: 0;"><strong><span style="font-size: 30px;">ABP Community </span></strong></p>
</div>
</div>
<div style="color:#ffffff;font-family:Poppins, Arial, Helvetica, sans-serif;line-height:1.8;padding-top:10px;padding-right:50px;padding-bottom:10px;padding-left:50px;">
<div style="line-height: 1.8; font-size: 12px; color: #ffffff; font-family: Poppins, Arial, Helvetica, sans-serif; mso-line-height-alt: 22px;">
<p style="line-height: 1.8; word-break: break-word; font-size: 14px; mso-line-height-alt: 25px; margin: 0;"><span style="font-size: 14px;">Share your experiences with the ABP Framework!</span><br/><span style="font-size: 14px;">ABP is an open source and community driven project. This guide is aims to help anyone wants to contribute to the project.</span></p>
<p style="line-height: 1.8; word-break: break-word; font-size: 14px; mso-line-height-alt: 25px; margin: 0;"><span style="font-size: 14px;">If you want to write articles or "how to" guides related to the ABP Framework and ASP.NET Core, please submit your article to the community.abp.io web site.</span></p>
</div>
</div>
<div align="center" class="button-container" style="padding-top:12px;padding-right:10px;padding-bottom:12px;padding-left:10px;">
<a href="http://www.example.com/" style="-webkit-text-size-adjust: none; text-decoration: none; display: inline-block; color: #000000; background-color: #fbd711; border-radius: 30px; -webkit-border-radius: 30px; -moz-border-radius: 30px; width: auto; width: auto; border-top: 1px solid #fbd711; border-right: 1px solid #fbd711; border-bottom: 1px solid #fbd711; border-left: 1px solid #fbd711; padding-top: 10px; padding-bottom: 10px; font-family: Poppins, Arial, Helvetica, sans-serif; text-align: center; mso-border-alt: none; word-break: keep-all;" target="_blank"><span style="padding-left:45px;padding-right:45px;font-size:18px;display:inline-block;"><span style="font-size: 16px; line-height: 2; word-break: break-word; mso-line-height-alt: 32px;"><span data-mce-style="font-size: 18px; line-height: 36px;" style="font-size: 18px; line-height: 36px;"><strong>Contribute</strong></span></span></span></a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</body>
</html>
```
* Then we need to make the template file as "Embedded Resource". We can do this as below.
* First right click to **EmailTemplate.tpl** and choose `Properties`.
![embedded-resource](embedded-resource.jpg)
* Then be sure about build action is **Embedded resource**.
![embedded-resource-2](embedded-resource-2.jpg)
### Step - 4 (Replacing the Email Template)
* To replace the current email template with our new email template, we need to override it. To achieve this, create a class named `EmailTemplateDefinitionProvider` under `Emailing` folder in `TemplateReplace.Domain` and fill it with the below content.
```csharp
using Volo.Abp.DependencyInjection;
using Volo.Abp.Emailing.Templates;
using Volo.Abp.TextTemplating;
namespace TemplateReplace.Emailing
{
public class EmailTemplateDefinitionProvider : TemplateDefinitionProvider, ITransientDependency
{
public override void Define(ITemplateDefinitionContext context)
{
var emailLayoutTemplate = context.GetOrNull(StandardEmailTemplates.Message);
emailLayoutTemplate
.WithVirtualFilePath(
"/Emailing/Templates/EmailTemplate.tpl",
isInlineLocalized: true
);
}
}
}
```
* In here we've created a template definition provider class that gets the email layout template and change the virtual file path for the template.
* This approach allows us to locate templates in any folder instead of the folder defined by the depended module. For more detail, check the [Virtual File System](https://docs.abp.io/en/abp/latest/Virtual-File-System).
### Step - 5
* Lastly, we need to configure the [Virtual File System](https://docs.abp.io/en/abp/latest/Virtual-File-System). To do this open your `TemplateReplaceDomainModule.cs` in `TemplateReplace.Domain` and update the content as below.
```csharp
using TemplateReplace.MultiTenancy;
using Volo.Abp.AuditLogging;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Emailing;
using Volo.Abp.FeatureManagement;
using Volo.Abp.Identity;
using Volo.Abp.IdentityServer;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.PermissionManagement.Identity;
using Volo.Abp.PermissionManagement.IdentityServer;
using Volo.Abp.SettingManagement;
using Volo.Abp.TenantManagement;
using Volo.Abp.VirtualFileSystem;
namespace TemplateReplace
{
[DependsOn(
typeof(TemplateReplaceDomainSharedModule),
typeof(AbpAuditLoggingDomainModule),
typeof(AbpBackgroundJobsDomainModule),
typeof(AbpFeatureManagementDomainModule),
typeof(AbpIdentityDomainModule),
typeof(AbpPermissionManagementDomainIdentityModule),
typeof(AbpIdentityServerDomainModule),
typeof(AbpPermissionManagementDomainIdentityServerModule),
typeof(AbpSettingManagementDomainModule),
typeof(AbpTenantManagementDomainModule),
typeof(AbpEmailingModule)
)]
public class TemplateReplaceDomainModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpMultiTenancyOptions>(options =>
{
options.IsEnabled = MultiTenancyConsts.IsEnabled;
});
//Add this configuration
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<TemplateReplaceDomainModule>();
});
}
}
}
```
* And now when we send a new email, we should see our newly defined template as the message like below.
![email-last](email-last.jpg)
## Text Template Management
* Generally, more than one e-mail is required in applications. We create email templates for **"password changes"** or **"welcome"** etc in our applications. In such cases, it is necessary to create different templates for each mail. ABP Commercial allows us to perform these operations on UI in a simple way. Text Template Management provides UI to easily create and manage email templates.
![template-definitions](template-definitions.png)
* ABP Commercial's [Text Template Management](https://commercial.abp.io/modules/Volo.TextTemplateManagement) module is really fascinating. It makes it super easy to stores and edits template contents. We can list all templates on a page, editing them, localizing them, and so on.
![inline-content](inline-content.png)
* ABP Commercial's text template management module, allows us to modify a template through the UI.
* I highly recommend you to [check it out](https://commercial.abp.io/modules/Volo.TextTemplateManagement).
## References
* [Text Templating](https://docs.abp.io/en/abp/latest/Text-Templating)
* [Emailing](https://docs.abp.io/en/abp/latest/Emailing)
* [Virtual File System](https://docs.abp.io/en/abp/latest/Virtual-File-System)

BIN
docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/bee.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

BIN
docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/db-migrator-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/db-migrator-2.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/db-migrator-3.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/email-last.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/embedded-resource-2.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/embedded-resource.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

BIN
docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/inline-content.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/message.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/settings.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
docs/en/Community-Articles/2020-09-09-Replacing-Email-Template-and-Sending-Emails/template-definitions.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

122
docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/POST.md

@ -0,0 +1,122 @@
# How to Setup Azure Active Directory and Integrate Abp Angular Application
This guide demonstrates how to register an application to Azure Active Directory and integrate AzureAD to an ABP angular application that enables users to sign in using OAuth 2.0 with credentials from **Azure Active Directory**.
## Authentication Flow
Abp angular applications use **Authentication Code with PKCE** (specs [here](https://tools.ietf.org/html/rfc7636)) which is the most suitable flow for spa applications by the time this article is written since implicit flow is deprecated.
The most common question is;
> Where to put OpenId connection code in angular project?
The answer is, **you don't**. Abp angular application is integrated with backend code (HttpApi.Host project) where it loads the configurations, **permissions** etc. For none-tiered angular applications, **HttpApi.Host** project also has IdentityServer4 embedded; also serving as **Authorization Server**. Angular application authentication flow is shown below.
<img src="auth-diagram.jpeg" alt="auth-diagram" style="zoom:50%;" />
> What if I want Azure AD as my authorization server and not IdentityServer?
This means your application will be using AzureAD user store for authentication. By registering both angular app and HttpApi to AzureAD, authentication might work but **authorization won't**. Users need to be registered to Abp identity system for auditing, permissions etc. So the flow should be 3rd party registration.
## Setting up OpenId Connection
Lets start with adding OpenId connection. Open the **HttpApiHostModule.cs** and update the **ConfigureAuthentication** method as below:
```csharp
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);
context.Services.AddAuthentication()
.AddIdentityServerAuthentication(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = false;
options.ApiName = "NonTieredAngular";
options.JwtBackChannelHandler = new HttpClientHandler()
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};
})
.AddOpenIdConnect("AzureOpenId", "Azure AD OpenId", options =>
{
options.Authority = "https://login.microsoftonline.com/" + configuration["AzureAd:TenantId"] + "/v2.0/";
options.ClientId = configuration["AzureAd:ClientId"];
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.CallbackPath = configuration["AzureAd:CallbackPath"];
options.ClientSecret = configuration["AzureAd:ClientSecret"];
options.RequireHttpsMetadata = false;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("email");
});
```
> If you are using tiered (separate identity server) application, open **IdentityServerModule.cs** and add the OpenIdConnection manually to **ConfigureServices** method as following:
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);
context.Services.AddAuthentication()
.AddOpenIdConnect("AzureOpenId", "Azure AD OpenId", options =>
{
... // Same configuration above
});
```
Now we can add AzureAD settings. Open the **appsettings.json** located in **HttpApi.Host** project (or **IdentityServer** project if you are using tiered application). Add the following;
```csharp
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<azureAd-tenant-id>",
"ClientId": "<azureAd-client-id>",
"Domain": "domain.onmicrosoft.com",
"CallbackPath": "/signin-azuread-oidc",
"ClientSecret": "<azureAd-client-secret>"
},
```
Keep on mind that **App.SelfUrl** + **AzureAd.CallbackPath** will be used in AzureAD app registration. We'll update the AzureAd settings after registering the application in Azure Portal.
## Setting up Azure Active Directory
Navigate to Manage Azure Active Directory in [azure portal](https://portal.azure.com/). Go to **App registrations** on left side menu and hit New registration.
![azure-app-registration](azure-app-registration.jpg)
Enter a name for your application and **App.SelfUrl** + **AzureAd.CallbackPath** as redirect uri then register.
<img src="azure-app-register.JPG" alt="azure-app-register" style="zoom:75%;" />
Now navigate to **Authentication** on the left menu and enable **ID tokens**.
![azure-app-authentication](azure-app-authentication.jpg)
We also need to set a client secret. Navigate to **Certificates & secrets** menu on the left and create a new client secret.
![azure-app-secret](azure-app-secret.jpg)
**Copy** the secret and update your appsettings.json **AzureAd.ClientSecret** field.
![azure-app-overview](azure-app-overview.jpg)
Also update your **AzureAd.TenantId** and **AzureAd.ClientId** fields with the information located under **Overview** menu. And that's all.
Next time you hit login, you should be seeing login screen enabled Azure AD like below.
![app-login](app-login.JPG)
# FAQ
* I am getting errors when trying to login to AzureAD.
* You can check [this article FAQ](https://community.abp.io/articles/how-to-use-the-azure-active-directory-authentication-for-mvc-razor-page-applications-4603b9cf) which covers many errors.
* But I don't want my users to see default login screen. I want my users to login **only** from AzureAD.
* You can **mimic** this behaviour by customizing the login page and instantly trigger Azure AD provider click. For more info, you can check [this article](https://community.abp.io/articles/how-to-customize-the-login-page-for-mvc-razor-page-applications-9a40f3cd).

BIN
docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/app-login.JPG

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/auth-diagram.jpeg

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/azure-app-authentication.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

BIN
docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/azure-app-overview.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/azure-app-register.JPG

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/azure-app-registration.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/azure-app-secret.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

317
docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/Using-DevExtremeAngularComponents-With-The-ABP-Framework.md

@ -0,0 +1,317 @@
# Using DevExtreme Angular Components With the ABP Framework
In this article, I will show you how to integrate the [DevExpress Angular components](https://js.devexpress.com/Documentation/Guide/Angular_Components/DevExtreme_Angular_Components/) to a project created using the ABP Framework startup templates. Then I will use the [DataGrid](https://js.devexpress.com/Documentation/Guide/Widgets/DataGrid/Overview/) component to show a list of users on the UI.
## Create the Project
Let's create a new web application with the Angular UI using [ABP CLI](https://docs.abp.io/en/abp/latest/CLI#new):
```shell
abp new DevExtremeAngular -u angular
```
> For detail information about how to generate and start up a project, please refer to the [official docs](https://docs.abp.io/en/abp/latest/Getting-Started?UI=NG&DB=EF&Tiered=No). For the scope of this post, we will not go into details of the backend applications.
## Running the Solution
### The Server Side
Server side contains multiple projects in the solution:
![A screenshot showing DevExtremeAngular.DbMigrator and DevExtremeAngular.HttpApi.Host](project-setup.png)
Run following projects in order;
* Run `DevExtremeAngular.DbMigrator` to create the database and seed the initial data.
* Run `DevExtremeAngular.HttpApi.Host` project to make the backend API up & running.
### The Angular Application
Open a command line terminal and navigate to `angular` folder then run `yarn` or `npm install` based on which package you are using.
After installation process is done, you can start your angular project by running `yarn start` or `npm start`. This command should serve the application and open the application in your default browser. If it doesn't open, you can navigate to http://localhost:4200 in your browser:
![A screenshot showing localhost is running](localhost-running.png)
You can login to the application by using following credentials:
> _Default admin username is **admin** and password is **1q2w3E\***_
![A screenshot showing login page](login-screen.png)
After successful login, you should be redirected to home page.
## Install DevExtreme
You can follow [the guide](https://js.devexpress.com/Documentation/Guide/Angular_Components/Getting_Started/Add_DevExtreme_to_an_Angular_CLI_Application/) provided by **DevExtreme** team or apply the following steps.
* `npm install devextreme devextreme-angular` or `yarn add devextreme devextreme-angular`
* Import given two following styles in `angular.json` file:
```javascript
// ...
"styles": [
// ...
"src/styles.scss",
"node_modules/devextreme/dist/css/dx.common.css",
"node_modules/devextreme/dist/css/dx.light.css"
]
```
* Add `dx-viewport` to classes of `body` in `index.html`
```html
<body class="bg-light dx-viewport">
<app-root>
<div class="donut centered"></div>
</app-root>
</body>
```
After completing these steps, you need to restart the angular application.
## Create a lazy Angular Module for DevExtreme Demo
Let's create a module which will be loaded lazily.
Open up a terminal and navigate to `angular` to run following command.
```shell
ng g m dev-extreme --route dev-extreme --module app
```
...or with `npx`, if you do not have `angular-cli` installed...
```shell
npx ng g m dev-extreme --route dev-extreme --module app
```
Your terminal should log the following output:
```shell
CREATE src/app/dev-extreme/dev-extreme-routing.module.ts (361 bytes)
CREATE src/app/dev-extreme/dev-extreme.module.ts (379 bytes)
CREATE src/app/dev-extreme/dev-extreme.component.scss (0 bytes)
CREATE src/app/dev-extreme/dev-extreme.component.html (26 bytes)
CREATE src/app/dev-extreme/dev-extreme.component.spec.ts (655 bytes)
CREATE src/app/dev-extreme/dev-extreme.component.ts (295 bytes)
UPDATE src/app/app-routing.module.ts (362 bytes)
```
The Angular CLI has created a module and configured it to lazy-load at `/dev-extreme` path.
The last step to be able to see our newly created module in the browser, open `route.provider.ts` and edit the array being added into the routes.
```typescript
// ...
routes.add([
{
path: '/',
name: '::Menu:Home',
iconClass: 'fas fa-home',
order: 1,
layout: eLayoutType.application,
},
{
path: '/dev-extreme',
name: 'Dev Extreme',
order: 2,
layout: eLayoutType.application,
},
]);
// ...
```
After completing the steps above, you should be able to see `Dev Extreme` on the header and when you click on it, you should be redirected to `/dev-extreme` page and see the following message on the screen.
![A screenshot showing a page that says dev-extreme works!](dev-extreme-page.png)
## Display users on the dev-extreme page
For this demo, we will list users on the screen. We already have `admin` as our first user.
Let's add couple of more to the list in `Administration -> Identity Management -> Users` page.
![A screenshot showing users page after adding couple of users](users.png)
Now we are ready to fetch our users and display them on `/dev-extreme` page.
Firstly, let's create a service for our component.
Navigate to the `dev-extreme` folder and run following command. If you run this command at the root, the service will be generated next to `app.module.ts`
```shell
ng g s dev-extreme
```
Following files should be created
```shell
CREATE src/app/dev-extreme/dev-extreme.service.spec.ts (378 bytes)
CREATE src/app/dev-extreme/dev-extreme.service.ts (139 bytes)
```
Let's import and inject `IdentityService` as dependency in `dev-extreme.service.ts`. After then, let's create a stream called `users$` to retrieve the users.
`identityService.getUsers` returns `ABP.PagedResponse` which contains two fields, `items` and `totalCount`. We are only interested in `items` for now.
When we apply the steps described above, the final version of `dev-extreme.service` should be as follows
```typescript
import { Injectable } from '@angular/core';
import { map } from 'rxjs/operators';
import { IdentityService } from '@abp/ng.identity';
@Injectable({
providedIn: 'root',
})
export class DevExtremeService {
users$ = this.service.getUsers().pipe(map((result) => result.items));
constructor(private service: IdentityService) {}
}
```
Now we can simply inject `DevExtremeService` as public and utilize `users$` stream in `dev-extreme.component.ts` as follows:
```typescript
import { Component } from '@angular/core';
import { DevExtremeService } from './dev-extreme.service';
@Component({
selector: 'app-dev-extreme',
templateUrl: './dev-extreme.component.html',
styleUrls: ['./dev-extreme.component.scss'],
})
export class DevExtremeComponent {
constructor(public service: DevExtremeService) {}
}
```
And use it within `dev-extreme.component.html`
```html
<ng-container *ngIf="service.users$ | async as users">
<ul>
<li *ngFor="let user of users">
{{ user.name }}
</li>
</ul>
</ng-container>
```
This should list names of the users on the screen
![A screenshot showing list users on the dev extreme page](users-on-dev-extreme.png)
## Use DxDataGrid to list the users
You can take a look at [demo](https://js.devexpress.com/Demos/WidgetsGallery/Demo/DataGrid/ColumnCustomization/Angular/Light/) provided by **DevExtreme** team or apply the following steps.
Now, our application is ready to use `dx-data-grid` in `dev-extreme.component.ts`
Firstly, we need to import `DxDataGridModule` in our module as follows.
```typescript
// ...
import { DxDataGridModule } from 'devextreme-angular';
@NgModule({
// ...
imports: [
// ...
DxDataGridModule
],
})
export class DevExtremeModule {}
```
At this point `dx-data-grid` is avaliable within our module and we can use it in our template.
Change `dev-extreme.component.html` to the following
```html
<ng-container *ngIf="service.users$ | async as users">
<dx-data-grid [dataSource]="users"></dx-data-grid>
</ng-container>
```
It should display a table on the screen
![A screenshot displaying dev extreme data grid with lots of columns](devextreme-first.png)
Since, we did not specify any columns, `dx-data-grid` displayed every column avaliable. Let's pick some columns to make it more readable.
Change `dev-extreme.component.html` to the following:
```html
<ng-container *ngIf="service.users$ | async as users">
<dx-data-grid [dataSource]="users">
<dxi-column dataField="userName"></dxi-column>
<dxi-column dataField="name"></dxi-column>
<dxi-column dataField="surname"></dxi-column>
<dxi-column dataField="email"></dxi-column>
<dxi-column dataField="phoneNumber"></dxi-column>
</dx-data-grid>
</ng-container>
```
which will display following table on the screen
![A screenshot displaying dev extreme data grid with these columns: username, name, surname, email and phone number](devextreme-second.png)
We can also utilize `abpLocalization` pipe to translate the headers of the table. To use `abpLocalization` pipe in our templates, we need to import `CoreModule` from `@abp/ng.core` into our module.
```typescript
import { CoreModule } from '@abp/ng.core';
@NgModule({
// ...
imports: [
// ...
CoreModule
],
})
export class DevExtremeModule {}
```
And change the template to the following:
```html
<ng-container *ngIf="service.users$ | async as users">
<dx-data-grid [dataSource]="users">
<dxi-column
dataField="userName"
[caption]="'AbpIdentity::DisplayName:UserName' | abpLocalization"
></dxi-column>
<dxi-column
dataField="name"
[caption]="'AbpIdentity::DisplayName:Name' | abpLocalization"
></dxi-column>
<dxi-column
dataField="surname"
[caption]="'AbpIdentity::DisplayName:Surname' | abpLocalization"
></dxi-column>
<dxi-column
dataField="email"
[caption]="'AbpIdentity::DisplayName:Email' | abpLocalization"
></dxi-column>
<dxi-column
dataField="phoneNumber"
[caption]="'AbpIdentity::DisplayName:PhoneNumber' | abpLocalization"
></dxi-column>
</dx-data-grid>
</ng-container>
```
The headers should change when a new language is selected;
![A gif showing the headers of the table getting translated into the chosen language](devextreme-final.gif)
## Conclusion
In this article, we have seen how to integrate `DevExtreme` angular components into a project generated by `ABP CLI`.
You can download source code of [the demo here](https://github.com/abpframework/abp-samples/tree/master/DevExtreme-Angular).

BIN
docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/dev-extreme-page.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/devextreme-final.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 KiB

BIN
docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/devextreme-first.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/devextreme-second.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/localhost-running.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/login-screen.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/project-setup.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/users-on-dev-extreme.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
docs/en/Community-Articles/2020-09-28-Using-DevExtremeAngularComponents-With-The-ABP-Framework/users.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

160
docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md

@ -0,0 +1,160 @@
# How to Add Custom Properties to the User Entity
## Introduction
In this step-by-step article, I will explain how you can customize the user entity class, which is available in every web application you create using the ABP framework, according to your needs. When you read this article, you will learn how to override the services of built-in modules, extend the entities, extend data transfer objects and customize the user interface in the applications you develop using the ABP framework.
You can see the screenshots below which we will reach at the end of the article.
![custom-identity-user-list](./custom-identity-user-list.png)
![new-user](./new-user.png)
## Preparing the Project
### Startup template and the initial run
Abp Framework offers startup templates to get into the work faster. We can create a new startup template using Abp CLI:
`abp new CustomizeUserDemo`
> In this article, I will go through the MVC application, but it will work also in the [Angular](https://docs.abp.io/en/abp/latest/Getting-Started?UI=NG&DB=EF&Tiered=No) application.
After the download is finished, we can run **CustomizeUserDemo.DbMigrator** project to create the database migrations and seed the initial data (admin user, role, etc). Then we can run `CustomizeUserDemo.Web` to see that our application is working.
> Default admin username is **admin** and password is **1q2w3E\***
![initial-project](./initial-project.png)
In this article, we will go through a scenario together and find the solutions to our questions through this scenario. However, since the scenario is not a real-life scenario, it may be strange, please don't get too about this issue :)
## Step-1
Add two new properties to the `AppUser` in the Users folder of the **CustomizeUserDemo.Domain** project as follows:
```csharp
public string Title { get; protected set; }
public int Reputation { get; protected set; }
```
## Step-2
Create the Users folder in the **CustomizeUserDemo.Domain.Shared** project, create the class `UserConsts` inside the folder and update the class you created as below:
```csharp
public static class UserConsts
{
public const string TitlePropertyName = "Title";
public const string ReputationPropertyName = "Reputation";
public const int MaxTitleLength = 64;
public const double MaxReputationValue = 1_000;
public const double MinReputationValue = 1;
}
```
## Step-3
Update the `CustomizeUserDemoEfCoreEntityExtensionMappings` class in the **CustomizeUserDemo.EntityFramework** project in the EntityFrameworkCore folder as below:
```csharp
public static class CustomizeUserDemoEfCoreEntityExtensionMappings
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public static void Configure()
{
CustomizeUserDemoGlobalFeatureConfigurator.Configure();
CustomizeUserDemoModuleExtensionConfigurator.Configure();
OneTimeRunner.Run(() =>
{
ObjectExtensionManager.Instance
.MapEfCoreProperty<IdentityUser, string>(
nameof(AppUser.Title),
(entityBuilder, propertyBuilder) =>
{
propertyBuilder.IsRequired();
propertyBuilder.HasMaxLength(UserConsts.MaxTitleLength);
}
).MapEfCoreProperty<IdentityUser, int>(
nameof(AppUser.Reputation),
(entityBuilder, propertyBuilder) =>
{
propertyBuilder.HasDefaultValue(UserConsts.MinReputationValue);
}
);
});
}
}
```
This class can be used to map these extra properties to table fields in the database. Please read [this](https://docs.abp.io/en/abp/latest/Customizing-Application-Modules-Extending-Entities) article to improve your understanding of what we are doing.
So far, we have added our extra features to the `User` entity and matched these features with the `ef core`.
Now we need to add migration to see what has changed in our database. This for, open the Package Manager Console (PMC) under the menu Tools > NuGet Package Manager.
![nuget-package-manager](./nuget-package-manager.png)
Select the **CustomizeUserDemo.EntityFramework.DbMigrations** as the **default project** and execute the following command:
```bash
Add-Migration "Updated-User-Entity"
```
![added-new-migration](./added-new-migration.png)
This will create a new migration class inside the `Migrations` folder of the **CustomizeUserDemo.EntityFrameworkCore.DbMigrations** project.
> If you are using another IDE than the Visual Studio, you can use `dotnet-ef` tool as [documented here](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli#create-a-migration).
Finally, run the **CustomizeUserDemo.DbMigrator** project to update the database.
When we updated the database, you can see that the `Title` and `Reputation` columns are added to the `Users` table.
![user-table](./user-table.png)
## Step-4
Open the `CustomizeUserDemoModuleExtensionConfigurator` in the **CustomizeUserDemo.Domain.Shared** project, and change the contents of the `ConfigureExtraProperties` method as shown below:
```csharp
private static void ConfigureExtraProperties()
{
ObjectExtensionManager.Instance.Modules().ConfigureIdentity(identity =>
{
identity.ConfigureUser(user =>
{
user.AddOrUpdateProperty<string>(
UserConsts.TitlePropertyName,
options =>
{
options.Attributes.Add(new RequiredAttribute());
options.Attributes.Add(
new StringLengthAttribute(UserConsts.MaxTitleLength)
);
}
);
user.AddOrUpdateProperty<int>(
UserConsts.ReputationPropertyName,
options =>
{
options.DefaultValue = UserConsts.MinReputationValue;
options.Attributes.Add(
new RangeAttribute(UserConsts.MinReputationValue, UserConsts.MaxReputationValue)
);
}
);
});
});
}
```
That's it. Now let's run the application and look at the Identity user page. You can also try to edit and recreate a record if you want, it will work even though we haven't done anything extra. Here is the magic code behind ABP framework.
If there is a situation you want to add, you can click the contribute button or make a comment. Also, if you like the article, don't forget to share it :)
Happy coding :)

BIN
docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/added-new-migration.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/custom-identity-user-list.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/initial-project.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/new-user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/nuget-package-manager.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/user-table.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

35
docs/en/Customizing-Application-Modules-Overriding-Services.md

@ -162,6 +162,41 @@ This example class inherits from the `IdentityUserManager` [domain service](Doma
Check the [localization system](Localization.md) to learn how to localize the error messages.
### Example: Overriding a Controller
````csharp
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.Account;
using Volo.Abp.DependencyInjection;
namespace MyProject.Controllers
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(AccountController))]
public class MyAccountController : AccountController
{
public MyAccountController(IAccountAppService accountAppService)
: base(accountAppService)
{
}
public override async Task SendPasswordResetCodeAsync(
SendPasswordResetCodeDto input)
{
Logger.LogInformation("Your custom logic...");
await base.SendPasswordResetCodeAsync(input);
}
}
}
````
This example replaces the `AccountController` (An API Controller defined in the [Account Module](Modules/Account.md)) and overrides the `SendPasswordResetCodeAsync` method.
**`[ExposeServices(typeof(AccountController))]` is essential** here since it registers this controller for the `AccountController` in the dependency injection system. `[Dependency(ReplaceServices = true)]` is also recommended to clear the old registration (even the ASP.NET Core DI system selects the last registered one).
### Overriding Other Classes
Overriding controllers, framework services, view component classes and any other type of classes registered to dependency injection can be overridden just like the examples above.

53
docs/en/Data-Filtering.md

@ -102,9 +102,58 @@ namespace Acme.BookStore
````
* [Inject](Dependency-Injection.md) the `IDataFilter` service to your class.
* Use the `Disable` method within a `using` statement to create a code block where the `ISoftDelete` filter is disabled inside it (Always use it inside a `using` block to guarantee that the filter is reset to its previous state).
* Use the `Disable` method within a `using` statement to create a code block where the `ISoftDelete` filter is disabled inside it.
`IDataFilter.Enable` method can be used to enable a filter. `Enable` and `Disable` methods can be used in a nested way to define inner scopes.
In addition to the `Disable<T>()` method;
* `IDataFilter.Enable<T>()` method can be used to enable a filter. `Enable` and `Disable` methods can be used in a **nested** way to define inner scopes.
* `IDataFilter.IsEnabled<T>()` can be used to check whether a filter is currently enabled or not.
> Always use the `Disable` and `Enable` methods it inside a `using` block to guarantee that the filter is reset to its previous state.
### The Generic IDataFilter Service
`IDataFilter` service has a generic version, `IDataFilter<TFilter>` that injects a more restricted and explicit data filter based on the filter type.
````csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore
{
public class MyBookService : ITransientDependency
{
private readonly IDataFilter<ISoftDelete> _softDeleteFilter;
private readonly IRepository<Book, Guid> _bookRepository;
public MyBookService(
IDataFilter<ISoftDelete> softDeleteFilter,
IRepository<Book, Guid> bookRepository)
{
_softDeleteFilter = softDeleteFilter;
_bookRepository = bookRepository;
}
public async Task<List<Book>> GetAllBooksIncludingDeletedAsync()
{
//Temporary disable the ISoftDelete filter
using (_softDeleteFilter.Disable())
{
return await _bookRepository.GetListAsync();
}
}
}
}
````
* This usage determines the filter type while injecting the `IDataFilter<T>` service.
* In this case you can use the `Disable()` and `Enable()` methods without specifying the filter type.
## AbpDataFilterOptions

4
docs/en/Distributed-Event-Bus-Kafka-Integration.md

@ -89,7 +89,7 @@ Defining multiple connections is allowed. In this case, you can specify the conn
}
````
This allows you to use multiple RabbitMQ server in your application, but select one of them for the event bus.
This allows you to use multiple Kafka cluster in your application, but select one of them for the event bus.
You can use any of the [ClientConfig](https://docs.confluent.io/current/clients/confluent-kafka-dotnet/api/Confluent.Kafka.ClientConfig.html) properties as the connection properties.
@ -164,4 +164,4 @@ Configure<AbpKafkaOptions>(options =>
});
````
Using these options classes can be combined with the `appsettings.json` way. Configuring an option property in the code overrides the value in the configuration file.
Using these options classes can be combined with the `appsettings.json` way. Configuring an option property in the code overrides the value in the configuration file.

65
docs/en/Distributed-Event-Bus-Rebus-Integration.md

@ -0,0 +1,65 @@
# Distributed Event Bus Rebus Integration
> This document explains **how to configure the [Rebus](http://mookid.dk/category/rebus/)** as the distributed event bus provider. See the [distributed event bus document](Distributed-Event-Bus.md) to learn how to use the distributed event bus system
## Installation
Use the ABP CLI to add [Volo.Abp.EventBus.Rebus](https://www.nuget.org/packages/Volo.Abp.EventBus.Rebus) NuGet package to your project:
* Install the [ABP CLI](https://docs.abp.io/en/abp/latest/CLI) if you haven't installed before.
* Open a command line (terminal) in the directory of the `.csproj` file you want to add the `Volo.Abp.EventBus.Rebus` package.
* Run `abp add-package Volo.Abp.EventBus.Rebus` command.
If you want to do it manually, install the [Volo.Abp.EventBus.Rebus](https://www.nuget.org/packages/Volo.Abp.EventBus.Rebus) NuGet package to your project and add `[DependsOn(typeof(AbpEventBusRebusModule))]` to the [ABP module](Module-Development-Basics.md) class inside your project.
## Configuration
You can configure using the standard [configuration system](Configuration.md), like using the [options](Options.md) classes.
### The Options Classes
`AbpRebusEventBusOptions` classe can be used to configure the event bus options for the Rebus.
You can configure this options inside the `PreConfigureServices` of your [module](Module-Development-Basics.md).
**Example: Minimize configuration**
```csharp
PreConfigure<AbpRebusEventBusOptions>(options =>
{
options.InputQueueName = "eventbus";
});
```
Rebus has many options, you can use the `Configurer` property of `AbpRebusEventBusOptions` class to configure.
Default events are **stored in memory**. See the [rebus document](https://github.com/rebus-org/Rebus/wiki/Transport) for more details.
**Example: Configure the store**
````csharp
PreConfigure<AbpRebusEventBusOptions>(options =>
{
options.InputQueueName = "eventbus";
options.Configurer = rebusConfigurer =>
{
rebusConfigurer.Transport(t => t.UseMsmq("eventbus"));
rebusConfigurer.Subscriptions(s => s.UseJsonFile(@"subscriptions.json"));
};
});
````
You can use the `Publish` properpty of `AbpRebusEventBusOptions` class to change the publishing method
**Example: Configure the event publishing**
````csharp
PreConfigure<AbpRebusEventBusOptions>(options =>
{
options.InputQueueName = "eventbus";
options.Publish = async (bus, type, data) =>
{
await bus.Publish(data);
};
});
````

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

@ -8,7 +8,8 @@ Distributed event bus system provides an **abstraction** that can be implemented
* `LocalDistributedEventBus` is the default implementation that implements the distributed event bus to work as in-process. Yes! The **default implementation works just like the [local event bus](Local-Event-Bus.md)**, if you don't configure a real distributed provider.
* `RabbitMqDistributedEventBus` implements the distributed event bus with the [RabbitMQ](https://www.rabbitmq.com/). See the [RabbitMQ integration document](Distributed-Event-Bus-RabbitMQ-Integration.md) to learn how to configure it.
* `KafkaDistributedEventBus` implements the distributed event bus with the [RabbitMQ](https://kafka.apache.org/). See the [Kafka integration document](Distributed-Event-Bus-Kafka-Integration.md) to learn how to configure it.
* `KafkaDistributedEventBus` implements the distributed event bus with the [Kafka](https://kafka.apache.org/). See the [Kafka integration document](Distributed-Event-Bus-Kafka-Integration.md) to learn how to configure it.
* `RebusDistributedEventBus` implements the distributed event bus with the [Rebus](http://mookid.dk/category/rebus/). See the [Rebus integration document](Distributed-Event-Bus-Rebus-Integration.md) to learn how to configure it.
Using a local event bus as default has a few important advantages. The most important one is that: It allows you to write your code compatible to distributed architecture. You can write a monolithic application now that can be split into microservices later. It is a good practice to communicate between bounded contexts (or between application modules) via distributed events instead of local events.
@ -44,7 +45,7 @@ namespace AbpDemo
public virtual async Task ChangeStockCountAsync(Guid productId, int newCount)
{
await _distributedEventBus.PublishAsync(
new StockCountChangedEvent
new StockCountChangedEto
{
ProductId = productId,
NewCount = newCount
@ -300,4 +301,4 @@ namespace AbpDemo
}
````
This example uses the `AutoMap` attribute of the AutoMapper to configure the mapping. You could create a profile class instead. Please refer to the AutoMapper document for more options.
This example uses the `AutoMap` attribute of the AutoMapper to configure the mapping. You could create a profile class instead. Please refer to the AutoMapper document for more options.

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

@ -23,6 +23,16 @@ Find `UseSqlServer()` calls in your solution, replace with `UseSqlite()`. Check
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.
An example connection string is
```
{
"ConnectionStrings": {
"Default": "Filename=./MySQLiteDBFile.sqlite"
}
}
```
You typically will change the `appsettings.json` inside the `.DbMigrator` and `.Web` projects, but it depends on your solution structure.
## Re-Generate the Migrations
@ -38,4 +48,4 @@ 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.
It is ready. Just run the application and enjoy coding.

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

@ -1,10 +1,57 @@
# Getting Started with the React Native
````json
//[doc-params]
{
"Tiered": ["No", "Yes"]
}
````
ABP platform provide basic [React Native](https://reactnative.dev/) startup template to develop mobile applications **integrated to your ABP based backends**.
When you **create a new application** as described in the [getting started document](Getting-Started.md), you have to add `-m react-native` option to include `react-native` project in your solution.
![React Native gif](./images/react-native-introduction.gif)
## How to Prepare Development Environment
Please follow the steps below to prepare your development environment for React Native.
1. **Install Node.js:** Please visit [Node.js downloads page](https://nodejs.org/en/download/) and download proper Node.js v12 or v14 installer for your OS. An alternative is to install [NVM](https://github.com/nvm-sh/nvm) and use it to have multiple versions of Node.js in your operating system.
2. **[Optional] Install Yarn:** You may install Yarn v1 (not v2) following the instructions on [the installation page](https://classic.yarnpkg.com/en/docs/install). Yarn v1 delivers an arguably better developer experience compared to npm v6 and below. You may skip this step and work with npm, which is built-in in Node.js, instead.
3. **[Optional] Install VS Code:** [VS Code](https://code.visualstudio.com/) is a free, open-source IDE which works seamlessly with TypeScript. Although you can use any IDE including Visual Studio or Rider, VS Code will most likely deliver the best developer experience when it comes to React Native projects.
4. **Install an Emulator:** React Native applications need an Android emulator or an iOS simulator to run on your OS. See the [Android Studio Emulator](https://docs.expo.io/workflow/android-simulator/) or [iOS Simulator](https://docs.expo.io/workflow/ios-simulator/) on expo.io documentation to learn how to set up an emulator.
## How to Start a New React Native Project
You have multiple options to initiate a new React Native project that works with ABP:
### 1. Using ABP CLI
ABP CLI is probably the most convenient and flexible way to initiate an ABP solution with a React Native application. Simply [install the ABP CLI](../../CLI.md) and run the following command in your terminal:
```shell
abp new MyCompanyName.MyProjectName -csf -u <angular or mvc> -m react-native
```
> To see further options in the CLI, please visit the [CLI manual](../../CLI.md).
This command will prepare a solution with an **Angular** or an **MVC** (depends on your choice), a **.NET Core**, and a **React Native** project in it.
### 2. Direct Download
You may [download a solution scaffold directly on ABP.io](https://abp.io/get-started) if you are more comfortable with GUI or simply want to try ABP without installing the CLI.
## Configure Your Local IP Address
Please do the following:
1. Click on the "DIRECT DOWNLOAD" tab.
2. Fill out the short form about your project.
3. Click on the "Create now" button.
...and a customized download will start in a few seconds.
## How to Configure & Run the Backend
> React Native application does not trust the auto-generated .NET HTTPS certificate. You should use **HTTP** during the development.
A React Native application running on an Android emulator or a physical phone **can not connect to the backend** on `localhost`. To fix this problem, it is necessary to run the backend application on your **local IP address**.
@ -25,19 +72,14 @@ A React Native application running on an Android emulator or a physical phone **
{{ end }}
## Run the Server Application
Run the backend application as described in the [getting started document](Getting-Started.md).
> React Native application does not trust the auto-generated .NET HTTPS certificate. You should use **HTTP** during the development.
Go to the `react-native` folder, open a command line terminal, type the `yarn` command (we suggest to the [yarn](https://yarnpkg.com/) package manager while `npm install` will also work):
## How to Configure & Run the React Native Application
```bash
yarn
```
* Open the `Environment.js` in the `react-native` folder and replace the `localhost` address on the `apiUrl` and `issuer` properties with your local IP address as shown below:
1. Make sure the [database migration is complete](./Getting-Started?UI=NG&DB=EF&Tiered=No#create-the-database) and the [API is up and running](./Getting-Started?UI=NG&DB=EF&Tiered=No#run-the-application).
2. Open `react-native` folder and run `yarn` or `npm install` if you have not already.
3. Open the `Environment.js` in the `react-native` folder and replace the `localhost` address on the `apiUrl` and `issuer` properties with your local IP address as shown below:
![react native environment local IP](images/rn-environment-local-ip.png)
@ -51,22 +93,21 @@ yarn
{{ end }}
Once all node modules are loaded, execute `yarn start` (or `npm start`) command:
```bash
yarn start
```
4. Run `yarn start` or `npm start`. Wait Expo CLI to start. Expo CLI opens the management interface on the `http://localhost:19002/` address.
Wait Expo CLI to start. Expo CLI opens the management interface on the `http://localhost:19002/` address.
> The React Native application was generated with [Expo](https://expo.io/). Expo is a set of tools built around React Native to help you quickly start an app and, while it has many features.
![expo-interface](images/rn-expo-interface.png)
In the above management interface, you can start the application with an Android emulator, an iOS simulator or a physical phone by the scan the QR code with the [Expo Client](https://expo.io/tools#client).
> See the [Android Studio Emulator](https://docs.expo.io/workflow/android-simulator/), [iOS Simulator](https://docs.expo.io/workflow/ios-simulator/) documents on expo.io.
![React Native login screen on iPhone 11](images/rn-login-iphone.png)
Enter **admin** as the username and **1q2w3E*** as the password to login to the application.
The application is up and running. You can continue to develop your application based on this startup template.
## See Also
* [React Native project structure](./Startup-Templates/Application#react-native)

168
docs/en/Getting-Started.md

@ -3,13 +3,15 @@
````json
//[doc-params]
{
"UI": ["MVC","NG"],
"UI": ["MVC", "Blazor", "NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
````
This tutorial explains how to create a new {{if UI == "MVC"}} ASP.NET Core MVC (Razor Pages) web {{else if UI == "NG"}} Angular {{end}} application using the startup template.
This tutorial explains how to create a new web application using the [application startup template](Startup-Templates/Application.md).
> This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. For other options, please change the preference on top of this document.
## Setup Your Development Environment
@ -20,11 +22,11 @@ First things first! Let's setup your development environment before creating the
The following tools should be installed on your development machine:
* [Visual Studio 2019 (v16.4+)](https://visualstudio.microsoft.com/vs/) for Windows / [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/). <sup id="a-editor">[1](#f-editor)</sup>
* [Visual Studio 2019](https://visualstudio.microsoft.com/vs/) for Windows / [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/). <sup id="a-editor">[1](#f-editor)</sup>
* [.NET Core 3.1+](https://www.microsoft.com/net/download/dotnet-core/)
* [Node v12 or v14](https://nodejs.org/en/)
* [Yarn v1.20+ (not v2)](https://classic.yarnpkg.com/en/docs/install) <sup id="a-yarn">[2](#f-yarn)</sup> or npm v6+ (installed with Node)
* [Node v12 or v14](https://nodejs.org/)
* [Yarn v1.20+ (not v2)](https://classic.yarnpkg.com/en/docs/install) <sup id="a-yarn">[2](#f-yarn)</sup> or npm v6+ (already installed with Node)
{{ if Tiered == "Yes" }}
* [Redis](https://redis.io/) (the startup solution uses the Redis as the [distributed cache](Caching.md)).
@ -37,7 +39,7 @@ The following tools should be installed on your development machine:
### Install the ABP CLI
[ABP CLI](./CLI.md) is a command line interface that is used to automate some common tasks for ABP based applications.
[ABP CLI](./CLI.md) is a command line interface that is used to automate some common tasks for ABP based solutions.
> ABP CLI is a free & open source tool for the ABP framework.
@ -55,105 +57,60 @@ dotnet tool update -g Volo.Abp.Cli
## Create a New Project
> This document assumes that you prefer to use **{{ UI_Value }}** as the UI framework and **{{ DB_Value }}** as the database provider. For other options, please change the preference on top of this document.
### Using the ABP CLI to Create a New Project
Use the `new` command of the ABP CLI to create a new project:
````shell
abp new Acme.BookStore{{if UI == "NG"}} -u angular {{end}}{{if DB == "Mongo"}} -d mongodb{{end}}{{if Tiered == "Yes" && UI != "NG"}} --tiered {{else if Tiered == "Yes" && UI == "NG"}}--separate-identity-server{{end}}
abp new Acme.BookStore{{if UI == "NG"}} -u angular{{else if UI == "Blazor"}} -u blazor{{end}}{{if DB == "Mongo"}} -d mongodb{{end}}{{if Tiered == "Yes"}}{{if UI == "MVC"}} --tiered{{else}} --separate-identity-server{{end}}{{end}}
````
{{ if UI == "NG" }}
> You can use different level of namespaces; e.g. BookStore, Acme.BookStore or Acme.Retail.BookStore.
* `-u` argument specifies the UI framework, `angular` in this case.
> Alternatively, you can select the "Direct Download" tab from the [ABP Framework web site](https://abp.io/get-started) to create a new solution.
{{ if Tiered == "Yes" }}
* `--separate-identity-server` argument is used to separate the identity server application from the API host application. If not specified, you will have a single endpoint on the server.
{{ end }}
{{ if UI == "MVC" }}
{{ end }}
* `--tiered` argument is used to create N-tiered solution where authentication server, UI and API layers are physically separated.
{{ if DB == "Mongo" }}
{{ else }}
* `-d` argument specifies the database provider, `mongodb` in this case.
* `--separate-identity-server` argument is used to separate the identity server application from the API host application. If not specified, you will have a single endpoint on the server.
{{ end }}
{{ if Tiered == "Yes" && UI != "NG" }}
* `--tiered` argument is used to create N-tiered solution where authentication server, UI and API layers are physically separated.
{{ end }}
> You can use different level of namespaces; e.g. BookStore, Acme.BookStore or Acme.Retail.BookStore.
#### ABP CLI Commands & Options
### ABP CLI Commands & Options
[ABP CLI document](./CLI.md) covers all of the available commands and options for the ABP CLI. This document uses the [application startup template](Startup-Templates/Application.md) to create a new web application. See the [ABP Startup Templates](Startup-Templates/Index.md) document for other templates.
> Alternatively, you can select the "Direct Download" tab from the [ABP Framework web site](https://abp.io/get-started) to create a new solution.
## The Solution Structure
{{ if UI == "MVC" }}
After creating your project, you will have the following solution folders & files:
![](images/solution-files-mvc.png)
You will see the following solution structure when you open the `.sln` file in the Visual Studio:
{{if DB == "Mongo"}}
![vs-default-app-solution-structure](images/vs-app-solution-structure-mongodb.png)
{{else}}
![vs-default-app-solution-structure](images/vs-app-solution-structure{{if Tiered == "Yes"}}-tiered{{end}}.png)
{{end}}
{{ else if UI == "NG" }}
There are three folders in the created solution:
### The Solution Structure
![](images/solution-files-non-mvc.png)
The solution has a layered structure (based on the [Domain Driven Design](Domain-Driven-Design.md)) and contains unit & integration test projects. See the [application template document](Startup-Templates/Application.md) to understand the solution structure in details.
* `angular` folder contains the Angular UI application.
* `aspnet-core` folder contains the backend solution.
Open the `.sln` (Visual Studio solution) file under the `aspnet-core` folder:
![vs-angular-app-backend-solution-structure](images/vs-spa-app-backend-structure{{if DB == "Mongo"}}-mongodb{{end}}.png)
{{ end }}
> ###### About the projects in your solution
>
> Your solution may have slightly different structure based on your **UI**, **database** and other preferences.
{{ if DB == "Mongo" }}
The solution has a layered structure (based on the [Domain Driven Design](Domain-Driven-Design.md)) and also contains unit & integration test projects.
#### MongoDB Transactions
{{ if DB == "EF" }}
The [startup template](Startup-templates/Index.md) **disables** transactions in the `.MongoDB` project by default. If your MongoDB server supports transactions, you can enable the it in the *YourProjectMongoDbModule* class:
Integration tests projects are properly configured to work with **EF Core** & **SQLite in-memory** database.
```csharp
Configure<AbpUnitOfWorkDefaultOptions>(options =>
{
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Auto;
});
```
{{ else if DB == "Mongo" }}
Integration tests projects are properly configured to work with in-memory **MongoDB** database created per test (used [Mongo2Go](https://github.com/Mongo2Go/Mongo2Go) library).
> Or you can delete this code since this is already the default behavior.
{{ end }}
> See the [application template document](Startup-Templates/Application.md) to understand the solution structure in details.
## Create the Database
### Connection String
Check the **connection string** in the `appsettings.json` file under the {{if UI == "MVC"}}{{if Tiered == "Yes"}}`.IdentityServer` and `.HttpApi.Host` projects{{else}}`.Web` project{{end}}{{else if UI == "NG" }}`.HttpApi.Host` project{{end}}:
Check the **connection string** in the `appsettings.json` file under the {{if Tiered == "Yes"}}`.IdentityServer` and `.HttpApi.Host` projects{{else}}{{if UI=="MVC"}}`.Web` project{{else}}`.HttpApi.Host` project{{end}}{{end}}
{{ if DB == "EF" }}
@ -163,7 +120,7 @@ Check the **connection string** in the `appsettings.json` file under the {{if UI
}
````
The solution is configured to use **Entity Framework Core** with **MS SQL Server**. EF Core supports [various](https://docs.microsoft.com/en-us/ef/core/providers/) database providers, so you can use any supported DBMS. See [the Entity Framework integration document](https://docs.abp.io/en/abp/latest/Entity-Framework-Core) to learn how to [switch to another DBMS](Entity-Framework-Core-Other-DBMS.md).
The solution is configured to use **Entity Framework Core** with **MS SQL Server** by default. EF Core supports [various](https://docs.microsoft.com/en-us/ef/core/providers/) database providers, so you can use any supported DBMS. See [the Entity Framework integration document](Entity-Framework-Core.md) to learn how to [switch to another DBMS](Entity-Framework-Core-Other-DBMS.md).
### Apply the Migrations
@ -171,7 +128,7 @@ The solution uses the [Entity Framework Core Code First Migrations](https://docs
#### Apply Migrations Using the DbMigrator
The solution comes with a `.DbMigrator` console application which applies migrations and also seed the initial data. It is useful on development as well as on production environment.
The solution comes with a `.DbMigrator` console application which applies migrations and also **seeds the initial data**. It is useful on **development** as well as on **production** environment.
> `.DbMigrator` project has its own `appsettings.json`. So, if you have changed the connection string above, you should also change this one.
@ -183,7 +140,7 @@ Right click to the `.DbMigrator` project and select **Set as StartUp Project**
![db-migrator-output](images/db-migrator-output.png)
> Initial [seed data](Data-Seeding.md) creates the `admin` user in the database which is then used to login to the application. So, you need to use `.DbMigrator` at least once for a new database.
> Initial [seed data](Data-Seeding.md) creates the `admin` user in the database (with the password is `1q2w3E*`) which is then used to login to the application. So, you need to use `.DbMigrator` at least once for a new database.
#### Using EF Core Update-Database Command
@ -223,7 +180,7 @@ The solution is configured to use **MongoDB** in your local computer, so you nee
### Seed Initial Data
The solution comes with a `.DbMigrator` console application which seeds the initial data. It is useful on development as well as on production environment.
The solution comes with a `.DbMigrator` console application which **seeds the initial data**. It is useful on **development** as well as on **production** environment.
> `.DbMigrator` project has its own `appsettings.json`. So, if you have changed the connection string above, you should also change this one.
@ -235,7 +192,7 @@ Right click to the `.DbMigrator` project and select **Set as StartUp Project**
![db-migrator-output](images/db-migrator-output.png)
> Initial [seed data](Data-Seeding.md) creates the `admin` user in the database which is then used to login to the application. So, you need to use `.DbMigrator` at least once for a new database.
> Initial [seed data](Data-Seeding.md) creates the `admin` user in the database (with the password is `1q2w3E*`) which is then used to login to the application. So, you need to use `.DbMigrator` at least once for a new database.
{{ end }}
@ -245,27 +202,27 @@ Right click to the `.DbMigrator` project and select **Set as StartUp Project**
{{ if Tiered == "Yes" }}
Ensure that the `.IdentityServer` project is the startup project. Run the application which will open a **login** page in your browser.
1. Ensure that the `.IdentityServer` project is the startup project. Run this application that will open a **login** page in your browser.
> Use Ctrl+F5 in Visual Studio (instead of F5) to run the application without debugging. If you don't have a debug purpose, this will be faster.
You can login, but you cannot enter to the main application here. This is just the authentication server.
You can login, but you cannot enter to the main application here. This is **just the authentication server**.
Ensure that the `.HttpApi.Host` project is the startup project and run the application which will open a **Swagger UI** in your browser.
2. Ensure that the `.HttpApi.Host` project is the startup project and run the application which will open a **Swagger UI** in your browser.
![swagger-ui](images/swagger-ui.png)
This is the API application that is used by the web application.
This is the HTTP API that is used by the web application.
Lastly, ensure that the `.Web` project is the startup project and run the application which will open a **welcome** page in your browser
3. Lastly, ensure that the `.Web` project is the startup project and run the application which will open a **welcome** page in your browser
![mvc-tiered-app-home](images/bookstore-home.png)
Click to the **login** button which will redirect you to the `Identity Server` to login to the application:
Click to the **login** button which will redirect you to the *authentication server* to login to the application:
![bookstore-login](images/bookstore-login.png)
{{ else }}
{{ else # Tiered != "Yes" }}
Ensure that the `.Web` project is the startup project. Run the application which will open the **login** page in your browser:
@ -273,11 +230,11 @@ Ensure that the `.Web` project is the startup project. Run the application which
![bookstore-login](images/bookstore-login.png)
{{ end }}
{{ end # Tiered }}
{{ else if UI != "MVC" }}
{{ else # UI != "MVC" }}
#### Running the HTTP API Host (server-side)
### Running the HTTP API Host (Server Side)
{{ if Tiered == "Yes" }}
@ -287,15 +244,15 @@ Ensure that the `.IdentityServer` project is the startup project. Run the applic
You can login, but you cannot enter to the main application here. This is just the authentication server.
{{ end }}
Ensure that the `.HttpApi.Host` project is the startup project and run the application which will open a Swagger UI:
{{ if Tiered == "No" }}
{{ else # Tiered == "No" }}
Ensure that the `.HttpApi.Host` project is the startup project and run the application which will open a Swagger UI:
> Use Ctrl+F5 in Visual Studio (instead of F5) to run the application without debugging. If you don't have a debug purpose, this will be faster.
{{ end }}
{{ end # Tiered }}
![swagger-ui](images/swagger-ui.png)
@ -305,12 +262,25 @@ You can see the application APIs and test them here. Get [more info](https://swa
>
> Most of the HTTP APIs require authentication & authorization. If you want to test authorized APIs, manually go to the `/Account/Login` page, enter `admin` as the username and `1q2w3E*` as the password to login to the application. Then you will be able to execute authorized APIs too.
{{ end }}
{{ end # UI }}
{{ if UI == "NG" }}
#### Running the Angular application (client-side)
{{ if UI == "Blazor" }}
### Running the Blazor Application (Client Side)
Ensure that the `.Blazor` project is the startup project and run the application.
> Use Ctrl+F5 in Visual Studio (instead of F5) to run the application without debugging. If you don't have a debug purpose, this will be faster.
Go to the `angular` folder, open a command line terminal, type the `yarn` command (we suggest to the [yarn](https://yarnpkg.com/) package manager while `npm install` will also work in most cases)
Once the application starts, click to the **Login** link on to header, which redirects you to the authentication server to enter a username and password:
![bookstore-login](images/bookstore-login.png)
{{ else if UI == "NG" }}
### Running the Angular Application (Client Side)
Go to the `angular` folder, open a command line terminal, type the `yarn` command (we suggest to the [yarn](https://yarnpkg.com/) package manager while `npm install` will also work)
```bash
yarn
@ -322,11 +292,7 @@ Once all node modules are loaded, execute `yarn start` (or `npm start`) command:
yarn start
```
This will take care of compiling your `TypeScript` code, and automatically reloading your browser.
After it finishes, `Angular Live Development Server` will be listening on localhost:4200,
open your web browser and navigate to [localhost:4200](http://localhost:4200/)
It may take a longer time for the first build. Once it finishes, it opens the Angular UI in your default browser with the [localhost:4200](http://localhost:4200/) address.
![bookstore-login](images/bookstore-login.png)
@ -338,7 +304,7 @@ Enter **admin** as the username and **1q2w3E*** as the password to login to the
If you want to include a [React Native](https://reactnative.dev/) project in your solution, add `-m react-native` (or `--mobile react-native`) argument to project creation command. This is a basic React Native startup template to develop mobile applications integrated to your ABP based backends.
See the "[Getting Started with the React Native](Getting-Started-React-Native.md)" document to learn how to configure and run the React Native application.
See the [Getting Started with the React Native](Getting-Started-React-Native.md) document to learn how to configure and run the React Native application.
## Next

3
docs/en/JavaScript/Dynamic-JavaScript-API-Clients.md

@ -1,3 +0,0 @@
## Dynamic JavaScript API Clients
TODO

100
docs/en/Localization.md

@ -2,7 +2,7 @@
ABP's localization system is seamlessly integrated to the `Microsoft.Extensions.Localization` package and compatible with the [Microsoft's localization documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization). It adds some useful features and enhancements to make it easier to use in real life application scenarios.
## Volo.Abp.Localization Package
## Installation
> This package is already installed by default with the startup template. So, most of the time, you don't need to install it manually.
@ -100,8 +100,6 @@ Configure<AbpLocalizationOptions>(options =>
> The [application startup template](Startup-Templates/Application.md) sets `DefaultResourceType` to the localization resource of the application.
See the *Client Side* section below for a use case.
### Short Localization Resource Name
Localization resources are also available in the client (JavaScript) side. So, setting a short name for the localization resource makes it easy to use localization texts. Example:
@ -156,13 +154,13 @@ services.Configure<AbpLocalizationOptions>(options =>
* If an extension file defines the same localized string, it overrides the string.
## Getting Localized Texts
## Getting the Localized Texts
### Server Side
Getting the localized text is pretty standard.
Getting the localized text on the server side is pretty standard.
### Simplest Usage In A Class
#### Simplest Usage In A Class
Just inject the `IStringLocalizer<TResource>` service and use it like shown below:
````C#
public class MyService
@ -183,9 +181,13 @@ public class MyService
##### Format Arguments
Format arguments can be passed after the localization key. If your message is `Hello {0}, welcome!`, then you can pass the `{0}` argument to the localizer like `_localizer["HelloMessage", "John"]`
Format arguments can be passed after the localization key. If your message is `Hello {0}, welcome!`, then you can pass the `{0}` argument to the localizer like `_localizer["HelloMessage", "John"]`.
> Refer to the [Microsoft's localization documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization) for details about using the localization.
#### Simplest Usage In A Razor View/Page
### Using In A Razor View/Page
Use `IHtmlLocalizer<T>` in razor views/pages;
````c#
@inject IHtmlLocalizer<TestResource> Localizer
@ -193,53 +195,59 @@ Format arguments can be passed after the localization key. If your message is `H
<h1>@Localizer["HelloWorld"]</h1>
````
Refer to the [Microsoft's localization documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization) for details about using localization on the server side.
### Client Side
ABP provides JavaScript services to use the same localized texts in the client side.
#### getResource
`abp.localization.getResource` function is used to get a localization resource:
````js
var testResource = abp.localization.getResource('Test');
````
Then you can localize a string based on this resource:
### Special Base Classes
````js
var str = testResource('HelloWorld');
````
Some ABP Framework base classes provide a `L` property to use the localizer even easier.
#### localize
**Example: Localize a text in an application service method**
`abp.localization.localize` function is a shortcut where you can both specify the text name and the resource name:
```csharp
using System.Threading.Tasks;
using MyProject.Localization;
using Volo.Abp.Application.Services;
````js
var str = abp.localization.localize('HelloWorld', 'Test');
````
namespace MyProject
{
public class TestAppService : ApplicationService
{
public TestAppService()
{
LocalizationResource = typeof(MyProjectResource);
}
`HelloWorld` is the text to localize, where `Test` is the localization resource name here.
public async Task DoIt()
{
var str = L["HelloWorld"];
}
}
}
```
If you don't specify the localization resource name, it uses the default localization resource defined on the `AbpLocalizationOptions` (see the *Default Resource* section above). Example:
When you set the `LocalizationResource` in the constructor, the `ApplicationService` class uses that resource type when you use the `L` property, just like in the `DoIt()` method.
````js
var str = abp.localization.localize('HelloWorld'); //uses the default resource
````
Setting `LocalizationResource` in every application service can be tedious. You can create an abstract base application service class, set it there and derive your application services from that base class. This is already implemented when you create a new project with the [startup templates](Startup-Templates/Application.md). So, you can simply inherit from the base class directly use the `L` property:
##### Format Arguments
```csharp
using System.Threading.Tasks;
If your localized string contains arguments, like `Hello {0}, welcome!`, you can pass arguments to the localization methods. Examples:
namespace MyProject
{
public class TestAppService : MyProjectAppService
{
public async Task DoIt()
{
var str = L["HelloWorld"];
}
}
}
```
````js
var str1 = abp.localization.getResource('Test')('HelloWelcomeMessage', 'John');
var str2 = abp.localization.localize('HelloWorld', 'Test', 'John');
````
The `L` property is also available for some other base classes like `AbpController` and `AbpPageModel`.
Both of the samples above produce the output `Hello John, welcome!`.
## The Client Side
## See Also
See the following documents to learn how to reuse the same localization texts in the JavaScript side;
* [Localization in Angular UI](UI/Angular/Localization.md)
* [Localization for the MVC / Razor Pages UI](UI/AspNetCore/JavaScript-API/Localization.md)
* [Localization for the Blazor UI](UI/Blazor/Localization.md)
* [Localization for the Angular UI](UI/Angular/Localization.md)

117
docs/en/Migration-Guides/Abp-4_0.md

@ -0,0 +1,117 @@
# ABP Framework 3.3 to 4.0 Migration Guide
## Auto API Controller Route Changes
The route calculation for the [Auto API Controllers](https://docs.abp.io/en/abp/latest/API/Auto-API-Controllers) is changing with the ABP Framework version 4.0 ([#5325](https://github.com/abpframework/abp/issues/5325)). Previously, **camelCase** route paths were being used. Beginning from the version 4.0, it uses **kebab-case** route paths where it is possible.
**A typical auto API before v4.0**
![route-before-4](images/route-before-4.png)
**camelCase route parts become kebab-case with 4.0**
![route-4](images/route-4.png)
If it is hard to change it for your application, you can continue to use the version 3.x route strategy, by following one of the approaches;
* Set `UseV3UrlStyle` to `true` in the options of the `options.ConventionalControllers.Create(...)` method. Example:
````csharp
options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.UseV3UrlStyle = true;
});
````
This approach effects only the controllers for the `BookStoreApplicationModule`.
* Set `UseV3UrlStyle` to `true` for the `AbpConventionalControllerOptions` to set it globally. Example:
```csharp
Configure<AbpConventionalControllerOptions>(options =>
{
options.UseV3UrlStyle = true;
});
```
Setting it globally effects all the modules in a modular application.
## Identity Server Changes
ABP Framework upgrades the [IdentityServer4](https://www.nuget.org/packages/IdentityServer4) library from 3.x to 4.x with the ABP Framework version 4.0. IdentityServer 4.x has a lot of changes, some of them are **breaking changes in the data structure**.
### Entity Changes
Entity changed don't directly affect your application, however it is good to know.
#### ApiScope
As the **most important breaking change**, Identity Server 4.x places the `ApiScope` as an independent aggregate root. Previously it was a part of the to `ApiResource` aggregate. This requires manual operation. See the *Database Changes* section.
Also, added `Enabled(string)` and `Description(bool,true)` properties.
#### ApiResource
* Added `AllowedAccessTokenSigningAlgorithms (string)` and `ShowInDiscoveryDocument(bool, default: true)` properties
#### Client
* Added `RequireRequestObject (bool)` and `AllowedIdentityTokenSigningAlgorithms (string)` properties.
* Changed default value of `RequireConsent` from `true` to `false`.
* Changed default value of `RequirePkce` from `false` to `true`.
#### DeviceFlowCodes
* Added `SessionId (string)` and `Description (string)` properties.
#### PersistedGrant
* Added `SessionId (string)` and `Description(string)` and `ConsumedTime (DateTime?)` properties
### Database Changes
> Attention: **Please backup your database** before the migration!
**If you are upgrading from 3.x, then there are some change should be done in your database.**
#### Database Schema Migration
If you are using **Entity Framework Core**, you need to add a new database migration, using the `Add-Migration` command, and apply changes to the database. Please **review the migration** script and read the sections below to understand if it affects your existing data. Otherwise, you may **loose some of your configuration**, which may not be easy to remember and re-configure.
#### Seed Code
If you haven't customize the `IdentityServerDataSeedContributor` and haven't customized the initial data inside the `IdentityServer*` tables;
1. Update `IdentityServerDataSeedContributor` class by comparing to [the latest code](https://github.com/abpframework/abp/blob/dev/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain/IdentityServer/IdentityServerDataSeedContributor.cs). You probably only need to add the `CreateApiScopesAsync` method and the code related to it.
2. Then you can simply clear all the **table data** in these tables then execute the `DbMigrator` application again to fill it with the new configuration.
#### Migrating the Configuration Data
If you've customize your IdentityServer configuration in the database or in the seed data, you should understand the changes and upgrade your code/data accordingly. Especially, the following changes will affect your application:
- `IdentityServerApiScopes` table's `Enabled` field is dropped and re-created. So, you need to manually enable the api scopes again.
- `IdentityServerApiResourceScopes` table is dropped and recreated. So, you need to backup and move your current data to the new table.
- `IdentityServerIdentityResourceClaims` table is dropped and recreated. So, you need to backup and move your current data to the new table.
You may need to perform additional steps based on how much you made custom configurations.
### Other IdentityServer Changes
IdentityServer has removed the [public origin option](https://github.com/IdentityServer/IdentityServer4/pull/4335). It was resolving http/https conversion problems, but they decided to leave this to the developer. This is especially needed if you use a reverse proxy where your external protocol is HTTPS but internal protocol is HTTP.
One simple solution is to add such a middleware into your ASP.NET Core pipeline, at the beginning.
```
app.Use((httpContext, next) =>
{
httpContext.Request.Scheme = "https";
return next();
});
```
> This sample is obtained from the [ASP.NET Core documentation](https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer#scenarios-and-use-cases). You can use it if you always use HTTPS in all environments.
### Related Resources
* https://leastprivilege.com/2020/06/19/announcing-identityserver4-v4-0/
* https://github.com/IdentityServer/IdentityServer4/issues/4592

14
docs/en/Migration-Guides/BlazorUI-3_3.md

@ -0,0 +1,14 @@
# Migration Guide for the Blazor UI from the v3.2 to the v3.3
## Startup Template Changes
* Remove `Volo.Abp.Account.Blazor` NuGet package from your `.Blazor.csproj` and add `Volo.Abp.TenantManagement.Blazor` NuGet package.
* Remove the ``typeof(AbpAccountBlazorModule)`` from the dependency list of *YourProjectBlazorModule* class and add the `typeof(AbpTenantManagementBlazorModule)`.
* Add `@using Volo.Abp.BlazoriseUI` and `@using Volo.Abp.BlazoriseUI.Components` into the `_Imports.razor` file.
* Remove the `div` with `id="blazor-error-ui"` (with its contents) from the `wwwroot/index.html ` file, since the ABP Framework now shows error messages as a better message box.
* Update the`AddOidcAuthentication` options in your *YourProjectBlazorModule* class as described in the issue [#5913](https://github.com/abpframework/abp/issues/5913).
## BlazoriseCrudPageBase to AbpCrudPageBase
Renamed `BlazoriseCrudPageBase` to `AbpCrudPageBase`. Just update the usages. It also has some changes, you may need to update method calls/usages manually.

BIN
docs/en/Migration-Guides/images/route-4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
docs/en/Migration-Guides/images/route-before-4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

4
docs/en/Module-Development-Basics.md

@ -57,7 +57,7 @@ public class BlogModule : AbpModule
}
````
See Configuration (TODO: link) document for more about the configuration system.
See the [Configuration](Configuration.md) document for more about the configuration system.
#### Pre & Post Configure Services
@ -139,4 +139,4 @@ A depended module may depend on another module, but you only need to define your
There are **two types of modules.** They don't have any structural difference but categorized by functionality and purpose:
- **Framework modules**: These are **core modules of the framework** like caching, emailing, theming, security, serialization, validation, EF Core integration, MongoDB integration... etc. They do not have application/business functionalities but makes your daily development easier by providing common infrastructure, integration and abstractions.
- **Application modules**: These modules implement **specific application/business functionalities** like blogging, document management, identity management, tenant management... etc. They generally have their own entities, services, APIs and UI components. See [pre-built application modules](Modules/Index.md).
- **Application modules**: These modules implement **specific application/business functionalities** like blogging, document management, identity management, tenant management... etc. They generally have their own entities, services, APIs and UI components. See [pre-built application modules](Modules/Index.md).

2
docs/en/Modules/Identity.md

@ -2,7 +2,7 @@
Identity module is used to manage [organization units](Organization-Units.md), roles, users and their permissions, based on the Microsoft Identity library.
See [the source code](https://github.com/abpframework/abp/tree/dev/modules/identity). Documentation will come soon...
**See [the source code](https://github.com/abpframework/abp/tree/dev/modules/identity). Documentation will come soon...**
## Identity Security Log

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

Loading…
Cancel
Save