Browse Source

Merge branch 'dev' into maliming/audit-exceptions

pull/9116/head
maliming 5 years ago
parent
commit
6cd72f2d33
  1. 15
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en-GB.json
  2. 15
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  3. 15
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json
  4. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en-GB.json
  5. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  6. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/tr.json
  7. 6
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en-GB.json
  8. 12
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  9. 6
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json
  10. 16
      docs/en/CLI.md
  11. 199
      docs/en/Community-Articles/2020-04-27-Use-Azure-Active-Directory-Authentication-for-MVC-Razor-Page-Applications/POST.md
  12. 25
      docs/en/Community-Articles/2020-09-16-How-to-Setup-Azure-Active-Directory-and-Integrate-Abp-Angular-Application/POST.md
  13. 1981
      docs/en/Domain-Driven-Design-Implementation-Guide.md
  14. 190
      docs/en/Modules/Setting-Management.md
  15. 106
      docs/en/Modules/Tenant-Management.md
  16. 3
      docs/en/Road-Map.md
  17. 24
      docs/en/Tutorials/Todo/Index.md
  18. 2
      docs/en/UI/Angular/Account-Module.md
  19. 2
      docs/en/UI/Angular/Authorization.md
  20. 37
      docs/en/UI/Angular/Custom-Setting-Page.md
  21. 2
      docs/en/UI/Blazor/Overall.md
  22. 8
      docs/en/docs-nav.json
  23. 0
      docs/en/images/custom-settings.png
  24. BIN
      docs/en/images/module-tenant-management-actions.png
  25. BIN
      docs/en/images/module-tenant-management-new-tenant.png
  26. BIN
      docs/en/images/module-tenant-management-page.png
  27. BIN
      docs/en/images/my-setting-group-blazor.png
  28. BIN
      docs/en/images/my-setting-group-component-contributor.png
  29. BIN
      docs/en/images/my-setting-group-component.png
  30. BIN
      docs/en/images/my-setting-group-page-contributor.png
  31. BIN
      docs/en/images/my-setting-group-ui.png
  32. BIN
      docs/en/images/my-setting-group-view-component.png
  33. 17
      docs/zh-Hans/CLI.md
  34. 192
      docs/zh-Hans/Modules/Setting-Management.md
  35. 41
      docs/zh-Hans/UI/Angular/Custom-Setting-Page.md
  36. 4
      docs/zh-Hans/docs-nav.json
  37. 0
      docs/zh-Hans/images/custom-settings.png
  38. BIN
      docs/zh-Hans/images/my-setting-group-blazor.png
  39. BIN
      docs/zh-Hans/images/my-setting-group-component-contributor.png
  40. BIN
      docs/zh-Hans/images/my-setting-group-component.png
  41. BIN
      docs/zh-Hans/images/my-setting-group-page-contributor.png
  42. BIN
      docs/zh-Hans/images/my-setting-group-ui.png
  43. BIN
      docs/zh-Hans/images/my-setting-group-view-component.png
  44. 49
      framework/Volo.Abp.sln
  45. 14
      framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Volo.Abp.AspNetCore.Components.Web.BasicTheme.csproj
  46. 17
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.csproj
  47. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Table/AbpTableTagHelperService.cs
  48. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js
  49. 2
      framework/src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj
  50. 1
      framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj
  51. 8
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs
  52. 78
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/InstallLibsCommand.cs
  53. 9
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/LIbs/IInstallLibsService.cs
  54. 231
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/LIbs/InstallLibsService.cs
  55. 53
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/LIbs/ResourceMapping.cs
  56. 23
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/ProjectNameValidator.cs
  57. 1
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
  58. 5
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs
  59. 14
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpModelBuilderObjectExtensions.cs
  60. 70
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionInfoExtensions.cs
  61. 74
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs
  62. 39
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionInfoEfCoreMappingOptions.cs
  63. 2
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs
  64. 6
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs
  65. 18
      framework/test/Volo.Abp.Cli.Core.Tests/Volo/Abp/Cli/ProjectNameValidation_Tests.cs
  66. 28
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Domain/TestEntityExtensionConfigurator.cs
  67. 9
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs
  68. 2
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/IAuditLogRepository.cs
  69. 10
      modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingDbContextModelBuilderExtensions.cs
  70. 6
      modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs
  71. 7
      modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogRepository.cs
  72. 4
      modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContextModelCreatingExtensions.cs
  73. 65
      modules/basic-theme/Volo.Abp.BasicTheme.sln
  74. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/AbpAspNetCoreComponentsServerBasicThemeModule.cs
  75. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/BasicThemeToolbarContributor.cs
  76. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Bundling/BlazorBasicThemeBundles.cs
  77. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Bundling/BlazorBasicThemeScriptContributor.cs
  78. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Bundling/BlazorBasicThemeStyleContributor.cs
  79. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/FodyWeavers.xml
  80. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/FodyWeavers.xsd
  81. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/LanguageSwitch.razor
  82. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/LoginDisplay.razor
  83. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/LoginDisplay.razor.cs
  84. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/_Imports.razor
  85. 6
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Volo.Abp.AspNetCore.Components.Server.BasicTheme.csproj
  86. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/AbpAspNetCoreComponentsWebBasicThemeModule.cs
  87. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/FodyWeavers.xml
  88. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/FodyWeavers.xsd
  89. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/App.razor
  90. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/AppWithoutAuth.razor
  91. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/Branding.razor
  92. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor
  93. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor.cs
  94. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainLayout.razor
  95. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainLayout.razor.cs
  96. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor
  97. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor.cs
  98. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavToolbar.razor
  99. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavToolbar.razor.cs
  100. 0
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/RedirectToLogin.razor

15
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en-GB.json

@ -197,6 +197,19 @@
"RemoveCache": "Remove Cache",
"Language": "Language",
"Optional": "Optional",
"CreateArticleLanguageInfo": "The language in which the article is written"
"CreateArticleLanguageInfo": "The language in which the article is written",
"Menu:Quotation": "Quotation",
"Menu:Invoice": "Invoice",
"Menu:PaymentRequests": "Payment Requests",
"Permission:PaymentRequests": "Payment Requests",
"PaymentRequests": "Payment Requests",
"Creator": "Creator",
"ExtraProperties": "Extra Properties",
"Organization": "Organization",
"Waiting": "Waiting",
"Completed": "Completed",
"Failed": "Failed",
"PaymentRequestDeletionWarningMessage": "This payment request will be deleted. Do you confirm that?",
"Payment": "Payment"
}
}

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

@ -277,6 +277,19 @@
"ThisExtensionIsNotAllowed": "This extension is not allowed.",
"TheFileIsTooLarge": "The file is too large!",
"ArticleDeletionConfirmationMessage": "Are you sure you want to hard delete this article?",
"ChooseCoverImage": "Choose a cover image..."
"ChooseCoverImage": "Choose a cover image...",
"Menu:Quotation": "Quotation",
"Menu:Invoice": "Invoice",
"Menu:PaymentRequests": "Payment Requests",
"Permission:PaymentRequests": "Payment Requests",
"PaymentRequests": "Payment Requests",
"Creator": "Creator",
"ExtraProperties": "Extra Properties",
"Organization": "Organization",
"Waiting": "Waiting",
"Completed": "Completed",
"Failed": "Failed",
"PaymentRequestDeletionWarningMessage": "This payment request will be deleted. Do you confirm that?",
"Payment": "Payment"
}
}

15
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json

@ -227,6 +227,19 @@
"TheFileIsTooLarge": "Dosya çok büyük.",
"ArticleDeletionConfirmationMessage": "Bu makaleyi kalıcı olarak silmek istediğinizden emin misiniz?",
"ChooseCoverImage": "Bir kapak resmi seçin...",
"CoverImage": "Kapak Resmi"
"CoverImage": "Kapak Resmi",
"Menu:Quotation": "Fiyatlandırma",
"Menu:Invoice": "Fatura",
"Menu:PaymentRequests": "Ödeme İstekleri",
"Permission:PaymentRequests": "Ödeme İstekleri",
"PaymentRequests": "Ödeme İstekleri",
"Creator": "Oluşturan",
"ExtraProperties": "Ekstra Özellikler",
"Organization": "Organizasyon",
"Waiting": "Bekliyor",
"Completed": "Tamamlandı",
"Failed": "Başarısız Oldu",
"PaymentRequestDeletionWarningMessage": "Bu ödeme isteği silinecek. Bunu onaylıyor musun?",
"Payment": "Ödeme"
}
}

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

@ -100,6 +100,7 @@
"VolosoftSharingInformationMessage": "I would like Volosoft to share my information with select partners so I can receive relevant information about their products and services.",
"WeWillSendYouADownloadLink": "We've sent the file to {0}.",
"InvalidFormInputs": "Please, type the valid information specified on the form.",
"DDDBookEmailBody": "Thank you. <br /> To download your book, <a href=\"{0}\">click here</a>."
"DDDBookEmailBody": "Thank you. <br /> To download your book, <a href=\"{0}\">click here</a>.",
"FreeDDDEBook": "Free DDD E-Book"
}
}

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

@ -357,6 +357,7 @@
"VolosoftSharingInformationMessage": "I would like Volosoft to share my information with select partners so I can receive relevant information about their products and services.",
"WeWillSendYouADownloadLink": "A link to download the e-book has been sent to {0}.<br/> Check your inbox / junk / spam boxes!",
"InvalidFormInputs": "Please, type the valid information specified on the form.",
"DDDBookEmailBody": "Thank you. <br /> To download your book, <a href=\"{0}\">click here</a>."
"DDDBookEmailBody": "Thank you. <br /> To download your book, <a href=\"{0}\">click here</a>.",
"FreeDDDEBook": "Free DDD E-Book"
}
}

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

@ -97,6 +97,7 @@
"VolosoftSharingInformationMessage": "Volosoft'un ürünlerimi seçkin ortaklarla paylaşmasını kabul ediyorum, böylece ilgili ortakların ürünleri ve hizmetleri hakkında ilgili bilgileri alabilirim.",
"WeWillSendYouADownloadLink": "{0} adresine email gönderilmiştir.",
"InvalidFormInputs": "Lütfen formda belirtilen geçerli bilgileri yazınız.",
"DDDBookEmailBody": "Teşekkürler. <br /> Kitabı indirmek için, <a href=\"{0}\">buraya tıklayınız</a>."
"DDDBookEmailBody": "Teşekkürler. <br /> Kitabı indirmek için, <a href=\"{0}\">buraya tıklayınız</a>.",
"FreeDDDEBook": "Ücretsiz DDD E-Kitap"
}
}

6
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en-GB.json

@ -255,8 +255,6 @@
"Surname": "Surname",
"CompanyName": "Company Name",
"DoYouAgreePrivacyPolicy": "I agree to the Terms & Conditions and <a href=\"https://commercial.abp.io/Privacy\">Privacy Policy</a>.",
"VolosoftMarketingInformationMessage": "I would like information, tips, and offers about Solutions for Businesses and Organizations and other Volosoft products and services.",
"VolosoftSharingInformationMessage": "I would like Volosoft to share my information with select partners so I can receive relevant information about their products and services.",
"Free": "Free",
"DDDEBook": "DDD E-book",
"PracticalGuideForImplementingDDD": "This book is a practical guide for implementing the Domain Driven Design with the ABP Framework.",
@ -270,6 +268,8 @@
"WeWillSendYouADownloadLink": "We've sent the file to {0}.",
"GoHome": "Go Home",
"InvalidFormInputs": "Please, type the valid information specified on the form.",
"DDDBookEmailBody": "Thank you. <br /> To download your book, <a href=\"{0}\">click here</a>."
"DDDBookEmailBody": "Thank you. <br /> To download your book, <a href=\"{0}\">click here</a>.",
"SubscribeToNewsletter": "Subscribe to the newsletter to get information about happenings in the ABP.IO Platform, like new releases, articles, offers, and more.",
"FirstEdition": "First Edition"
}
}

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

@ -244,7 +244,7 @@
"ExampleUseCase": "Example Use Case",
"DomainAndApplicationLogic": "Domain Logic & Application Logic",
"Author": "Author",
"Page": "Page",
"Pages": "Pages",
"PublishedOn": "Published on",
"FreeEBook": "Free E-Book",
"Download": "Download",
@ -256,8 +256,6 @@
"Surname": "Surname",
"CompanyName": "Company Name",
"DoYouAgreePrivacyPolicy": "I agree to the <a href=\"https://account.abp.io/Account/TermsConditions\">Terms & Conditions</a> and <a href=\"https://account.abp.io/Account/Privacy\">Privacy Policy</a>.",
"VolosoftMarketingInformationMessage": "I would like information, tips, and offers about Solutions for Businesses and Organizations and other Volosoft products and services.",
"VolosoftSharingInformationMessage": "I would like Volosoft to share my information with select partners so I can receive relevant information about their products and services.",
"Free": "Free",
"DDDEBook": "DDD E-book",
"PracticalGuideForImplementingDDD": "This book is a practical guide for implementing the Domain Driven Design with the ABP Framework.",
@ -268,9 +266,13 @@
"DomainVsApplicationLogic": "Domain Logic vs Application Logic",
"SamplesAndDiscussions": "Samples & Discussions",
"EmailNotValid": "Please enter a valid email address.",
"WeWillSendYouADownloadLink": "A link to download the e-book has been sent to {0}.<br/> Check your inbox / junk / spam boxes!",
"WeWillSendYouADownloadLink": "A link to download the e-book has been sent to {0}. Check your inbox, junk or spam boxes!",
"GoHome": "Go Home",
"InvalidFormInputs": "Please, type the valid information specified on the form.",
"DDDBookEmailBody": "Thank you. <br /> To download your book, <a href=\"{0}\">click here</a>."
"DDDBookEmailBody": "Thank you. <br /> To download your book, <a href=\"{0}\">click here</a>.",
"SubscribeToNewsletter": "Subscribe to the newsletter to get information about happenings in the ABP.IO Platform, like new releases, articles, offers, and more.",
"FirstEdition": "First Edition",
"ThankYou": "Thank you!",
"CheckboxMandatory": "You need to check this to proceed!"
}
}

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

@ -218,8 +218,6 @@
"Surname": "Soyad",
"CompanyName": "Şirket adı",
"DoYouAgreePrivacyPolicy": "Şartlar & Koşulları ve <a href=\"https://commercial.abp.io/Privacy\">Gizlilik Politikasını</a> kabul ediyorum.",
"VolosoftMarketingInformationMessage": "İşletmeler ve Organizasyonlar için çözümler ve diğer Volosoft ürün ve hizmetleri hakkında bilgi, ipucu ve teklifler almak istiyorum.",
"VolosoftSharingInformationMessage": "Volosoft'un ürünlerimi seçkin ortaklarla paylaşmasını kabul ediyorum, böylece ilgili ortakların ürünleri ve hizmetleri hakkında ilgili bilgileri alabilirim.",
"Free": "Ücretsiz",
"DDDEBook": "DDD E-kitap",
"PracticalGuideForImplementingDDD": "Bu kitap ABP Framework ile birlikte Domain Driven Design'ın uygulanması için pratik bir kılavuz görevi görür.",
@ -233,6 +231,8 @@
"WeWillSendYouADownloadLink": "{0} adresine email gönderilmiştir.",
"GoHome": "Anasayfaya Dön",
"InvalidFormInputs": "Lütfen formda belirtilen geçerli bilgileri yazınız.",
"DDDBookEmailBody": "Teşekkürler. <br /> Kitabı indirmek için, <a href=\"{0}\">buraya tıklayınız</a>."
"DDDBookEmailBody": "Teşekkürler. <br /> Kitabı indirmek için, <a href=\"{0}\">buraya tıklayınız</a>.",
"SubscribeToNewsletter": "ABP.IO Platform'u ile ilgili yeni haberler, makaleler, teklifler ve daha fazlası gibi gelişmeler hakkında bilgi almak için bültene abone olun.",
"FirstEdition": "İlk Baskı"
}
}

16
docs/en/CLI.md

@ -42,6 +42,7 @@ Here, the list of all available commands before explaining their details:
* **`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.
* **`bundle`**: Generates script and style references for an ABP Blazor project.
* **`install-libs`**: Install NPM Packages for MVC / Razor Pages and Blazor Server UI types.
### help
@ -433,3 +434,18 @@ abp bundle [options]
`bundle` command reads the `appsettings.json` file inside the Blazor project for bundling options. For more details about managing style and script references in Blazor apps, see [Managing Global Scripts & Styles](UI/Blazor/Global-Scripts-Styles.md)
### install-libs
This command install NPM Packages for MVC / Razor Pages and Blazor Server UI types. Its **executing directory** or passed ```--working-directory``` parameter's directory must contain a project file(*.csproj).
`install-libs` command reads the `abp.resourcemapping.js` file to manage package. For more details see [Client Side Package Management](UI/AspNetCore/Client-Side-Package-Management.md).
Usage:
````bash
abp install-libs [options]
````
#### Options
* ```--working-directory``` or ```-wd```: Specifies the working directory. This option is useful when executing directory doesn't contain a project file.

199
docs/en/Community-Articles/2020-04-27-Use-Azure-Active-Directory-Authentication-for-MVC-Razor-Page-Applications/POST.md

@ -6,23 +6,21 @@ Adding Azure Active Directory is pretty straightforward in ABP framework. Couple
Two different **alternative approaches** for AzureAD integration will be demonstrated for better coverage.
1. ~~**AddAzureAD**: This approach uses Microsoft [AzureAD UI nuget package](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.AzureAD.UI/) which is very popular when users search the web about how to integrate AzureAD to their web application.~~ Now marked **Obsolete** (see https://github.com/aspnet/Announcements/issues/439).
2. **AddOpenIdConnect**: This approach uses default [OpenIdConnect](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.OpenIdConnect/) which can be used for not only AzureAD but for all OpenId connections.
1. **AddOpenIdConnect**: This approach uses default [OpenIdConnect](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.OpenIdConnect/) which can be used for not only AzureAD but for all OpenId connections.
3. **AddMicrosoftIdentityWebAppAuthentication:** This approach uses newly introduced [Microsoft.Identity.Web nuget package](https://www.nuget.org/packages/Microsoft.Identity.Web/) to replace AddAzureAD.
3. ~~**AddAzureAD**: This approach uses Microsoft [AzureAD UI nuget package](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.AzureAD.UI/) which is very popular when users search the web about how to integrate AzureAD to their web application.~~ Now marked **Obsolete** (see https://github.com/aspnet/Announcements/issues/439).
> There is **no difference** in functionality between these approaches. AddAzureAD is an abstracted way of OpenIdConnection ([source](https://github.com/dotnet/aspnetcore/blob/c56aa320c32ee5429d60647782c91d53ac765865/src/Azure/AzureAD/Authentication.AzureAD.UI/src/AzureADAuthenticationBuilderExtensions.cs#L122)) with predefined cookie settings.
>
> However there are key differences in integration to ABP applications because of default configurated signin schemes which will be explained below.
## 1. AddAzureAD
## 1. AddOpenIdConnect
This approach uses the most common way to integrate AzureAD by using the [Microsoft AzureAD UI nuget package](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.AzureAD.UI/).
If you choose this approach, you will need to install `Microsoft.AspNetCore.Authentication.AzureAD.UI` package to your **.Web** project. Also, since AddAzureAD extension uses [configuration binding](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#default-configuration), you need to update your appsettings.json file located in your **.Web** project.
If you don't want to use an extra nuget package in your application, you can use the straight default [OpenIdConnect](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.OpenIdConnect/) which can be used for all OpenId connections including AzureAD external authentication.
#### **Updating `appsettings.json`**
You don't have to use `appsettings.json` configuration but it is a good practice to set AzureAD information in the `appsettings.json`.
You need to add a new section to your `appsettings.json` which will be binded to configuration when configuring the `OpenIdConnectOptions`:
To get the AzureAD information from `appsettings.json`, which will be used in `OpenIdConnectOptions` configuration, simply add a new section to `appsettings.json` located in your **.Web** project:
````json
"AzureAd": {
@ -34,63 +32,90 @@ You need to add a new section to your `appsettings.json` which will be binded to
}
````
> Important configuration here is the CallbackPath. This value must be the same with one of your Azure AD-> app registrations-> Authentication -> RedirectUri.
Then, you need to configure the `OpenIdConnectOptions` to complete the integration.
#### Configuring OpenIdConnectOptions
In your **.Web** project, locate your **ApplicationWebModule** and modify `ConfigureAuthentication` method with the following:
Then, In your **.Web** project; you can modify the `ConfigureAuthentication` method located in your **ApplicationWebModule** with the following:
````csharp
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);
context.Services.AddAuthentication()
.AddIdentityServerAuthentication(options =>
{
options.Authority = configuration["AuthServer:Authority"];
... //Omitted other third party configurations
.AddOpenIdConnect("AzureOpenId", "Azure Active Directory 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.ApiName = "Acme.BookStore";
})
.AddAzureAD(options => configuration.Bind("AzureAd", options));
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("email");
context.Services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
});
}
````
> **Don't forget to:**
>
> * Add `options.Scope.Add("email");` since [default signin scheme is `AzureADOpenID`](https://github.com/dotnet/aspnetcore/blob/c56aa320c32ee5429d60647782c91d53ac765865/src/Azure/AzureAD/Authentication.AzureAD.UI/src/AzureADOpenIdConnectOptionsConfiguration.cs#L35).
> * Add `options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");`. Mapping this to [ClaimTypes.NameIdentifier](https://github.com/dotnet/runtime/blob/6d395de48ac718a913e567ae80961050f2a9a4fa/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimTypes.cs#L59) is important since default SignIn Manager behavior uses this claim type for external login information.
And that's it, integration is completed. Keep on mind that you can connect any other external authentication providers.
## 2. Alternative Approach: AddMicrosoftIdentityWebApp
With .Net 5.0, AzureAd is marked [obsolete](https://github.com/dotnet/aspnetcore/issues/25807) and will not be supported in the near future. However its expanded functionality is available in [microsoft-identity-web](https://github.com/AzureAD/microsoft-identity-web/wiki) packages.
Add (or replace with) the new nuget package Microsoft.Identity.Web nuget package](https://www.nuget.org/packages/Microsoft.Identity.Web/).
In your **.Web** project; you update the `ConfigureAuthentication` method located in your **ApplicationWebModule** with the following while having the AzureAd appsettings section as defined before:
````csharp
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.AddAuthentication()
... //Omitted other third party configurations
.AddMicrosoftIdentityWebApp(configuration.GetSection("AzureAd"));
context.Services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.Authority = "https://login.microsoftonline.com/" + configuration["AzureAd:TenantId"] + "/v2.0/";
options.ClientId = configuration["AzureAd:ClientId"];
options.CallbackPath = configuration["AzureAd:CallbackPath"];
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.CallbackPath = configuration["AzureAd:CallbackPath"];
options.ClientSecret = configuration["AzureAd:ClientSecret"];
options.RequireHttpsMetadata = false;
options.TokenValidationParameters.ValidateIssuer = false;
options.SaveTokens = false;
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.SignInScheme = IdentityConstants.ExternalScheme;
options.Scope.Add("email");
options.SignInScheme = IdentityConstants.ExternalScheme;
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
});
}
````
And that's all to add new Microsoft-Identity-Web.
> **Don't forget to:**
>
> * Add `.AddAzureAD(options => configuration.Bind("AzureAd", options))` after `.AddAuthentication()`. This binds your AzureAD appsettings and easy to miss out.
> * Add `JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear()`. This will disable the default Microsoft claim type mapping.
> * Add `JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier)`. Mapping this to [ClaimTypes.NameIdentifier](https://github.com/dotnet/runtime/blob/6d395de48ac718a913e567ae80961050f2a9a4fa/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimTypes.cs#L59) is important since default SignIn Manager behavior uses this claim type for external login information.
> * Add `options.SignInScheme = IdentityConstants.ExternalScheme` since [default signin scheme is `AzureADOpenID`](https://github.com/dotnet/aspnetcore/blob/c56aa320c32ee5429d60647782c91d53ac765865/src/Azure/AzureAD/Authentication.AzureAD.UI/src/AzureADOpenIdConnectOptionsConfiguration.cs#L35).
> * Add `options.Scope.Add("email")` if you are using **v2.0** endpoint of AzureAD since v2.0 endpoint doesn't return the `email` claim as default. The [Account Module](https://docs.abp.io/en/abp/latest/Modules/Account) uses `email` claim to [register external users](https://github.com/abpframework/abp/blob/be32a55449e270d2d456df3dabdc91f3ffdd4fa9/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs#L215).
> * Add `options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");`. Mapping this to [ClaimTypes.NameIdentifier](https://github.com/dotnet/runtime/blob/6d395de48ac718a913e567ae80961050f2a9a4fa/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimTypes.cs#L59) is important since default SignIn Manager behavior uses this claim type for external login information.
You are done and integration is completed.
Keep in mind that [Microsoft-Identity-Web](https://github.com/AzureAD/microsoft-identity-web) is relatively new and keeps getting new enhancements, features and documentation.
## 2. Alternative Approach: AddOpenIdConnect
## 3. Obsolete Alternative Approach: AddAzureAD
If you don't want to use an extra nuget package in your application, you can use the straight default [OpenIdConnect](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.OpenIdConnect/) which can be used for all OpenId connections including AzureAD external authentication.
This approach uses the most common way to integrate AzureAD by using the [Microsoft AzureAD UI nuget package](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.AzureAD.UI/).
You don't have to use `appsettings.json` configuration but it is a good practice to set AzureAD information in the `appsettings.json`.
If you choose this approach, you will need to install `Microsoft.AspNetCore.Authentication.AzureAD.UI` package to your **.Web** project. Also, since AddAzureAD extension uses [configuration binding](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#default-configuration), you need to update your appsettings.json file located in your **.Web** project.
To get the AzureAD information from `appsettings.json`, which will be used in `OpenIdConnectOptions` configuration, simply add a new section to `appsettings.json` located in your **.Web** project:
#### **Updating `appsettings.json`**
You need to add a new section to your `appsettings.json` which will be binded to configuration when configuring the `OpenIdConnectOptions`:
````json
"AzureAd": {
@ -102,74 +127,49 @@ To get the AzureAD information from `appsettings.json`, which will be used in `O
}
````
Then, In your **.Web** project; you can modify the `ConfigureAuthentication` method located in your **ApplicationWebModule** with the following:
````csharp
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);
context.Services.AddAuthentication()
.AddIdentityServerAuthentication(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = false;
options.ApiName = "BookStore";
})
.AddOpenIdConnect("AzureOpenId", "Azure Active Directory 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.RequireHttpsMetadata = false;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("email");
});
}
````
And that's it, integration is completed. Keep on mind that you can connect any other external authentication providers.
## 3. AddMicrosoftIdentityWebAppAuthentication
> Important configuration here is the CallbackPath. This value must be the same with one of your Azure AD-> app registrations-> Authentication -> RedirectUri.
With .Net 5.0, AzureAd is marked [obsolete](https://github.com/dotnet/aspnetcore/issues/25807) and will not be supported in the near future. However its expanded functionality is available in [microsoft-identity-web](https://github.com/AzureAD/microsoft-identity-web/wiki) packages.
Then, you need to configure the `OpenIdConnectOptions` to complete the integration.
Add (or replace with) the new nuget package Microsoft.Identity.Web nuget package](https://www.nuget.org/packages/Microsoft.Identity.Web/).
#### Configuring OpenIdConnectOptions
In your **.Web** project; you update the `ConfigureAuthentication` method located in your **ApplicationWebModule** with the following while having the AzureAd appsettings section as defined before:
In your **.Web** project, locate your **ApplicationWebModule** and modify `ConfigureAuthentication` method with the following:
````csharp
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);
context.Services.AddAuthentication()
.AddIdentityServerAuthentication(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = false;
options.ApiName = "Acme.BookStore";
});
context.Services.AddMicrosoftIdentityWebAppAuthentication(
configuration: configuration,
configSectionName: "AzureAd",
openIdConnectScheme:"AzureAD",
cookieScheme:null);
... //Omitted other third party configurations
.AddAzureAD(options => configuration.Bind("AzureAd", options));
context.Services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.ClientId = configuration["AzureAd:ClientId"];
options.CallbackPath = configuration["AzureAd:CallbackPath"];
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters.ValidateIssuer = false;
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.SignInScheme = IdentityConstants.ExternalScheme;
options.Scope.Add("email");
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
});
}
````
And that's all to add new Microsoft-Identity-Web.
> **Don't forget to:**
>
> * Pass **cookieScheme** parameter as **null** or your [*GetExternalLoginInfoAsync* method will always return null](https://github.com/AzureAD/microsoft-identity-web/issues/133#).
> * Add `.AddAzureAD(options => configuration.Bind("AzureAd", options))` after `.AddAuthentication()`. This binds your AzureAD appsettings and easy to miss out.
> * Add `options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");`. Mapping this to [ClaimTypes.NameIdentifier](https://github.com/dotnet/runtime/blob/6d395de48ac718a913e567ae80961050f2a9a4fa/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimTypes.cs#L59) is important since default SignIn Manager behavior uses this claim type for external login information.
> * Add `options.SignInScheme = IdentityConstants.ExternalScheme` since [default signin scheme is `AzureADOpenID`](https://github.com/dotnet/aspnetcore/blob/c56aa320c32ee5429d60647782c91d53ac765865/src/Azure/AzureAD/Authentication.AzureAD.UI/src/AzureADOpenIdConnectOptionsConfiguration.cs#L35).
> * Add `options.Scope.Add("email")` if you are using **v2.0** endpoint of AzureAD since v2.0 endpoint doesn't return the `email` claim as default. The [Account Module](https://docs.abp.io/en/abp/latest/Modules/Account) uses `email` claim to [register external users](https://github.com/abpframework/abp/blob/be32a55449e270d2d456df3dabdc91f3ffdd4fa9/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs#L215).
Keep in mind that [Microsoft-Identity-Web](https://github.com/AzureAD/microsoft-identity-web) is relatively new and keeps getting new enhancements, features and documentation.
You are done and integration is completed.
## The Source Code
@ -247,3 +247,14 @@ You can find the source code of the completed example [here](https://github.com/
await Task.CompletedTask;
});
````
* I get page not found error on redirection to **https://login.live.com/oauth20_authorize.srf?**!
* Probably you are trying to login with Microsoft account to Azure portal instead of the Azure AD account. Try azure AD user account for login instead of microsoft account. You can also check the answers for [this question](https://answers.microsoft.com/en-us/msoffice/forum/msoffice_o365admin-mso_dirservices-mso_o365b/cant-login-in-loginlivecom-with-a-ms-account-valid/6da991e6-9528-461a-9638-9c5680e95888) and [this question](https://docs.microsoft.com/en-us/answers/questions/34806/azure-ad-404-error-when-login-with-microsoft-accou.html) for more details.
# May 2021 Update
- **AddOpenIdConnect**: Removed `JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();` and added `sub` claim mapping in ClaimActions rather than global mapping.
- Updated `AddMicrosoftIdentityWebAppAuthentication ` to `AddMicrosoftIdentityWebApp`.
- Updated OpenIdConnect and AddMicrosoftIdentityWebApp configurations.
- Obsolete approach moved to third place in the list.

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

@ -23,20 +23,9 @@ This means your application will be using AzureAD user store for authentication.
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
};
})
... //Omitted other third party configurations
.AddOpenIdConnect("AzureOpenId", "Azure AD OpenId", options =>
{
options.Authority = "https://login.microsoftonline.com/" + configuration["AzureAd:TenantId"] + "/v2.0/";
@ -48,6 +37,8 @@ context.Services.AddAuthentication()
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("email");
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
});
```
@ -58,10 +49,7 @@ 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 =>
{
@ -120,3 +108,8 @@ Next time you hit login, you should be seeing login screen enabled Azure AD like
* 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).
# May 2021 Update
- **AddOpenIdConnect**: Removed `JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();` and added `sub` claim mapping in ClaimActions rather than global mapping.
- Updated OpenIdConnect configurations.

1981
docs/en/Domain-Driven-Design-Implementation-Guide.md

File diff suppressed because it is too large

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

@ -83,4 +83,192 @@ Setting Management module is extensible, just like the [setting system](../Setti
* `TenantSettingManagementProvider`: Gets or sets the setting value for a tenant.
* `UserSettingManagementProvider`: Gets the setting value for a user.
`ISettingManager` uses the setting management providers on get/set methods. Typically, every setting management provider defines extension methods on the `ISettingManagement` service (like `SetForUserAsync` defined by the user setting management provider).
`ISettingManager` uses the setting management providers on get/set methods. Typically, every setting management provider defines extension methods on the `ISettingManagement` service (like `SetForUserAsync` defined by the user setting management provider).
## Setting Management UI
Setting Mangement module provided the email setting UI by default, and it is extensible; You can add your tabs to this page for your application settings.
### MVC UI
#### Create a setting View Component
Create `MySettingGroup` folder under the `Components` folder. Add a new view component. Name it as `MySettingGroupViewComponent`:
![MySettingGroupViewComponent](../images/my-setting-group-view-component.png)
Open the `MySettingGroupViewComponent.cs` and change the whole content as shown below:
```csharp
public class MySettingGroupViewComponent : AbpViewComponent
{
public virtual IViewComponentResult Invoke()
{
return View("~/Components/MySettingGroup/Default.cshtml");
}
}
```
> You can also use the `InvokeAsync` method, In this example, we use the `Invoke` method.
#### Default.cshtml
Create a `Default.cshtml` file under the `MySettingGroup` folder.
Open the `Default.cshtml` and change the whole content as shown below:
```html
<div>
<p>My setting group page</p>
</div>
```
#### BookStoreSettingPageContributor
Create a `BookStoreSettingPageContributor.cs` file under the `Settings` folder:
![BookStoreSettingPageContributor](../images/my-setting-group-page-contributor.png)
The content of the file is shown below:
```csharp
public class BookStoreSettingPageContributor : ISettingPageContributor
{
public Task ConfigureAsync(SettingPageCreationContext context)
{
context.Groups.Add(
new SettingPageGroup(
"Volo.Abp.MySettingGroup",
"MySettingGroup",
typeof(MySettingGroupViewComponent)
)
);
return Task.CompletedTask;
}
public Task<bool> CheckPermissionsAsync(SettingPageCreationContext context)
{
// You can check the permissions here
return Task.FromResult(true);
}
}
```
Open the `BookStoreWebModule.cs` file and add the following code:
```csharp
Configure<SettingManagementPageOptions>(options =>
{
options.Contributors.Add(new BookStoreSettingPageContributor());
});
```
#### Run the Application
Navigate to `/SettingManagement` route to see the changes:
![Custom Settings Tab](../images/my-setting-group-ui.png)
### Blazor UI
#### Create a Razor Component
Create `MySettingGroup` folder under the `Pages` folder. Add a new razor component. Name it as `MySettingGroupComponent`:
![MySettingGroupComponent](../images/my-setting-group-component.png)
Open the `MySettingGroupComponent.razor` and change the whole content as shown below:
```csharp
<Row>
<p>my setting group</p>
</Row>
```
#### BookStoreSettingComponentContributor
Create a `BookStoreSettingComponentContributor.cs` file under the `Settings` folder:
![BookStoreSettingComponentContributor](../images/my-setting-group-component-contributor.png)
The content of the file is shown below:
```csharp
public class BookStoreSettingComponentContributor : ISettingComponentContributor
{
public Task ConfigureAsync(SettingComponentCreationContext context)
{
context.Groups.Add(
new SettingComponentGroup(
"Volo.Abp.MySettingGroup",
"MySettingGroup",
typeof(MySettingGroupComponent)
)
);
return Task.CompletedTask;
}
public Task<bool> CheckPermissionsAsync(SettingComponentCreationContext context)
{
// You can check the permissions here
return Task.FromResult(true);
}
}
```
Open the `BookStoreBlazorModule.cs` file and add the following code:
```csharp
Configure<SettingManagementComponentOptions>(options =>
{
options.Contributors.Add(new BookStoreSettingComponentContributor());
});
```
#### Run the Application
Navigate to `/setting-management` route to see the changes:
![Custom Settings Tab](../images/my-setting-group-blazor.png)
### Angular UI
#### Create a Component
Create a component with the following command:
```bash
yarn ng generate component my-settings
```
Open the `app.component.ts` and modify the file as shown below:
```js
import { Component } from '@angular/core';
import { SettingTabsService } from '@abp/ng.core'; // imported SettingTabsService
import { MySettingsComponent } from './my-settings/my-settings.component'; // imported MySettingsComponent
@Component(/* component metadata */)
export class AppComponent {
constructor(private settingTabs: SettingTabsService) // injected MySettingsComponent
{
// added below
settingTabs.add([
{
name: 'MySettings',
order: 1,
requiredPolicy: 'policy key here',
component: MySettingsComponent,
},
]);
}
}
```
#### Run the Application
Navigate to `/setting-management` route to see the changes:
![Custom Settings Tab](../images/custom-settings.png)

106
docs/en/Modules/Tenant-Management.md

@ -1,3 +1,107 @@
# Tenant Management Module
TODO
[Multi-Tenancy](../Multi-Tenancy.md) is one of the core features of ABP Framework. It provides the fundamental infrastructure to build your own SaaS (Software-as-a-Service) solution. ABP's multi-tenancy system abstracts where your tenants are stored, by providing the `ITenantStore` interface. All you need to do is to implement that interface.
**The Tenant Management module is an implementation of the the `ITenantStore` interface. It stores tenants in a database. It also provides UI to manage your tenants and their [features](../Features.md).**
> Please **refer to the [Multi-Tenancy](../Multi-Tenancy.md) documentation** to understand the multi-tenancy system of the ABP Framework. This document focuses on the Tenant Management module.
### About the ABP Commercial SaaS Module
The [SaaS Module](https://commercial.abp.io/modules/Volo.Saas) is an alternative implementation of this module with more features and possibilities. It is distributed as a part of the [ABP Commercial](https://commercial.abp.io/) subscription.
## How to Install
This module comes as pre-installed (as [NuGet/NPM packages](NuGet/NPM packages)) when you [create a new solution](https://abp.io/get-started) with the ABP Framework. You can continue to use it as package and get updates easily, or you can include its source code into your solution (see `get-source` [CLI](../CLI.md) command) to develop your custom module.
### The Source Code
The source code of this module can be accessed [here](https://github.com/abpframework/abp/tree/dev/modules/tenant-management). The source code is licensed with [MIT](https://choosealicense.com/licenses/mit/), so you can freely use and customize it.
## User Interface
This module adds "*Administration -> Tenant Management -> Tenants*" menu item to the main menu of the application, which opens the page shown below:
![module-tenant-management-page](../images/module-tenant-management-page.png)
In this page, you see the all the tenants. You can create a new tenant as shown below:
![module-tenant-management-new-tenant](../images/module-tenant-management-new-tenant.png)
In this modal;
* **Name**: The unique name of the tenant. If you use subdomains for your tenants (like https://some-tenant.your-domain.com), this will be the subdomain name.
* **Admin Email Address**: Email address of the admin user for this tenant.
* **Admin Password**: The password of the admin user for this tenant.
When you click to *Actions* button near to a tenant, you will see the actions you can take:
![module-tenant-management-actions](../images/module-tenant-management-actions.png)
### Managing the Tenant Features
The Features action opens a modal to enable/disable/set [features](../Features.md) for the related tenant. Here, an example modal:
![features-modal](../images/features-modal.png)
### Managing the Host Features
*Manage Host features* button is used to set features for the host side, if you use the features of your application also in the host side.
## Internals
This section can be used as a reference if you want to [customize](../Customizing-Application-Modules-Guide.md) this module without changing [its source code](https://github.com/abpframework/abp/tree/dev/modules/tenant-management).
### Domain Layer
#### Aggregates
* `Tenant`
#### Repositories
* `ITenantRepository`
#### Domain Services
* `TenantManager`
### Application Layer
#### Application Services
* `TenantAppService`
#### Permissions
- `AbpTenantManagement.Tenants`: Tenant management.
- `AbpTenantManagement.Tenants.Create`: Creating a new tenant.
- `AbpTenantManagement.Tenants.Update`: Editing an existing tenant.
- `AbpTenantManagement.Tenants.Delete`: Deleting an existing tenant.
- `AbpTenantManagement.Tenants.ManageFeatures`: Manage features of the tenants.
### Entity Framework Core Integration
* `TenantManagementDbContext` (implements `ITenantManagementDbContext`)
**Database Tables:**
* `AbpTenants`
* `AbpTenantConnectionStrings`
### MongoDB Integration
* `TenantManagementMongoDbContext` (implements `ITenantManagementMongoDbContext`)
**Database Collections:**
* `AbpTenants` (also includes the connection string)
## Notices
ABP Framework allows to use *database per tenant* approach that allows a tenant can have a dedicated database. This module has the fundamental infrastructure to make that implementation possible (see its source code), however it doesn't implement the application layer and UI functionalities to provide it as an out of the box implementation. You can implement these features yourself, or consider to use the [ABP Commercial Saas Module](https://docs.abp.io/en/commercial/latest/modules/saas) that fully implements it and provides much more business features.
## See Also
* [Multi-Tenancy](../Multi-Tenancy.md)
* [ABP Commercial SaaS Module](https://docs.abp.io/en/commercial/latest/modules/saas)

3
docs/en/Road-Map.md

@ -8,11 +8,9 @@ This document provides a road map, release schedule and planned features for the
This version will focus on **documentation** and **improvements** of current features. In addition, the following features are planned:
* Publishing distributed events as transactional ([#6126](https://github.com/abpframework/abp/issues/6126))
* Revisit the microservice demo solution ([#8385](https://github.com/abpframework/abp/issues/8385))
* A new UI Theme alternative to the Basic Theme ([#6132](https://github.com/abpframework/abp/issues/6132))
* Improvements and new features to the [CMS Kit](Modules/Cms-Kit.md) module ([#8380](https://github.com/abpframework/abp/issues/8380) [#8381](https://github.com/abpframework/abp/issues/8381))
* Pre-configured test project for the [Blazor UI](UI/Blazor/Overall.md) ([#5516](https://github.com/abpframework/abp/issues/5516))
* Razor engine support for text templating ([#8373](https://github.com/abpframework/abp/issues/8373))
**Planned release date**: End of Quarter 2, 2021. See the [4.4 milestone](https://github.com/abpframework/abp/milestone/52) to track the progress.
@ -25,6 +23,7 @@ We planned to focus on the ABP Framework v5.0 after the 4.4 release. This versio
* Upgrading to Bootstrap 5.x ([#8922](https://github.com/abpframework/abp/issues/8922))
* Alternative to IdentityServer4 ([#7221](https://github.com/abpframework/abp/issues/7221))
* Dapr integration ([#2183](https://github.com/abpframework/abp/issues/2183))
* Publishing distributed events as transactional ([#6126](https://github.com/abpframework/abp/issues/6126))
* Resource based authorization system ([#236](https://github.com/abpframework/abp/issues/236))
* API Versioning system: finalize & document ([#497](https://github.com/abpframework/abp/issues/497))
* Performance optimizations; Enabling .NET Trimming, using source generators and reducing reflection, etc.

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

@ -135,7 +135,7 @@ namespace TodoApp
}
````
`BasicAggregateRoot` is one the simplest base class to create root entities, and `Guid` is the primary key (`Id`) of the entity here.
`BasicAggregateRoot` is the simplest base class to create root entities, and `Guid` is the primary key (`Id`) of the entity here.
## Database Integration
@ -214,7 +214,7 @@ Now, we can use ABP repositories to save and retrieve todo items, as we'll do in
## Application Layer
An [Application Service](../../Application-Services.md) is used to perform use cases of the application. We need to perform the following use cases;
An [Application Service](../../Application-Services.md) is used to perform use cases of the application. We need to perform the following use cases:
* Get the list of todo items
* Create a new todo item
@ -243,7 +243,7 @@ namespace TodoApp
### Data Transfer Object
`GetListAsync` and `CreateAsync` methods return `TodoItemDto`. Applications Services typically gets and returns DTOs ([Data Transfer Objects](../../Data-Transfer-Objects.md)) instead of entities. So, we should define the DTO class here. Create a new `TodoItemDto` class inside the *TodoApp.Application.Contracts* project:
`GetListAsync` and `CreateAsync` methods return `TodoItemDto`. `ApplicationService` typically gets and returns DTOs ([Data Transfer Objects](../../Data-Transfer-Objects.md)) instead of entities. So, we should define the DTO class here. Create a new `TodoItemDto` class inside the *TodoApp.Application.Contracts* project:
````csharp
using System;
@ -465,9 +465,9 @@ $(function () {
});
````
In the first part, we are registering to click events of the trash icons near to the todo items, deleting the related item on the server and showing a notification on the UI. Also, we are removing the deleted item from DOM, so we don't need to refresh the page.
In the first part, we are subscribing to click events of the trash icons near to the todo items, deleting the related item on the server and showing a notification on the UI. Also, we are removing the deleted item from DOM, so we don't need to refresh the page.
In the second part, we are creating a new todo item on the server. If it succeed, we are then manipulating DOM to insert a new `<li>` element to the todo list. In this way, no need to refresh the whole page after creating a new todo item.
In the second part, we are creating a new todo item on the server. If it succeeds, we are then manipulating DOM to insert a new `<li>` element to the todo list. This way we don't need to refresh the whole page after creating a new todo item.
The interesting part here is how we communicate with the server. See the *Dynamic JavaScript Proxies & Auto API Controllers* section to understand how it works. But now, let's continue and complete the application.
@ -504,13 +504,13 @@ As the final touch, open the `Index.css` file in the `Pages` folder of the *Todo
This is a simple styling for the todo page. We believe that you can do much better :)
Now, you can run the application again to see the result.
Now, you can run the application again and see the result.
### Dynamic JavaScript Proxies & Auto API Controllers
In the `Index.js` file, we've used `todoApp.todo.delete(...)` and `todoApp.todo.create(...)` functions to communicate with the server. These functions are dynamically created by the ABP Framework, thanks to the [Dynamic JavaScript Client Proxy](../../UI/AspNetCore/Dynamic-JavaScript-Proxies.md) system. They perform HTTP API calls to the server and return a promise, so you can register a callback to the `then` function as we've done above.
However, you may ask that we haven't created any API Controller, so how server handles these requests? This question brings us the [Auto API Controller](../../API/Auto-API-Controllers.md) feature of the ABP Framework. It automatically converts the application services to API Controllers by conventions.
However, you may notice that we haven't created any API Controller, so how server handles these requests? This question brings us the [Auto API Controller](../../API/Auto-API-Controllers.md) feature of the ABP Framework. It automatically converts the application services to API Controllers by convention.
If you open the [Swagger UI](https://swagger.io/tools/swagger-ui/) by entering the `/swagger` URL in your application, you can see the Todo API:
@ -559,7 +559,7 @@ namespace TodoApp.Blazor.Pages
}
````
This class uses the `ITodoAppService` to perform operations for the todo items. It manipulates the `TodoItems` list after create and delete operations. In this way, we don't need to refresh the whole todo list from the server.
This class uses the `ITodoAppService` to perform operations for the todo items. It manipulates the `TodoItems` list after create and delete operations. This way, we don't need to refresh the whole todo list from the server.
{{if UI=="Blazor"}}
@ -653,7 +653,7 @@ In the `Index.razor.cs` file, we've injected (with the `[Inject]` attribute) and
The magic is done by the ABP Framework's [Dynamic C# Client Proxy](../../API/Dynamic-CSharp-API-Clients.md) system. It uses the standard `HttpClient` and performs HTTP API requests to the remote server. It also handles all the standard tasks for us, including authorization, JSON serialization and exception handling.
However, you may ask that we haven't created any API Controller, so how server handles these requests? This question brings us the [Auto API Controller](../../API/Auto-API-Controllers.md) feature of the ABP Framework. It automatically converts the application services to API Controllers by conventions.
However, you may ask that we haven't created any API Controller, so how server handles these requests? This question brings us the [Auto API Controller](../../API/Auto-API-Controllers.md) feature of the ABP Framework. It automatically converts the application services to API Controllers by convention.
If you run the `TodoApp.HttpApi.Host` application, you can see the Todo API:
@ -669,7 +669,7 @@ ABP provides a handy feature to automatically create client-side services to eas
You first need to run the `TodoApp.HttpApi.Host` project since the proxy generator reads API definitions from the server application.
> **Warning**: There is a problem with IIS Express; it doesn't allow to connect to the application from another process. If you are using Visual Studio, select the `TodoApp.HttpApi.Host` instead of IIS Express in the run button drop-down list, as shown in the figure below:
> **Warning**: There is an issue with IIS Express: it doesn't allow to connect to the application from another process. If you are using Visual Studio, select the `TodoApp.HttpApi.Host` instead of IIS Express in the run button drop-down list, as shown in the figure below:
![run-without-iisexpress](run-without-iisexpress.png)
@ -813,7 +813,7 @@ Now, you can run the application again to see the result.
## Conclusion
In this tutorial, we've build a very simple application to warm up to the ABP Framework. If you are looking to build a serious application, please check the [web application development tutorial](../Part-1.md) which covers all the aspects of a real-life web application development.
In this tutorial, we've built a very simple application to warm up to the ABP Framework. If you are looking to build a serious application, please check the [web application development tutorial](../Part-1.md) which covers all the aspects of a real-life web application development.
## Source Code
@ -821,4 +821,4 @@ You can find source code of the completed application [here](https://github.com/
## See Also
* [Web Application Development Tutorial](../Part-1.md)
* [Web Application Development Tutorial](../Part-1.md)

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

@ -120,6 +120,4 @@ export const environment = {
} as Config.Environment;
```
> Note: The resource owner password flow does not support the two-factor authentication for some technical reasons.
See the [Authorization in Angular UI](./Authorization.md) document for more details.

2
docs/en/UI/Angular/Authorization.md

@ -52,5 +52,3 @@ export const environment = {
```
According to this flow, the user is redirected to the login page in the account module.
> Note: The resource owner password flow does not support the two-factor authentication for some technical reasons.

37
docs/en/UI/Angular/Custom-Setting-Page.md

@ -1,37 +0,0 @@
# Custom Setting Page
There are several settings tabs from different modules. You can add a custom setting page to your project.
1. Create a component with the following command:
```bash
yarn ng generate component my-settings
```
2. Open the `app.component.ts` and modify the file as shown below:
```js
import { Component } from '@angular/core';
import { SettingTabsService } from '@abp/ng.core'; // imported SettingTabsService
import { MySettingsComponent } from './my-settings/my-settings.component'; // imported MySettingsComponent
@Component(/* component metadata */)
export class AppComponent {
constructor(private settingTabs: SettingTabsService) // injected MySettingsComponent
{
// added below
settingTabs.add([
{
name: 'MySettings',
order: 1,
requiredPolicy: 'policy key here',
component: MySettingsComponent,
},
]);
}
}
```
Navigate to `/setting-management` route to see the changes:
![Custom Settings Tab](./images/custom-settings.png)

2
docs/en/UI/Blazor/Overall.md

@ -93,6 +93,8 @@ These libraries are selected as the base libraries and available to the applicat
> Bootstrap's JavaScript part is not used since the Blazorise library already provides the necessary functionalities to the Bootstrap components in a native way.
> Beginning from June, 2021, the Blazorise library has dual licenses; open source & commercial. Based on your yearly revenue, you may need to buy a commercial license. See [this post](https://blazorise.com/news/blazorise-commercial-going-live/) for the announcement.
### The Layout
The themes provide the layout. So, you have a responsive layout with the standard features already implemented. The screenshot below has taken from the layout of the [Basic Theme](Basic-Theme.md):

8
docs/en/docs-nav.json

@ -543,8 +543,8 @@
]
},
{
"text": "Guide: Implementing DDD",
"path": "Domain-Driven-Design-Implementation-Guide.md"
"text": "E-Book: Implementing DDD",
"path": "https://abp.io/books/implementing-domain-driven-design"
}
]
},
@ -1027,10 +1027,6 @@
"text": "Component Replacement",
"path": "UI/Angular/Component-Replacement.md"
},
{
"text": "Custom Setting Page",
"path": "UI/Angular/Custom-Setting-Page.md"
},
{
"text": "Extensions",
"items": [

0
docs/en/UI/Angular/images/custom-settings.png → docs/en/images/custom-settings.png

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

BIN
docs/en/images/module-tenant-management-actions.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

BIN
docs/en/images/module-tenant-management-new-tenant.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/en/images/module-tenant-management-page.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
docs/en/images/my-setting-group-blazor.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
docs/en/images/my-setting-group-component-contributor.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/en/images/my-setting-group-component.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
docs/en/images/my-setting-group-page-contributor.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
docs/en/images/my-setting-group-ui.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
docs/en/images/my-setting-group-view-component.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

17
docs/zh-Hans/CLI.md

@ -39,6 +39,7 @@ dotnet tool update -g Volo.Abp.Cli
* **`translate`**: 当源代码控制存储库中有多个JSON[本地化](Localization.md文件时,可简化翻译本地化文件的过程.
* **`login`**: 使用你在[abp.io](https://abp.io/)的用户名和密码在你的计算机上认证.
* **`logout`**: 在你的计算机注销认证.
* **`install-libs`**: 为 MVC / Razor Pages 和 Blazor Server UI 类型安装NPM包.
### help
@ -339,3 +340,19 @@ abp login <username> -p <password> -o <organization> # You can enter both your
```
abp logout
```
### install-libs
为 MVC / Razor Pages 和 Blazor Server UI 类型安装NPM包, 它的 **执行目录** 或者传递的 ```--working-directory``` 目录必须包含一个项目文件(*.csproj).
`install-libs` 命令读取 `abp.resourcemapping.js` 来管理包. 参阅[客户端包管理](UI/AspNetCore/Client-Side-Package-Management.md)了解更多细节.
用法:
````bash
abp install-libs [options]
````
#### Options
* ```--working-directory``` 或 ```-wd```: 指定工作目录, 当执行目录不包含项目文件时会很有用.

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

@ -83,4 +83,194 @@ namespace Demo
* `TenantSettingManagementProvider`: 获取或设定租户的设置值.
* `UserSettingManagementProvider`: 获取或设定用户的设置值.
`ISettingManager``get/set` 方法中使用设置管理提供程序. 通常每个设置程序提供程序都在 `ISettingManagement` 服务上定义了模块方法 (比如用户设置管理程序提供定义了 `SetForUserAsync` 方法).
`ISettingManager``get/set` 方法中使用设置管理提供程序. 通常每个设置程序提供程序都在 `ISettingManagement` 服务上定义了模块方法 (比如用户设置管理程序提供定义了 `SetForUserAsync` 方法).
## Setting Management UI.
设置管理模块默认提供了邮件设置页面并且它是可扩展的; 你可以为你的应用程序设置添加设置标签到设置页面.
### MVC UI
#### 创建视图组件
`Components` 目录下创建 `MySettingGroup` 文件夹, 添加一个名为 `MySettingGroupViewComponent` 的视图组件:
![MySettingGroupViewComponent](../images/my-setting-group-view-component.png)
打开 `MySettingGroupViewComponent.cs` 替换为以下内容:
```csharp
public class MySettingGroupViewComponent : AbpViewComponent
{
public virtual IViewComponentResult Invoke()
{
return View("~/Components/MySettingGroup/Default.cshtml");
}
}
```
> 你还可以使用 `InvokeAsync` 方法,在这个示例中我们使用 `Invoke` 方法.
#### Default.cshtml
`MySettingGroup` 目录下创建 `Default.cshtml` 文件.
打开 `Default.cshtml` 替换为以下内容:
```html
<div>
<p>My setting group page</p>
</div>
```
#### BookStoreSettingPageContributor
`Settings` 目录下创建 `BookStoreSettingPageContributor.cs` 文件.
![BookStoreSettingPageContributor](../images/my-setting-group-page-contributor.png)
文件内容如下:
```csharp
public class BookStoreSettingPageContributor : ISettingPageContributor
{
public Task ConfigureAsync(SettingPageCreationContext context)
{
context.Groups.Add(
new SettingPageGroup(
"Volo.Abp.MySettingGroup",
"MySettingGroup",
typeof(MySettingGroupViewComponent)
)
);
return Task.CompletedTask;
}
public Task<bool> CheckPermissionsAsync(SettingPageCreationContext context)
{
// You can check the permissions here
return Task.FromResult(true);
}
}
```
打开 `BookStoreWebModule.cs` 文件添加以下代码:
```csharp
Configure<SettingManagementPageOptions>(options =>
{
options.Contributors.Add(new BookStoreSettingPageContributor());
});
```
#### 运行应用程序
导航到 `/SettingManagement` 路由查看更改:
![Custom Settings Tab](../images/my-setting-group-ui.png)
### Blazor UI
#### 创建 Razor 组件
`Pages` 目录下创建 `MySettingGroup` 文件夹, 添加一个名为 `MySettingGroupComponent` 的Razor组件:
![MySettingGroupComponent](../images/my-setting-group-component.png)
打开 `MySettingGroupComponent.razor` 替换为以下内容:
```csharp
<Row>
<p>my setting group</p>
</Row>
```
#### BookStoreSettingComponentContributor
`Settings` 目录下创建 `BookStoreSettingComponentContributor.cs` 文件.
![BookStoreSettingComponentContributor](../images/my-setting-group-component-contributor.png)
文件内容如下:
```csharp
public class BookStoreSettingComponentContributor : ISettingComponentContributor
{
public Task ConfigureAsync(SettingComponentCreationContext context)
{
context.Groups.Add(
new SettingComponentGroup(
"Volo.Abp.MySettingGroup",
"MySettingGroup",
typeof(MySettingGroupComponent)
)
);
return Task.CompletedTask;
}
public Task<bool> CheckPermissionsAsync(SettingComponentCreationContext context)
{
// You can check the permissions here
return Task.FromResult(true);
}
}
```
打开 `BookStoreBlazorModule.cs` 文件添加以下代码:
```csharp
Configure<SettingManagementComponentOptions>(options =>
{
options.Contributors.Add(new BookStoreSettingComponentContributor());
});
```
#### 运行应用程序
导航到 `/setting-management` 路由查看更改:
![Custom Settings Tab](../images/my-setting-group-blazor.png)
### Angular UI
不同的模块提供它们的设置选项卡. 你可以通过3个步骤在项目中自定义设置页面.
#### 创建组件
使用以下命令创建一个组件
```bash
yarn ng generate component my-settings
```
打开 `app.component.ts` 做以下修改:
```js
import { Component } from '@angular/core';
import { SettingTabsService } from '@abp/ng.core'; // imported SettingTabsService
import { MySettingsComponent } from './my-settings/my-settings.component'; // imported MySettingsComponent
@Component(/* component metadata */)
export class AppComponent {
constructor(private settingTabs: SettingTabsService) // injected MySettingsComponent
{
// added below
settingTabs.add([
{
name: 'MySettings',
order: 1,
requiredPolicy: 'policy key here',
component: MySettingsComponent,
},
]);
}
}
```
#### 运行应用程序
导航到 `/setting-management` 路由你会看到以下变化:
![Custom Settings Tab](../images/custom-settings.png)

41
docs/zh-Hans/UI/Angular/Custom-Setting-Page.md

@ -1,41 +0,0 @@
# 自定义设置页面
不同的模块提供它们的设置选项卡. 你可以通过3个步骤在项目中自定义设置页面.
1. 使用以下命令创建一个组件
```bash
yarn ng generate component my-settings
```
2. 打开 `app.component.ts` 做以下修改:
```js
import { Component } from '@angular/core';
import { SettingTabsService } from '@abp/ng.core'; // imported SettingTabsService
import { MySettingsComponent } from './my-settings/my-settings.component'; // imported MySettingsComponent
@Component(/* component metadata */)
export class AppComponent {
constructor(private settingTabs: SettingTabsService) // injected MySettingsComponent
{
// added below
settingTabs.add([
{
name: 'MySettings',
order: 1,
requiredPolicy: 'policy key here',
component: MySettingsComponent,
},
]);
}
}
```
导航到 `/setting-management` 路由你会看到以下变化:
![Custom Settings Tab](./images/custom-settings.png)
## 下一步是什么?
- [懒加载 Scripts 与 Styles](./Lazy-Load-Service.md)

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

@ -518,10 +518,6 @@
"text": "替换组件",
"path": "UI/Angular/Component-Replacement.md"
},
{
"text": "自定义设置页",
"path": "UI/Angular/Custom-Setting-Page.md"
},
{
"text": "懒加载Scripts与Styles",
"path": "UI/Angular/Lazy-Load-Service.md"

0
docs/zh-Hans/UI/Angular/images/custom-settings.png → docs/zh-Hans/images/custom-settings.png

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

BIN
docs/zh-Hans/images/my-setting-group-blazor.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
docs/zh-Hans/images/my-setting-group-component-contributor.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/zh-Hans/images/my-setting-group-component.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
docs/zh-Hans/images/my-setting-group-page-contributor.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
docs/zh-Hans/images/my-setting-group-ui.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
docs/zh-Hans/images/my-setting-group-view-component.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

49
framework/Volo.Abp.sln

@ -155,16 +155,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EntityFrameworkCor
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EventBus.RabbitMQ", "src\Volo.Abp.EventBus.RabbitMQ\Volo.Abp.EventBus.RabbitMQ.csproj", "{468C3DCB-8C00-40E7-AE51-0738EAAB312A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic", "src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj", "{2F5EE6D9-511B-4998-BD62-0B9F03E02432}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared", "src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj", "{86A3BB43-8FA2-4CC2-BAD0-A86C6C9D9585}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Tests", "test\Volo.Abp.AspNetCore.Mvc.UI.Tests\Volo.Abp.AspNetCore.Mvc.UI.Tests.csproj", "{7E0517E0-AE09-4E10-8469-308F065F2F43}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo", "test\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj", "{57E29185-6DAF-4A41-8CE0-3F07EE3E289A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests", "test\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests.csproj", "{869F7453-7DDC-4915-B92C-7861466AB68B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Emailing", "src\Volo.Abp.Emailing\Volo.Abp.Emailing.csproj", "{8B1CB44B-BA40-4C78-9447-A7864126D7C3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Sms", "src\Volo.Abp.Sms\Volo.Abp.Sms.csproj", "{8BB10746-8BAD-4317-8EE5-A36805DB93F6}"
@ -271,8 +265,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BackgroundWorkers.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo", "src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj", "{29E42ADB-85F8-44AE-A9B0-078F84C1B866}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo", "test\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo.csproj", "{0C498CF2-D052-4BF7-AD35-509A90F69707}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Http.Client.IdentityModel.Web.Tests", "test\Volo.Abp.Http.Client.IdentityModel.Web.Tests\Volo.Abp.Http.Client.IdentityModel.Web.Tests.csproj", "{E1963439-2BE5-4DB5-8438-2A9A792A1ADA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.ObjectExtending", "src\Volo.Abp.ObjectExtending\Volo.Abp.ObjectExtending.csproj", "{D1815C77-16D6-4F99-8814-69065CD89FB3}"
@ -343,8 +335,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Compone
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BlazoriseUI", "src\Volo.Abp.BlazoriseUI\Volo.Abp.BlazoriseUI.csproj", "{4EBDDB1B-D6C5-4FAE-B5A7-2171B18CDFA5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme", "src\Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme\Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.csproj", "{ABC27C10-C0FF-44CB-B4FF-A09C0B79F695}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Components.WebAssembly.Theming", "src\Volo.Abp.AspNetCore.Components.WebAssembly.Theming\Volo.Abp.AspNetCore.Components.WebAssembly.Theming.csproj", "{29CA7471-4E3E-4E75-8B33-001DDF682F01}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Autofac.WebAssembly", "src\Volo.Abp.Autofac.WebAssembly\Volo.Abp.Autofac.WebAssembly.csproj", "{37F89B0B-1C6B-426F-A5EE-676D1956D9E9}"
@ -365,14 +355,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Http.Tests", "test
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Components.Web", "src\Volo.Abp.AspNetCore.Components.Web\Volo.Abp.AspNetCore.Components.Web.csproj", "{F03A1CEA-FA44-4F30-BFC2-00BC2EAAB4E2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Components.Web.BasicTheme", "src\Volo.Abp.AspNetCore.Components.Web.BasicTheme\Volo.Abp.AspNetCore.Components.Web.BasicTheme.csproj", "{5AD34048-5DAA-4067-9C7D-09295617A057}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Components.Web.Theming", "src\Volo.Abp.AspNetCore.Components.Web.Theming\Volo.Abp.AspNetCore.Components.Web.Theming.csproj", "{B9133C38-AC24-4E2F-B581-D124CF410CDF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EventBus.Abstractions", "src\Volo.Abp.EventBus.Abstractions\Volo.Abp.EventBus.Abstractions.csproj", "{8FDB3BF7-AD89-43F6-8DEB-C3E29B8801FE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Components.Server.BasicTheme", "src\Volo.Abp.AspNetCore.Components.Server.BasicTheme\Volo.Abp.AspNetCore.Components.Server.BasicTheme.csproj", "{F35E5CFC-569F-4D7D-A30F-DD8AE97FEC5A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Sms.Aliyun", "src\Volo.Abp.Sms.Aliyun\Volo.Abp.Sms.Aliyun.csproj", "{ACFBA3FB-18CE-4655-9D14-1F1F5C3DFC30}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Sms.Aliyun.Tests", "test\Volo.Abp.Sms.Aliyun.Tests\Volo.Abp.Sms.Aliyun.Tests.csproj", "{DADEA538-3CA1-4ADE-A7E6-EF77A0CE4401}"
@ -699,10 +685,6 @@ Global
{468C3DCB-8C00-40E7-AE51-0738EAAB312A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{468C3DCB-8C00-40E7-AE51-0738EAAB312A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{468C3DCB-8C00-40E7-AE51-0738EAAB312A}.Release|Any CPU.Build.0 = Release|Any CPU
{2F5EE6D9-511B-4998-BD62-0B9F03E02432}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2F5EE6D9-511B-4998-BD62-0B9F03E02432}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2F5EE6D9-511B-4998-BD62-0B9F03E02432}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F5EE6D9-511B-4998-BD62-0B9F03E02432}.Release|Any CPU.Build.0 = Release|Any CPU
{86A3BB43-8FA2-4CC2-BAD0-A86C6C9D9585}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{86A3BB43-8FA2-4CC2-BAD0-A86C6C9D9585}.Debug|Any CPU.Build.0 = Debug|Any CPU
{86A3BB43-8FA2-4CC2-BAD0-A86C6C9D9585}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -711,14 +693,6 @@ Global
{7E0517E0-AE09-4E10-8469-308F065F2F43}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E0517E0-AE09-4E10-8469-308F065F2F43}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E0517E0-AE09-4E10-8469-308F065F2F43}.Release|Any CPU.Build.0 = Release|Any CPU
{57E29185-6DAF-4A41-8CE0-3F07EE3E289A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{57E29185-6DAF-4A41-8CE0-3F07EE3E289A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{57E29185-6DAF-4A41-8CE0-3F07EE3E289A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{57E29185-6DAF-4A41-8CE0-3F07EE3E289A}.Release|Any CPU.Build.0 = Release|Any CPU
{869F7453-7DDC-4915-B92C-7861466AB68B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{869F7453-7DDC-4915-B92C-7861466AB68B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{869F7453-7DDC-4915-B92C-7861466AB68B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{869F7453-7DDC-4915-B92C-7861466AB68B}.Release|Any CPU.Build.0 = Release|Any CPU
{8B1CB44B-BA40-4C78-9447-A7864126D7C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8B1CB44B-BA40-4C78-9447-A7864126D7C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8B1CB44B-BA40-4C78-9447-A7864126D7C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -931,10 +905,6 @@ Global
{29E42ADB-85F8-44AE-A9B0-078F84C1B866}.Debug|Any CPU.Build.0 = Debug|Any CPU
{29E42ADB-85F8-44AE-A9B0-078F84C1B866}.Release|Any CPU.ActiveCfg = Release|Any CPU
{29E42ADB-85F8-44AE-A9B0-078F84C1B866}.Release|Any CPU.Build.0 = Release|Any CPU
{0C498CF2-D052-4BF7-AD35-509A90F69707}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0C498CF2-D052-4BF7-AD35-509A90F69707}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0C498CF2-D052-4BF7-AD35-509A90F69707}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0C498CF2-D052-4BF7-AD35-509A90F69707}.Release|Any CPU.Build.0 = Release|Any CPU
{E1963439-2BE5-4DB5-8438-2A9A792A1ADA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1963439-2BE5-4DB5-8438-2A9A792A1ADA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1963439-2BE5-4DB5-8438-2A9A792A1ADA}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -1075,10 +1045,6 @@ Global
{4EBDDB1B-D6C5-4FAE-B5A7-2171B18CDFA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EBDDB1B-D6C5-4FAE-B5A7-2171B18CDFA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EBDDB1B-D6C5-4FAE-B5A7-2171B18CDFA5}.Release|Any CPU.Build.0 = Release|Any CPU
{ABC27C10-C0FF-44CB-B4FF-A09C0B79F695}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ABC27C10-C0FF-44CB-B4FF-A09C0B79F695}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ABC27C10-C0FF-44CB-B4FF-A09C0B79F695}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ABC27C10-C0FF-44CB-B4FF-A09C0B79F695}.Release|Any CPU.Build.0 = Release|Any CPU
{29CA7471-4E3E-4E75-8B33-001DDF682F01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{29CA7471-4E3E-4E75-8B33-001DDF682F01}.Debug|Any CPU.Build.0 = Debug|Any CPU
{29CA7471-4E3E-4E75-8B33-001DDF682F01}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -1119,10 +1085,6 @@ Global
{F03A1CEA-FA44-4F30-BFC2-00BC2EAAB4E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F03A1CEA-FA44-4F30-BFC2-00BC2EAAB4E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F03A1CEA-FA44-4F30-BFC2-00BC2EAAB4E2}.Release|Any CPU.Build.0 = Release|Any CPU
{5AD34048-5DAA-4067-9C7D-09295617A057}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5AD34048-5DAA-4067-9C7D-09295617A057}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5AD34048-5DAA-4067-9C7D-09295617A057}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5AD34048-5DAA-4067-9C7D-09295617A057}.Release|Any CPU.Build.0 = Release|Any CPU
{B9133C38-AC24-4E2F-B581-D124CF410CDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9133C38-AC24-4E2F-B581-D124CF410CDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9133C38-AC24-4E2F-B581-D124CF410CDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -1131,10 +1093,6 @@ Global
{8FDB3BF7-AD89-43F6-8DEB-C3E29B8801FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FDB3BF7-AD89-43F6-8DEB-C3E29B8801FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FDB3BF7-AD89-43F6-8DEB-C3E29B8801FE}.Release|Any CPU.Build.0 = Release|Any CPU
{F35E5CFC-569F-4D7D-A30F-DD8AE97FEC5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F35E5CFC-569F-4D7D-A30F-DD8AE97FEC5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F35E5CFC-569F-4D7D-A30F-DD8AE97FEC5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F35E5CFC-569F-4D7D-A30F-DD8AE97FEC5A}.Release|Any CPU.Build.0 = Release|Any CPU
{ACFBA3FB-18CE-4655-9D14-1F1F5C3DFC30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ACFBA3FB-18CE-4655-9D14-1F1F5C3DFC30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ACFBA3FB-18CE-4655-9D14-1F1F5C3DFC30}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -1262,11 +1220,8 @@ Global
{82ED4DD2-DEF8-40D5-9BF9-663AFD35B06D} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{6EABA98D-0B71-4ED7-A939-AFDA106D1151} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{468C3DCB-8C00-40E7-AE51-0738EAAB312A} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{2F5EE6D9-511B-4998-BD62-0B9F03E02432} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{86A3BB43-8FA2-4CC2-BAD0-A86C6C9D9585} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{7E0517E0-AE09-4E10-8469-308F065F2F43} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{57E29185-6DAF-4A41-8CE0-3F07EE3E289A} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{869F7453-7DDC-4915-B92C-7861466AB68B} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{8B1CB44B-BA40-4C78-9447-A7864126D7C3} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{8BB10746-8BAD-4317-8EE5-A36805DB93F6} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{EC71FBDD-A6BD-4B5D-92FE-E108FE12CE8B} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
@ -1320,7 +1275,6 @@ Global
{9467418B-4A9B-4093-9B31-01A9DEF5B372} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{CD5770BB-2E0C-4B3C-80E0-21B8CC43DBA9} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{29E42ADB-85F8-44AE-A9B0-078F84C1B866} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{0C498CF2-D052-4BF7-AD35-509A90F69707} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{E1963439-2BE5-4DB5-8438-2A9A792A1ADA} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{D1815C77-16D6-4F99-8814-69065CD89FB3} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{17F8CA89-D9A2-4863-A5BD-B8E4D2901FD5} = {447C8A77-E5F0-4538-8687-7383196D04EA}
@ -1356,7 +1310,6 @@ Global
{8A22D962-016E-474A-8BB7-F831F0ABF3AC} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{E1A62D10-F2FB-4040-BD60-11A3934058DF} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{4EBDDB1B-D6C5-4FAE-B5A7-2171B18CDFA5} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{ABC27C10-C0FF-44CB-B4FF-A09C0B79F695} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{29CA7471-4E3E-4E75-8B33-001DDF682F01} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{37F89B0B-1C6B-426F-A5EE-676D1956D9E9} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{DEFE3DB2-EA4F-4F90-87FC-B25D64427BC5} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
@ -1367,10 +1320,8 @@ Global
{00D07595-993C-40FC-BD90-0DD6331414D3} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{A37BFEB5-7C57-4CDC-93B8-B5CE4BB9ACE1} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{F03A1CEA-FA44-4F30-BFC2-00BC2EAAB4E2} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{5AD34048-5DAA-4067-9C7D-09295617A057} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{B9133C38-AC24-4E2F-B581-D124CF410CDF} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{8FDB3BF7-AD89-43F6-8DEB-C3E29B8801FE} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{F35E5CFC-569F-4D7D-A30F-DD8AE97FEC5A} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{ACFBA3FB-18CE-4655-9D14-1F1F5C3DFC30} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{DADEA538-3CA1-4ADE-A7E6-EF77A0CE4401} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{863C18F9-2407-49F9-9ADC-F6229AF3B385} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}

14
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Volo.Abp.AspNetCore.Components.Web.BasicTheme.csproj

@ -1,14 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.AspNetCore.Components.Web.Theming\Volo.Abp.AspNetCore.Components.Web.Theming.csproj" />
</ItemGroup>
</Project>

17
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.csproj

@ -1,17 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<PackageId>Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme</PackageId>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.AspNetCore.Components.Web.BasicTheme\Volo.Abp.AspNetCore.Components.Web.BasicTheme.csproj" />
<ProjectReference Include="..\Volo.Abp.AspNetCore.Components.WebAssembly.Theming\Volo.Abp.AspNetCore.Components.WebAssembly.Theming.csproj" />
<ProjectReference Include="..\Volo.Abp.Http.Client.IdentityModel.WebAssembly\Volo.Abp.Http.Client.IdentityModel.WebAssembly.csproj" />
</ItemGroup>
</Project>

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Table/AbpTableTagHelperService.cs

@ -9,6 +9,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Table
{
output.TagName = "table";
output.Attributes.AddClass("table");
output.TagMode = TagMode.StartTagAndEndTag;
SetResponsiveness(context, output);
SetTheme(context, output);
@ -95,4 +96,4 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Table
}
}
}
}
}

8
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js

@ -236,9 +236,11 @@ var abp = abp || {};
var $actionContainer = _createRowAction(aData, column.rowAction, tableInstance);
hideEmptyColumn($actionContainer, tableInstance, colIndex);
var $actionButton = $(cells[colIndex]).find(".abp-action-button");
if ($actionButton.length === 0) {
$(cells[colIndex]).empty().append($actionContainer);
if ($actionContainer) {
var $actionButton = $(cells[colIndex]).find(".abp-action-button");
if ($actionButton.length === 0) {
$(cells[colIndex]).empty().append($actionContainer);
}
}
}
}

2
framework/src/Volo.Abp.Castle.Core/Volo.Abp.Castle.Core.csproj

@ -16,7 +16,7 @@
<ItemGroup>
<PackageReference Include="Castle.Core" Version="4.4.1" />
<PackageReference Include="Castle.Core.AsyncInterceptor" Version="2.0.21-alpha" />
<PackageReference Include="Castle.Core.AsyncInterceptor" Version="2.0.0" />
</ItemGroup>
<ItemGroup>

1
framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj

@ -13,6 +13,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" Version="$(MicrosoftPackageVersion)" />
<PackageReference Include="SharpZipLib" Version="1.3.1" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
<PackageReference Include="NuGet.Versioning" Version="5.9.0" />

8
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs

@ -2,9 +2,11 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.Http;
using Volo.Abp.Cli.LIbs;
using Volo.Abp.Domain;
using Volo.Abp.IdentityModel;
using Volo.Abp.Json;
using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.Minify;
using Volo.Abp.Modularity;
@ -25,6 +27,11 @@ namespace Volo.Abp.Cli
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Configure<AbpSystemTextJsonSerializerOptions>(options =>
{
options.UnsupportedTypes.Add(typeof(ResourceMapping));
});
Configure<AbpCliOptions>(options =>
{
//TODO: Define constants like done for GenerateProxyCommand.Name.
@ -49,6 +56,7 @@ namespace Volo.Abp.Cli
options.Commands["build"] = typeof(BuildCommand);
options.Commands["bundle"] = typeof(BundleCommand);
options.Commands["create-migration-and-run-migrator"] = typeof(CreateMigrationAndRunMigratorCommand);
options.Commands["install-libs"] = typeof(InstallLibsCommand);
});
}
}

78
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/InstallLibsCommand.cs

@ -0,0 +1,78 @@
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.LIbs;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Commands
{
public class InstallLibsCommand : IConsoleCommand, ITransientDependency
{
public ILogger<InstallLibsCommand> Logger { get; set; }
protected IInstallLibsService InstallLibsService { get; }
public InstallLibsCommand(IInstallLibsService installLibsService)
{
InstallLibsService = installLibsService;
Logger = NullLogger<InstallLibsCommand>.Instance;
}
public async Task ExecuteAsync(CommandLineArgs commandLineArgs)
{
var workingDirectoryArg = commandLineArgs.Options.GetOrNull(
Options.WorkingDirectory.Short,
Options.WorkingDirectory.Long
);
var workingDirectory = workingDirectoryArg ?? Directory.GetCurrentDirectory();
if (!Directory.Exists(workingDirectory))
{
throw new CliUsageException(
"Specified directory does not exist." +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
await InstallLibsService.InstallLibsAsync(workingDirectory);
}
public string GetUsageInfo()
{
var sb = new StringBuilder();
sb.AppendLine("");
sb.AppendLine("Usage:");
sb.AppendLine("");
sb.AppendLine(" abp install-libs");
sb.AppendLine("");
sb.AppendLine("Options:");
sb.AppendLine("");
sb.AppendLine("-wd|--working-directory <directory-path> (default: empty)");
sb.AppendLine("");
sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI");
return sb.ToString();
}
public string GetShortDescription()
{
return "Install NPM Packages for MVC / Razor Pages and Blazor Server UI types.";
}
public static class Options
{
public static class WorkingDirectory
{
public const string Short = "wd";
public const string Long = "working-directory";
}
}
}
}

9
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/LIbs/IInstallLibsService.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Volo.Abp.Cli.LIbs
{
public interface IInstallLibsService
{
Task InstallLibsAsync(string directory);
}
}

231
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/LIbs/InstallLibsService.cs

@ -0,0 +1,231 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.FileSystemGlobbing;
using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using NuGet.Versioning;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
namespace Volo.Abp.Cli.LIbs
{
public class InstallLibsService : IInstallLibsService, ITransientDependency
{
public const string LibsDirectory = "./wwwroot/libs";
public ILogger<InstallLibsService> Logger { get; set; }
private readonly IJsonSerializer _jsonSerializer;
public InstallLibsService(IJsonSerializer jsonSerializer)
{
_jsonSerializer = jsonSerializer;
Logger = NullLogger<InstallLibsService>.Instance;
}
public async Task InstallLibsAsync(string directory)
{
var projectFiles = Directory.GetFiles(directory, "*.csproj");
if (!projectFiles.Any())
{
Logger.LogError("No project file found in the directory.");
return;
}
if (!await CanInstallLibs(directory))
{
Logger.LogWarning(
"abp install-libs command is available for MVC, Razor Page, and Blazor-Server UI types");
return;
}
if (!IsNpmInstalled())
{
Logger.LogWarning("NPM is not installed, visit https://nodejs.org/en/download/ and install NPM");
return;
}
if (IsYarnAvailable())
{
RunYarn(directory);
}
else
{
RunNpmInstall(directory);
}
await CleanAndCopyResources(directory);
}
private async Task CleanAndCopyResources(string fileDirectory)
{
var mappingFiles = Directory.GetFiles(fileDirectory, "abp.resourcemapping.js", SearchOption.AllDirectories);
var resourceMapping = new ResourceMapping
{
Clean = new List<string> {LibsDirectory}
};
foreach (var mappingFile in mappingFiles)
{
using (var reader = File.OpenText(mappingFile))
{
var mappingFileContent = await reader.ReadToEndAsync();
var mapping = _jsonSerializer.Deserialize<ResourceMapping>(mappingFileContent
.Replace("module.exports", string.Empty)
.Replace("=", string.Empty).Trim().TrimEnd(';'));
mapping.ReplaceAliases();
mapping.Clean.ForEach(c => resourceMapping.Clean.AddIfNotContains(c));
mapping.Aliases.ToList().ForEach(x =>
{
resourceMapping.Aliases.AddIfNotContains(new KeyValuePair<string, string>(x.Key, x.Value));
});
mapping.Mappings.ToList().ForEach(x =>
{
resourceMapping.Mappings.AddIfNotContains(new KeyValuePair<string, string>(x.Key, x.Value));
});
}
}
EnsureLibsFolderExists(fileDirectory, LibsDirectory);
CleanDirsAndFiles(fileDirectory, resourceMapping);
CopyResourcesToLibs(fileDirectory, resourceMapping);
}
private void EnsureLibsFolderExists(string fileDirectory, string libsDirectory)
{
Directory.CreateDirectory(Path.Combine(fileDirectory, libsDirectory));
}
private void CopyResourcesToLibs(string fileDirectory, ResourceMapping resourceMapping)
{
foreach (var mapping in resourceMapping.Mappings)
{
var destPath = Path.Combine(fileDirectory, mapping.Value);
var files = FindFiles(fileDirectory, mapping.Key);
foreach (var file in files)
{
var destFilePath = Path.Combine(destPath, Path.GetFileName(file));
if (File.Exists(destFilePath))
{
continue;
}
Directory.CreateDirectory(Path.GetFullPath(destPath));
File.Copy(file, destFilePath);
}
}
}
private async Task<bool> CanInstallLibs(string fileDirectory)
{
var projectFiles = Directory.GetFiles(fileDirectory, "*.csproj");
using (var reader = File.OpenText(projectFiles[0]))
{
var projectFileContent = await reader.ReadToEndAsync();
return projectFileContent.Contains("Microsoft.NET.Sdk.Web");
}
}
private void CleanDirsAndFiles(string directory, ResourceMapping resourceMapping)
{
var files = FindFiles(directory, resourceMapping.Clean.ToArray());
foreach (var file in files)
{
if (File.Exists(file))
{
File.Delete(file);
}
}
foreach (var directoryInfo in Directory.GetDirectories(Path.Combine(directory, resourceMapping.Clean.First()),"*", SearchOption.AllDirectories).Reverse())
{
if (!Directory.EnumerateFileSystemEntries(directoryInfo).Any())
{
Directory.Delete(directoryInfo);
}
}
}
private string[] FindFiles(string directory, params string[] patterns)
{
var matcher = new Matcher();
foreach (var pattern in patterns)
{
if (pattern.StartsWith("!"))
{
matcher.AddExclude(NormalizeGlob(pattern).TrimStart('!'));
}
else
{
matcher.AddInclude(NormalizeGlob(pattern));
}
}
var result = matcher.Execute(new DirectoryInfoWrapper(new DirectoryInfo(directory)));
return result.Files.Select(x => Path.Combine(directory, x.Path)).ToArray();
}
private string NormalizeGlob(string pattern)
{
pattern = pattern.Replace("//", "/");
if (!Path.HasExtension(pattern) && !pattern.EndsWith("*"))
{
return pattern.EnsureEndsWith('/') + "**";
}
return pattern;
}
private void RunNpmInstall(string directory)
{
Logger.LogInformation($"Running npm install on {directory}");
CmdHelper.RunCmd($"cd {directory} && npm install");
}
private void RunYarn(string directory)
{
Logger.LogInformation($"Running Yarn on {directory}");
CmdHelper.RunCmd($"cd {directory} && yarn");
}
private bool IsNpmInstalled()
{
var output = CmdHelper.RunCmdAndGetOutput("npm -v").Trim();
return SemanticVersion.TryParse(output, out _);
}
private bool IsYarnAvailable()
{
var output = CmdHelper.RunCmdAndGetOutput("npm list yarn -g").Trim();
if (output.Contains("empty"))
{
return false;
}
if (!SemanticVersion.TryParse(output.Substring(output.IndexOf('@') + 1), out var version))
{
return false;
}
return version > SemanticVersion.Parse("1.20.0");
}
}
}

53
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/LIbs/ResourceMapping.cs

@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.Linq;
namespace Volo.Abp.Cli.LIbs
{
public class ResourceMapping
{
public Dictionary<string, string> Aliases { get; set; }
public List<string> Clean { get; set; }
public Dictionary<string, string> Mappings { get; set; }
public ResourceMapping()
{
Aliases = new Dictionary<string, string>
{
{"@node_modules", "./node_modules"},
{"@libs", "./wwwroot/libs"},
};
Clean = new List<string>();
Mappings = new Dictionary<string, string>();
}
public void ReplaceAliases()
{
for (var i = 0; i < Mappings.Count; i++)
{
var mapping = Mappings.ElementAt(i);
Mappings.Remove(mapping.Key);
var key = mapping.Key;
var value = mapping.Value;
foreach (var alias in Aliases)
{
key = key.Replace(alias.Key, alias.Value);
value = value.Replace(alias.Key, alias.Value);
}
Mappings[key] = value;
}
for (var i = 0; i < Clean.Count; i++)
{
foreach (var alias in Aliases)
{
Clean[i] = Clean[i].Replace(alias.Key, alias.Value);
}
}
}
}
}

23
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/ProjectNameValidator.cs

@ -17,6 +17,11 @@ namespace Volo.Abp.Cli.Utils
"LPT2"
};
private static readonly string[] IllegalKeywords = new[]
{
"Blazor"
};
private static bool HasParentDirectoryString(string projectName)
{
return projectName.Contains("..");
@ -40,6 +45,19 @@ namespace Volo.Abp.Cli.Utils
return false;
}
private static bool HasIllegalKeywords(string projectName)
{
foreach (var illegalKeyword in IllegalKeywords)
{
if (projectName.Contains(illegalKeyword))
{
return true;
}
}
return false;
}
public static bool IsValid(string projectName)
{
if (projectName == null)
@ -62,6 +80,11 @@ namespace Volo.Abp.Cli.Utils
return false;
}
if (HasIllegalKeywords(projectName))
{
return false;
}
return true;
}
}

1
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs

@ -86,7 +86,6 @@ namespace Volo.Abp.EntityFrameworkCore
protected AbpDbContext(DbContextOptions<TDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)

5
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs

@ -82,6 +82,11 @@ namespace Volo.Abp.EntityFrameworkCore.Modeling
}
}
public static void ApplyObjectExtensionMappings(this EntityTypeBuilder b)
{
ObjectExtensionManager.Instance.ConfigureEfCoreEntity(b);
}
public static void ConfigureSoftDelete<T>(this EntityTypeBuilder<T> b)
where T : class, ISoftDelete
{

14
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpModelBuilderObjectExtensions.cs

@ -0,0 +1,14 @@
using Microsoft.EntityFrameworkCore;
using Volo.Abp.ObjectExtending;
namespace Volo.Abp.EntityFrameworkCore.Modeling
{
public static class AbpModelBuilderObjectExtensions
{
public static void TryConfigureObjectExtensions<TDbContext>(this ModelBuilder modelBuilder)
where TDbContext : DbContext
{
ObjectExtensionManager.Instance.ConfigureEfCoreDbContext<TDbContext>(modelBuilder);
}
}
}

70
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionInfoExtensions.cs

@ -1,11 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Volo.Abp.ObjectExtending
{
public static class EfCoreObjectExtensionInfoExtensions
{
public const string EfCoreDbContextConfigurationName = "EfCoreDbContextMapping";
public const string EfCoreEntityConfigurationName = "EfCoreEntityMapping";
[Obsolete("Use MapEfCoreProperty with EntityTypeAndPropertyBuildAction parameters.")]
public static ObjectExtensionInfo MapEfCoreProperty<TProperty>(
[NotNull] this ObjectExtensionInfo objectExtensionInfo,
@ -71,5 +77,69 @@ namespace Volo.Abp.ObjectExtending
}
);
}
public static ObjectExtensionInfo MapEfCoreEntity(
[NotNull] this ObjectExtensionInfo objectExtensionInfo,
[NotNull] Action<EntityTypeBuilder> entityTypeBuildAction)
{
Check.NotNull(objectExtensionInfo, nameof(objectExtensionInfo));
var mappingOptionList = new List<ObjectExtensionInfoEfCoreMappingOptions>
{
new ObjectExtensionInfoEfCoreMappingOptions(
objectExtensionInfo,
entityTypeBuildAction)
};
objectExtensionInfo.Configuration.AddOrUpdate(EfCoreEntityConfigurationName, mappingOptionList,
(k, v) =>
{
v.As<List<ObjectExtensionInfoEfCoreMappingOptions>>().Add(mappingOptionList.First());
return v;
});
return objectExtensionInfo;
}
public static ObjectExtensionInfo MapEfCoreDbContext(
[NotNull] this ObjectExtensionInfo objectExtensionInfo,
[NotNull] Action<ModelBuilder> modelBuildAction)
{
Check.NotNull(objectExtensionInfo, nameof(objectExtensionInfo));
var mappingOptionList = new List<ObjectExtensionInfoEfCoreMappingOptions>
{
new ObjectExtensionInfoEfCoreMappingOptions(
objectExtensionInfo,
modelBuildAction)
};
objectExtensionInfo.Configuration.AddOrUpdate(EfCoreDbContextConfigurationName, mappingOptionList,
(k, v) =>
{
v.As<List<ObjectExtensionInfoEfCoreMappingOptions>>().Add(mappingOptionList.First());
return v;
});
return objectExtensionInfo;
}
public static List<ObjectExtensionInfoEfCoreMappingOptions> GetEfCoreEntityMappings(
[NotNull] this ObjectExtensionInfo objectExtensionInfo)
{
Check.NotNull(objectExtensionInfo, nameof(objectExtensionInfo));
return !objectExtensionInfo.Configuration.TryGetValue(EfCoreEntityConfigurationName, out var options) ?
new List<ObjectExtensionInfoEfCoreMappingOptions>() : options.As<List<ObjectExtensionInfoEfCoreMappingOptions>>();
}
public static List<ObjectExtensionInfoEfCoreMappingOptions> GetEfCoreDbContextMappings(
[NotNull] this ObjectExtensionInfo objectExtensionInfo)
{
Check.NotNull(objectExtensionInfo, nameof(objectExtensionInfo));
return !objectExtensionInfo.Configuration.TryGetValue(EfCoreDbContextConfigurationName, out var options) ?
new List<ObjectExtensionInfoEfCoreMappingOptions>() : options.As<List<ObjectExtensionInfoEfCoreMappingOptions>>();
}
}
}

74
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs

@ -1,5 +1,6 @@
using System;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities;
@ -8,6 +9,45 @@ namespace Volo.Abp.ObjectExtending
{
public static class EfCoreObjectExtensionManagerExtensions
{
public static ObjectExtensionManager MapEfCoreDbContext<TDbContext>(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] Action<ModelBuilder> modelBuilderAction)
where TDbContext : DbContext
{
return objectExtensionManager.AddOrUpdate(
typeof(TDbContext),
options =>
{
options.MapEfCoreDbContext(modelBuilderAction);
});
}
public static ObjectExtensionManager MapEfCoreEntity<TEntity>(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] Action<EntityTypeBuilder> entityTypeBuildAction)
where TEntity : IEntity
{
return MapEfCoreEntity(
objectExtensionManager,
typeof(TEntity),
entityTypeBuildAction);
}
public static ObjectExtensionManager MapEfCoreEntity(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] Type entityType,
[NotNull] Action<EntityTypeBuilder> entityTypeBuildAction)
{
Check.NotNull(objectExtensionManager, nameof(objectExtensionManager));
return objectExtensionManager.AddOrUpdate(
entityType,
options =>
{
options.MapEfCoreEntity(entityTypeBuildAction);
});
}
public static ObjectExtensionManager MapEfCoreProperty<TEntity, TProperty>(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] string propertyName)
@ -32,10 +72,7 @@ namespace Volo.Abp.ObjectExtending
entityType,
propertyType,
propertyName,
options =>
{
options.MapEfCore();
}
options => { options.MapEfCore(); }
);
}
@ -126,6 +163,13 @@ namespace Volo.Abp.ObjectExtending
return;
}
var efCoreEntityMappings = objectExtension.GetEfCoreEntityMappings();
foreach (var efCoreEntityMapping in efCoreEntityMappings)
{
efCoreEntityMapping.EntityTypeBuildAction?.Invoke(typeBuilder);
}
foreach (var property in objectExtension.GetProperties())
{
var efCoreMapping = property.GetEfCoreMappingOrNull();
@ -148,5 +192,27 @@ namespace Volo.Abp.ObjectExtending
#pragma warning restore 618
}
}
public static void ConfigureEfCoreDbContext<TDbContext>(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] ModelBuilder modelBuilder)
where TDbContext : DbContext
{
Check.NotNull(objectExtensionManager, nameof(objectExtensionManager));
Check.NotNull(modelBuilder, nameof(modelBuilder));
var objectExtension = objectExtensionManager.GetOrNull(typeof(TDbContext));
if (objectExtension == null)
{
return;
}
var efCoreDbContextMappings = objectExtension.GetEfCoreDbContextMappings();
foreach (var efCoreDbContextMapping in efCoreDbContextMappings)
{
efCoreDbContextMapping.ModelBuildAction?.Invoke(modelBuilder);
}
}
}
}

39
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionInfoEfCoreMappingOptions.cs

@ -0,0 +1,39 @@
using System;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace Volo.Abp.ObjectExtending
{
public class ObjectExtensionInfoEfCoreMappingOptions
{
[NotNull]
public ObjectExtensionInfo ObjectExtension { get; }
[CanBeNull]
public Action<EntityTypeBuilder> EntityTypeBuildAction { get; set; }
[CanBeNull]
public Action<ModelBuilder> ModelBuildAction { get; set; }
public ObjectExtensionInfoEfCoreMappingOptions(
[NotNull] ObjectExtensionInfo objectExtension,
[NotNull] Action<EntityTypeBuilder> entityTypeBuildAction)
{
ObjectExtension = Check.NotNull(objectExtension, nameof(objectExtension));
EntityTypeBuildAction = Check.NotNull(entityTypeBuildAction, nameof(entityTypeBuildAction));
EntityTypeBuildAction = entityTypeBuildAction;
}
public ObjectExtensionInfoEfCoreMappingOptions(
[NotNull] ObjectExtensionInfo objectExtension,
[NotNull] Action<ModelBuilder> modelBuildAction)
{
ObjectExtension = Check.NotNull(objectExtension, nameof(objectExtension));
ModelBuildAction = Check.NotNull(modelBuildAction, nameof(modelBuildAction));
ModelBuildAction = modelBuildAction;
}
}
}

2
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs

@ -24,7 +24,7 @@ namespace Volo.Abp.ObjectExtending
public ObjectExtensionInfo([NotNull] Type type)
{
Type = Check.AssignableTo<IHasExtraProperties>(type, nameof(type));
Type = Check.NotNull(type, nameof(type));
Properties = new ConcurrentDictionary<string, ObjectExtensionPropertyInfo>();
Configuration = new ConcurrentDictionary<object, object>();
Validators = new List<Action<ObjectExtensionValidationContext>>();

6
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs

@ -25,7 +25,6 @@ namespace Volo.Abp.ObjectExtending
[NotNull]
public virtual ObjectExtensionManager AddOrUpdate<TObject>(
[CanBeNull] Action<ObjectExtensionInfo> configureAction = null)
where TObject : IHasExtraProperties
{
return AddOrUpdate(typeof(TObject), configureAction);
}
@ -50,8 +49,6 @@ namespace Volo.Abp.ObjectExtending
[NotNull] Type type,
[CanBeNull] Action<ObjectExtensionInfo> configureAction = null)
{
Check.AssignableTo<IHasExtraProperties>(type, nameof(type));
var extensionInfo = ObjectsExtensions.GetOrAdd(
type,
_ => new ObjectExtensionInfo(type)
@ -64,7 +61,6 @@ namespace Volo.Abp.ObjectExtending
[CanBeNull]
public virtual ObjectExtensionInfo GetOrNull<TObject>()
where TObject : IHasExtraProperties
{
return GetOrNull(typeof(TObject));
}
@ -72,8 +68,6 @@ namespace Volo.Abp.ObjectExtending
[CanBeNull]
public virtual ObjectExtensionInfo GetOrNull([NotNull] Type type)
{
Check.AssignableTo<IHasExtraProperties>(type, nameof(type));
return ObjectsExtensions.GetOrDefault(type);
}

18
framework/test/Volo.Abp.Cli.Core.Tests/Volo/Abp/Cli/ProjectNameValidation_Tests.cs

@ -45,5 +45,23 @@ namespace Volo.Abp.Cli
var args = new CommandLineArgs("new", "Test..Test");
await _newCommand.ExecuteAsync(args).ShouldThrowAsync<CliUsageException>();
}
[Fact]
public async Task Has_Illegel_Keyword_Test()
{
var illegalKeywords = new[]
{
"Acme.Blazor",
"MyBlazor",
};
foreach (var illegalKeyword in illegalKeywords)
{
var args = new CommandLineArgs("new", illegalKeyword);
await _newCommand.ExecuteAsync(args).ShouldThrowAsync<CliUsageException>();
}
}
}
}

28
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Domain/TestEntityExtensionConfigurator.cs

@ -1,6 +1,8 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Volo.Abp.ObjectExtending;
using Volo.Abp.TestApp.Domain;
using Volo.Abp.TestApp.EntityFrameworkCore;
using Volo.Abp.Threading;
namespace Volo.Abp.EntityFrameworkCore.Domain
@ -35,7 +37,31 @@ namespace Volo.Abp.EntityFrameworkCore.Domain
"EnumNumberString"
).MapEfCoreProperty<City, ExtraProperties_Tests.Color>(
"EnumLiteral"
);
).MapEfCoreEntity<City>(b =>
{
b.As<EntityTypeBuilder<City>>()
.Property(x=>x.Name).IsRequired();
}).MapEfCoreEntity<City>(b =>
{
b.As<EntityTypeBuilder<City>>()
.Property(x=>x.Name).HasMaxLength(200);
}).MapEfCoreEntity(typeof(Person), b =>
{
b.As<EntityTypeBuilder<Person>>()
.HasIndex(x=>x.Birthday);
});
ObjectExtensionManager.Instance.MapEfCoreDbContext<TestAppDbContext>(b =>
{
b.Entity<City>().Property(x => x.Name).IsRequired();
});
ObjectExtensionManager.Instance.MapEfCoreDbContext<TestAppDbContext>(b =>
{
b.Entity<Author>().Property(x => x.Name).IsRequired();
});
});
}
}

9
framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs

@ -1,6 +1,7 @@
using Microsoft.EntityFrameworkCore;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Modeling;
using Volo.Abp.EntityFrameworkCore.TestApp.FourthContext;
using Volo.Abp.EntityFrameworkCore.TestApp.ThirdDbContext;
using Volo.Abp.TestApp.Domain;
@ -41,6 +42,8 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore
modelBuilder.Entity<Phone>(b =>
{
b.HasKey(p => new {p.PersonId, p.Number});
b.ApplyObjectExtensionMappings();
});
modelBuilder
@ -48,6 +51,8 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore
{
p.HasNoKey();
p.ToView("View_PersonView");
p.ApplyObjectExtensionMappings();
});
modelBuilder.Entity<City>(b =>
@ -57,7 +62,11 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore
d.WithOwner().HasForeignKey(x => x.CityId);
d.HasKey(x => new {x.CityId, x.Name});
});
b.ApplyObjectExtensionMappings();
});
modelBuilder.TryConfigureObjectExtensions<TestAppDbContext>();
}
}
}

2
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/IAuditLogRepository.cs

@ -18,6 +18,7 @@ namespace Volo.Abp.AuditLogging
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
@ -33,6 +34,7 @@ namespace Volo.Abp.AuditLogging
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,

10
modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/AbpAuditLoggingDbContextModelBuilderExtensions.cs

@ -50,6 +50,8 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
b.HasIndex(x => new { x.TenantId, x.ExecutionTime });
b.HasIndex(x => new { x.TenantId, x.UserId, x.ExecutionTime });
b.ApplyObjectExtensionMappings();
});
builder.Entity<AuditLogAction>(b =>
@ -67,6 +69,8 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
b.HasIndex(x => new { x.AuditLogId });
b.HasIndex(x => new { x.TenantId, x.ServiceName, x.MethodName, x.ExecutionTime });
b.ApplyObjectExtensionMappings();
});
builder.Entity<EntityChange>(b =>
@ -86,6 +90,8 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
b.HasIndex(x => new { x.AuditLogId });
b.HasIndex(x => new { x.TenantId, x.EntityTypeFullName, x.EntityId });
b.ApplyObjectExtensionMappings();
});
builder.Entity<EntityPropertyChange>(b =>
@ -100,7 +106,11 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
b.Property(x => x.OriginalValue).HasMaxLength(EntityPropertyChangeConsts.MaxOriginalValueLength).HasColumnName(nameof(EntityPropertyChange.OriginalValue));
b.HasIndex(x => new { x.EntityChangeId });
b.ApplyObjectExtensionMappings();
});
builder.TryConfigureObjectExtensions<AbpAuditLoggingDbContext>();
}
}
}

6
modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo/Abp/AuditLogging/EntityFrameworkCore/EfCoreAuditLogRepository.cs

@ -29,6 +29,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
@ -44,6 +45,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
endTime,
httpMethod,
url,
userId,
userName,
applicationName,
correlationId,
@ -67,6 +69,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
@ -81,6 +84,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
endTime,
httpMethod,
url,
userId,
userName,
applicationName,
correlationId,
@ -100,6 +104,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
@ -118,6 +123,7 @@ namespace Volo.Abp.AuditLogging.EntityFrameworkCore
.WhereIf(hasException.HasValue && !hasException.Value, auditLog => auditLog.Exceptions == null || auditLog.Exceptions == "")
.WhereIf(httpMethod != null, auditLog => auditLog.HttpMethod == httpMethod)
.WhereIf(url != null, auditLog => auditLog.Url != null && auditLog.Url.Contains(url))
.WhereIf(userId != null, auditLog => auditLog.UserId == userId)
.WhereIf(userName != null, auditLog => auditLog.UserName == userName)
.WhereIf(applicationName != null, auditLog => auditLog.ApplicationName == applicationName)
.WhereIf(correlationId != null, auditLog => auditLog.CorrelationId == correlationId)

7
modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo/Abp/AuditLogging/MongoDB/MongoAuditLogRepository.cs

@ -30,6 +30,7 @@ namespace Volo.Abp.AuditLogging.MongoDB
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
@ -45,6 +46,7 @@ namespace Volo.Abp.AuditLogging.MongoDB
endTime,
httpMethod,
url,
userId,
userName,
applicationName,
correlationId,
@ -68,6 +70,7 @@ namespace Volo.Abp.AuditLogging.MongoDB
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
@ -82,6 +85,7 @@ namespace Volo.Abp.AuditLogging.MongoDB
endTime,
httpMethod,
url,
userId,
userName,
applicationName,
correlationId,
@ -103,6 +107,7 @@ namespace Volo.Abp.AuditLogging.MongoDB
DateTime? endTime = null,
string httpMethod = null,
string url = null,
Guid? userId = null,
string userName = null,
string applicationName = null,
string correlationId = null,
@ -120,6 +125,7 @@ namespace Volo.Abp.AuditLogging.MongoDB
.WhereIf(hasException.HasValue && !hasException.Value, auditLog => auditLog.Exceptions == null || auditLog.Exceptions == "")
.WhereIf(httpMethod != null, auditLog => auditLog.HttpMethod == httpMethod)
.WhereIf(url != null, auditLog => auditLog.Url != null && auditLog.Url.Contains(url))
.WhereIf(userId != null, auditLog => auditLog.UserId == userId)
.WhereIf(userName != null, auditLog => auditLog.UserName == userName)
.WhereIf(applicationName != null, auditLog => auditLog.ApplicationName == applicationName)
.WhereIf(correlationId != null, auditLog => auditLog.CorrelationId == correlationId)
@ -128,7 +134,6 @@ namespace Volo.Abp.AuditLogging.MongoDB
.WhereIf(minDuration != null && minDuration > 0, auditLog => auditLog.ExecutionDuration >= minDuration);
}
public virtual async Task<Dictionary<DateTime, double>> GetAverageExecutionDurationPerDayAsync(
DateTime startDate,
DateTime endDate,

4
modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContextModelCreatingExtensions.cs

@ -39,7 +39,11 @@ namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore
b.Property(x => x.Priority).HasDefaultValue(BackgroundJobPriority.Normal);
b.HasIndex(x => new { x.IsAbandoned, x.NextTryTime });
b.ApplyObjectExtensionMappings();
});
builder.TryConfigureObjectExtensions<BackgroundJobsDbContext>();
}
}
}

65
modules/basic-theme/Volo.Abp.BasicTheme.sln

@ -0,0 +1,65 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED6D078F-B0A2-48E8-A09D-3B7CDF6CE3D1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0BC55E3B-4964-48E3-A390-2ADD37980149}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Components.Server.BasicTheme", "src\Volo.Abp.AspNetCore.Components.Server.BasicTheme\Volo.Abp.AspNetCore.Components.Server.BasicTheme.csproj", "{C8068E7F-4A04-4755-8976-C2A4C0ADC708}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Components.Web.BasicTheme", "src\Volo.Abp.AspNetCore.Components.Web.BasicTheme\Volo.Abp.AspNetCore.Components.Web.BasicTheme.csproj", "{655C0CF7-7BFA-45E4-A157-E868A97FB45B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme", "src\Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme\Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.csproj", "{95954B0B-9FE0-4351-B1F2-53DDF03F0738}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic", "src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj", "{21E20CC4-E82B-451B-BB73-141997C81C56}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo", "test\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo.csproj", "{7DFA95DB-F3A1-4883-AB03-9B02E540A134}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo", "test\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.csproj", "{51B491ED-F959-4974-A876-528B5F16BC92}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests", "test\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests.csproj", "{8C336CB8-F7A9-4203-AE55-D8F5FDB2A958}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C8068E7F-4A04-4755-8976-C2A4C0ADC708}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C8068E7F-4A04-4755-8976-C2A4C0ADC708}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C8068E7F-4A04-4755-8976-C2A4C0ADC708}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C8068E7F-4A04-4755-8976-C2A4C0ADC708}.Release|Any CPU.Build.0 = Release|Any CPU
{655C0CF7-7BFA-45E4-A157-E868A97FB45B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{655C0CF7-7BFA-45E4-A157-E868A97FB45B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{655C0CF7-7BFA-45E4-A157-E868A97FB45B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{655C0CF7-7BFA-45E4-A157-E868A97FB45B}.Release|Any CPU.Build.0 = Release|Any CPU
{95954B0B-9FE0-4351-B1F2-53DDF03F0738}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95954B0B-9FE0-4351-B1F2-53DDF03F0738}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95954B0B-9FE0-4351-B1F2-53DDF03F0738}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95954B0B-9FE0-4351-B1F2-53DDF03F0738}.Release|Any CPU.Build.0 = Release|Any CPU
{21E20CC4-E82B-451B-BB73-141997C81C56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{21E20CC4-E82B-451B-BB73-141997C81C56}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21E20CC4-E82B-451B-BB73-141997C81C56}.Release|Any CPU.ActiveCfg = Release|Any CPU
{21E20CC4-E82B-451B-BB73-141997C81C56}.Release|Any CPU.Build.0 = Release|Any CPU
{7DFA95DB-F3A1-4883-AB03-9B02E540A134}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7DFA95DB-F3A1-4883-AB03-9B02E540A134}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7DFA95DB-F3A1-4883-AB03-9B02E540A134}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7DFA95DB-F3A1-4883-AB03-9B02E540A134}.Release|Any CPU.Build.0 = Release|Any CPU
{51B491ED-F959-4974-A876-528B5F16BC92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{51B491ED-F959-4974-A876-528B5F16BC92}.Debug|Any CPU.Build.0 = Debug|Any CPU
{51B491ED-F959-4974-A876-528B5F16BC92}.Release|Any CPU.ActiveCfg = Release|Any CPU
{51B491ED-F959-4974-A876-528B5F16BC92}.Release|Any CPU.Build.0 = Release|Any CPU
{8C336CB8-F7A9-4203-AE55-D8F5FDB2A958}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C336CB8-F7A9-4203-AE55-D8F5FDB2A958}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C336CB8-F7A9-4203-AE55-D8F5FDB2A958}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C336CB8-F7A9-4203-AE55-D8F5FDB2A958}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{C8068E7F-4A04-4755-8976-C2A4C0ADC708} = {ED6D078F-B0A2-48E8-A09D-3B7CDF6CE3D1}
{655C0CF7-7BFA-45E4-A157-E868A97FB45B} = {ED6D078F-B0A2-48E8-A09D-3B7CDF6CE3D1}
{95954B0B-9FE0-4351-B1F2-53DDF03F0738} = {ED6D078F-B0A2-48E8-A09D-3B7CDF6CE3D1}
{21E20CC4-E82B-451B-BB73-141997C81C56} = {ED6D078F-B0A2-48E8-A09D-3B7CDF6CE3D1}
{7DFA95DB-F3A1-4883-AB03-9B02E540A134} = {0BC55E3B-4964-48E3-A390-2ADD37980149}
{51B491ED-F959-4974-A876-528B5F16BC92} = {0BC55E3B-4964-48E3-A390-2ADD37980149}
{8C336CB8-F7A9-4203-AE55-D8F5FDB2A958} = {0BC55E3B-4964-48E3-A390-2ADD37980149}
EndGlobalSection
EndGlobal

0
framework/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/AbpAspNetCoreComponentsServerBasicThemeModule.cs → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/AbpAspNetCoreComponentsServerBasicThemeModule.cs

0
framework/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/BasicThemeToolbarContributor.cs → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/BasicThemeToolbarContributor.cs

0
framework/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Bundling/BlazorBasicThemeBundles.cs → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Bundling/BlazorBasicThemeBundles.cs

0
framework/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Bundling/BlazorBasicThemeScriptContributor.cs → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Bundling/BlazorBasicThemeScriptContributor.cs

0
framework/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Bundling/BlazorBasicThemeStyleContributor.cs → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Bundling/BlazorBasicThemeStyleContributor.cs

0
framework/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/FodyWeavers.xml → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/FodyWeavers.xml

0
framework/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/FodyWeavers.xsd → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/FodyWeavers.xsd

0
framework/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/LanguageSwitch.razor → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/LanguageSwitch.razor

0
framework/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/LoginDisplay.razor → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/LoginDisplay.razor

0
framework/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/LoginDisplay.razor.cs → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/LoginDisplay.razor.cs

0
framework/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/_Imports.razor → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Themes/Basic/_Imports.razor

6
framework/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Volo.Abp.AspNetCore.Components.Server.BasicTheme.csproj → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Server.BasicTheme/Volo.Abp.AspNetCore.Components.Server.BasicTheme.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
@ -12,7 +12,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.AspNetCore.Components.Server.Theming\Volo.Abp.AspNetCore.Components.Server.Theming.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Components.Server.Theming\Volo.Abp.AspNetCore.Components.Server.Theming.csproj" />
<ProjectReference Include="..\Volo.Abp.AspNetCore.Components.Web.BasicTheme\Volo.Abp.AspNetCore.Components.Web.BasicTheme.csproj" />
</ItemGroup>

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/AbpAspNetCoreComponentsWebBasicThemeModule.cs → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/AbpAspNetCoreComponentsWebBasicThemeModule.cs

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/FodyWeavers.xml → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/FodyWeavers.xml

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/FodyWeavers.xsd → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/FodyWeavers.xsd

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/App.razor → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/App.razor

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/AppWithoutAuth.razor → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/AppWithoutAuth.razor

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/Branding.razor → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/Branding.razor

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor.cs → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor.cs

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainLayout.razor → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainLayout.razor

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainLayout.razor.cs → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainLayout.razor.cs

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor.cs → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor.cs

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavToolbar.razor → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavToolbar.razor

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavToolbar.razor.cs → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavToolbar.razor.cs

0
framework/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/RedirectToLogin.razor → modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/RedirectToLogin.razor

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

Loading…
Cancel
Save