Browse Source

Merge branch 'dev' into auto-merge/rel-4-1/50

pull/7059/head
Mehmet Erim 5 years ago
committed by GitHub
parent
commit
ec98bc8e15
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      .github/workflows/auto-pr.yml
  2. 5
      README.md
  3. 14
      abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/en-GB.json
  4. 202
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en-GB.json
  5. 35
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en-GB.json
  6. 39
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en-GB.json
  7. 106
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en-GB.json
  8. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
  9. 197
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en-GB.json
  10. 2
      common.props
  11. 4
      docs/en/Background-Workers.md
  12. 2
      docs/en/Blob-Storing-Aliyun.md
  13. 2
      docs/en/Blob-Storing-Aws.md
  14. 2
      docs/en/Blob-Storing-Azure.md
  15. 2
      docs/en/Blob-Storing-Minio.md
  16. 2
      docs/en/Blob-Storing.md
  17. 51
      docs/en/Blog-Posts/2021-01-07 v4_1_Release_Stable/POST.md
  18. 8
      docs/en/CLI.md
  19. 5
      docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/POST.md
  20. 2
      docs/en/Contribution/Index.md
  21. 4
      docs/en/Emailing.md
  22. 10
      docs/en/Entity-Framework-Core-Migrations.md
  23. 41
      docs/en/Entity-Framework-Core.md
  24. 2
      docs/en/Modules/Docs.md
  25. 41
      docs/en/MongoDB.md
  26. 5
      docs/en/Repositories.md
  27. 10
      docs/en/Samples/Microservice-Demo.md
  28. 10
      docs/en/UI/AspNetCore/Branding.md
  29. 3
      docs/en/UI/Blazor/Page-Progress.md
  30. 2
      docs/zh-Hans/Blob-Storing-Aliyun.md
  31. 2
      docs/zh-Hans/Blob-Storing-Aws.md
  32. 2
      docs/zh-Hans/Blob-Storing-Azure.md
  33. 2
      docs/zh-Hans/Blob-Storing-Minio.md
  34. 12
      docs/zh-Hans/Blob-Storing.md
  35. 2
      docs/zh-Hans/CLI.md
  36. 2
      docs/zh-Hans/Domain-Driven-Design-Implementation-Guide.md
  37. 10
      docs/zh-Hans/Entity-Framework-Core-Migrations.md
  38. 2
      docs/zh-Hans/Modules/Docs.md
  39. 6
      docs/zh-Hans/Samples/Microservice-Demo.md
  40. 37
      framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs
  41. 10
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/Branding.razor
  42. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor
  43. 16
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor
  44. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/SecondLevelNavMenuItem.razor
  45. 9
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
  46. 49
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpIdNameTagHelper.cs
  47. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/PagerModel.cs
  48. 12
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en-GB.json
  49. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml
  50. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js
  51. 41
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs
  52. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj
  53. 3
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs
  54. 41
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpController.cs
  55. 37
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Authentication/ChallengeAccountController.cs
  56. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs
  57. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs
  58. 4
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs
  59. 52
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs
  60. 17
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions.cs
  61. 6
      framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AuthorizationOptionsExtensions.cs
  62. 10
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/en-GB.json
  63. 16
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs
  64. 10
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs
  65. 34
      framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs
  66. 26
      framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs
  67. 140
      framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacRegistration.cs
  68. 122
      framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProvider.cs
  69. 77
      framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProviderFactory.cs
  70. 67
      framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceScope.cs
  71. 65
      framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceScopeFactory.cs
  72. 4
      framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj
  73. 4
      framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs
  74. 4
      framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs
  75. 9
      framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/AbpBackgroundJobsHangfireModule.cs
  76. 26
      framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/AbpDashboardOptionsProvider.cs
  77. 10
      framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/AbpBackgroundWorkersQuartzModule.cs
  78. 2
      framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerAdapter.cs
  79. 9
      framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs
  80. 4
      framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs
  81. 10
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs
  82. 2
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs
  83. 2
      framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProviderConfiguration.cs
  84. 2
      framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobProviderConfiguration.cs
  85. 4
      framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProviderConfiguration.cs
  86. 3
      framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainerFactoryExtensions.cs
  87. 1
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliCoreModule.cs
  88. 61
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigrator.cs
  89. 106
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs
  90. 1
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs
  91. 13
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/DatabaseManagementSystem.cs
  92. 97
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs
  93. 17
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs
  94. 6
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs
  95. 10
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs
  96. 24
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateChangeDbMigratorPortSettingsStep.cs
  97. 46
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RemoveUnnecessaryPortsStep.cs
  98. 40
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationAdder.cs
  99. 73
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationManager.cs
  100. 8
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs

12
.github/workflows/auto-pr.yml

@ -1,10 +1,10 @@
name: Merge branch dev with rel-4.1
name: Merge branch dev with rel-4.2
on:
push:
branches:
- rel-4.1
- rel-4.2
jobs:
merge-dev-with-rel-4-1:
merge-dev-with-rel:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@ -17,8 +17,8 @@ jobs:
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
branch: auto-merge/rel-4-1/${{github.run_number}}
title: Merge branch dev with rel-4.1
body: This PR generated automatically to merge dev with rel-4.1. Please review the changed files before merging to prevent any errors that may occur.
branch: auto-merge/rel-4-2/${{github.run_number}}
title: Merge branch dev with rel-4.2
body: This PR generated automatically to merge dev with rel-4.2. Please review the changed files before merging to prevent any errors that may occur.
reviewers: ${{github.actor}}
token: ${{ github.token }}

5
README.md

@ -2,7 +2,8 @@
![build and test](https://github.com/abpframework/abp/workflows/build%20and%20test/badge.svg)
[![NuGet](https://img.shields.io/nuget/v/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core)
[![MyGet (with prereleases)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds)
[![NuGet (with prereleases)](https://img.shields.io/nuget/vpre/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core)
[![MyGet (nightly builds)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds)
[![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core)
ABP Framework is a complete **infrastructure** based on the **ASP.NET Core** to create **modern web applications** and **APIs** by following the software development **best practices** and the **latest technologies**.
@ -103,4 +104,4 @@ ABP is a community-driven open source project. See [the contribution guide](http
## Support the ABP Framework
Love ABP Framework? **Please give a star** to this repository :star:
Love ABP Framework? **Please give a star** to this repository :star:

14
abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/en-GB.json

@ -0,0 +1,14 @@
{
"culture": "en-GB",
"texts": {
"Account": "ABP Account - Login & Register | ABP.IO",
"Welcome": "Welcome",
"UseOneOfTheFollowingLinksToContinue": "Use one of the following links to continue",
"FrameworkHomePage": "Framework home page",
"FrameworkDocumentation": "Framework documentation",
"OfficialBlog": "Official blog",
"CommercialHomePage": "Commercial home page",
"CommercialSupportWebSite": "Commercial support web site",
"CommunityWebSite": "ABP community web site"
}
}

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

@ -0,0 +1,202 @@
{
"culture": "en-GB",
"texts": {
"Permission:Organizations": "Organisations",
"Permission:Manage": "Manage Organisations",
"Permission:DiscountRequests": "Discount Requests",
"Permission:DiscountManage": "Manage Discount Requests",
"Permission:Disable": "Disable",
"Permission:Enable": "Enable",
"Permission:EnableSendEmail": "Enable Send Email",
"Permission:SendEmail": "Send Email",
"Permission:NpmPackages": "NPM Packages",
"Permission:NugetPackages": "Nuget Packages",
"Permission:Maintenance": "Maintenance",
"Permission:Maintain": "Maintain",
"Permission:ClearCaches": "Clear caches",
"Permission:Modules": "Modules",
"Permission:Packages": "Packages",
"Permission:Edit": "Edit",
"Permission:Delete": "Delete",
"Permission:Create": "Create",
"Permission:Accounting": "Accounting",
"Permission:Accounting:Quotation": "Quotation",
"Permission:Accounting:Invoice": "Invoice",
"Menu:Organizations": "Organisations",
"Menu:Accounting": "Accounting",
"Menu:Packages": "Packages",
"Menu:DiscountRequests": "Discount Requests",
"NpmPackageDeletionWarningMessage": "This NPM Package will be deleted. Please confirm this?",
"NugetPackageDeletionWarningMessage": "This Nuget Package will be deleted. Please confirm this?",
"ModuleDeletionWarningMessage": "This Module will be deleted. Please confirm this?",
"Name": "Name",
"DisplayName": "Display name",
"ShortDescription": "Short description",
"NameFilter": "Name",
"CreationTime": "Creation time",
"IsPro": "Is pro",
"ShowOnModuleList": "Show in module list",
"EfCoreConfigureMethodName": "Configure method name",
"IsProFilter": "Is pro",
"ApplicationType": "Application type",
"Target": "Target",
"TargetFilter": "Target",
"ModuleClass": "Module class",
"NugetPackageTarget.DomainShared": "Domain Shared",
"NugetPackageTarget.Domain": "Domain",
"NugetPackageTarget.Application": "Application",
"NugetPackageTarget.ApplicationContracts": "Application Contracts",
"NugetPackageTarget.HttpApi": "Http Api",
"NugetPackageTarget.HttpApiClient": "Http Api Client",
"NugetPackageTarget.Web": "Web",
"NugetPackageTarget.EntityFrameworkCore": "Delete Entity Framework Core",
"NugetPackageTarget.MongoDB": "MongoDB",
"Edit": "Edit",
"Delete": "Delete",
"Refresh": "Refresh",
"NpmPackages": "NPM Packages",
"NugetPackages": "Nuget Packages",
"NpmPackageCount": "NPM Package Count",
"NugetPackageCount": "Nuget Package Count",
"Module": "Modules",
"ModuleInfo": "Module info",
"CreateANpmPackage": "Create a NPM package",
"CreateAModule": "Create a module",
"CreateANugetPackage": "Create a Nuget package",
"AddNew": "Add new",
"PackageAlreadyExist{0}": "\"{0}\" package has already been added.",
"ModuleAlreadyExist{0}": "\"{0}\" module has already been added.",
"ClearCache": "Clear cache",
"SuccessfullyCleared": "Successfully cleared",
"Menu:NpmPackages": "NPM Packages",
"Menu:Modules": "Modules",
"Menu:Maintenance": "Maintenance",
"Menu:NugetPackages": "Nuget Packages",
"CreateAnOrganization": "Create an organisation",
"Organizations": "Organisations",
"LongName": "Long name",
"LicenseType": "License type",
"MissingLicenseTypeField": "The license type field is required!",
"LicenseStartTime": "License start time",
"LicenseEndTime": "License end time",
"AllowedDeveloperCount": "Allowed developer count",
"UserNameOrEmailAddress": "Username or email address",
"AddOwner": "Add owner",
"UserName": "Username",
"Email": "Email",
"Developers": "Developers",
"AddDeveloper": "Add developer",
"Create": "Create",
"UserNotFound": "User not found",
"{0}WillBeRemovedFromDevelopers": "{0} Will be removed from developers, please confirm?",
"{0}WillBeRemovedFromOwners": "{0} Will be removed from owners, please confirm?",
"Computers": "Computers",
"UniqueComputerId": "Unique computer id",
"LastSeenDate": "Last seen date",
"{0}Computer{1}WillBeRemovedFromRecords": "Computer of {0} ({1}) will be removed from records",
"OrganizationDeletionWarningMessage": "Organisation will be deleted",
"DeletingLastOwnerWarningMessage": "An organisation must have at least one owner, therefore you cannot remove this owner",
"This{0}AlreadyExistInThisOrganization": "{0} already exist in this organisation",
"AreYouSureYouWantToDeleteAllComputers": "Are you sure you want to delete all computers?",
"DeleteAll": "Delete all",
"DoYouWantToCreateNewUser": "Do you want to create new user?",
"MasterModules": "Master Modules",
"OrganizationName": "Organisation name",
"CreationDate": "Creation date",
"LicenseStartDate": "License start date",
"LicenseEndDate": "License end date",
"OrganizationNamePlaceholder": "Organisation name...",
"TotalQuestionCountPlaceholder": "Total question count...",
"RemainingQuestionCountPlaceholder": "Remaining question count...",
"LicenseTypePlaceholder": "License type...",
"CreationDatePlaceholder": "Creation date...",
"LicenseStartDatePlaceholder": "License start date...",
"LicenseEndDatePlaceholder": "License end date...",
"UsernameOrEmail": "Username or email",
"UsernameOrEmailPlaceholder": "Username or email...",
"Member": "Member",
"PurchaseOrderNo": "Purchase Order No.",
"QuotationDate": "Quotation date",
"CompanyName": "Company name",
"CompanyAddress": "Company address",
"Price": "Price",
"DiscountText": "Discount text",
"DiscountQuantity": "Discount quantity",
"DiscountPrice": "Discount price",
"Quotation": "Quotation",
"ExtraText": "Extra text",
"ExtraAmount": "Extra Amount",
"DownloadQuotation": "Download Quotation",
"Invoice": "Invoice",
"TaxNumber": "Tax No.",
"InvoiceNumber": "Invoice No.",
"InvoiceDate": "Invoice Date",
"InvoiceNote": "Invoice Note",
"Quantity": "Quantity",
"AddProduct": "Add Product",
"AddProductWarning": "You need to add a Product!",
"TotalPrice": "Total Price",
"Generate": "Generate",
"MissingQuantityField": "The Quantity field is required!",
"MissingPriceField": "The Price field is required!",
"CodeUsageStatus": "Status",
"Country": "Country",
"DeveloperCount": "Developer Count",
"RequestCode": "Request Code",
"WebSite": "Website",
"GithubUsername": "Github Username",
"PhoneNumber": "Phone Number",
"ProjectDescription": "Project Description",
"Referrer": "Referrer",
"DiscountRequests": "Discount Request",
"Copylink": "Copy Link",
"Disable": "Disable",
"Enable": "Enable",
"EnableSendEmail": "Enable Send Email",
"SendEmail": "Send Email",
"SuccessfullyDisabled": "Successfully disabled",
"SuccessfullyEnabled": "Successfully enabled",
"EmailSent": "Email sent",
"SuccessfullySent": "Successfully sent",
"SuccessfullyDeleted": "Successfully deleted",
"DiscountRequestDeletionWarningMessage": "Discount request will be deleted",
"BusinessType": "Business Type",
"TotalQuestionCount": "Total question count",
"RemainingQuestionCount": "Remaining question count",
"TotalQuestionMustBeGreaterWarningMessage": "TotalQuestionCount must be greater than RemainingQuestionCount!",
"QuestionCountsMustBeGreaterThanZero": "TotalQuestionCount and RemainingQuestionCount must be zero or greater than zero!",
"UnlimitedQuestionCount": "Unlimited question count",
"Notes": "Notes",
"Menu:Community": "Community",
"Menu:Articles": "Articles",
"Wait": "Wait",
"Approve": "Approve",
"Reject": "Reject",
"Details": "Details",
"Url": "Url",
"Title": "Title",
"ContentSource": "Content source",
"Status": "Status",
"ReadArticle": "Read article",
"ArticleHasBeenWaiting": "Article has been waiting",
"ArticleHasBeenApproved": "Article has been approved",
"ArticleHasBeenRejected": "Article has been rejected",
"Permission:Community": "Community",
"Permission:CommunityArticle": "Article",
"Link": "Link",
"Enum:ContentSource:0": "Github",
"Enum:ContentSource:1": "External",
"Enum:Status:0": "Waiting",
"Enum:Status:1": "Author name",
"Enum:Status:2": "Approved",
"Summary": "Summary",
"AuthorName": "Author",
"CoverImage": "Cover Image",
"RemoveCacheConfirmationMessage": "Are you sure you want remove the cache for \"{0}\" article?",
"SuccessfullyRemoved": "Successfully cleared",
"RemoveCache": "Remove Cache",
"Language": "Language",
"Optional": "Optional",
"CreateArticleLanguageInfo": "The language in which the article is written"
}
}

35
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en-GB.json

@ -0,0 +1,35 @@
{
"culture": "en-GB",
"texts": {
"Volo.AbpIo.Domain:010004": "Maximum member count reached!",
"Volo.AbpIo.Domain:010005": "Maximum owner count reached!",
"Volo.AbpIo.Domain:010006": "This user is already an owner in this organisation!",
"Volo.AbpIo.Domain:010007": "This user is already a developer in this organisation!",
"Volo.AbpIo.Domain:010008": "Allowed Developer Count can not be less then current developer count!",
"Volo.AbpIo.Domain:010009": "Allowed Developer Count can not be less then 0!",
"Volo.AbpIo.Domain:010010": "Maximum mac address count has been exceeded!",
"Volo.AbpIo.Domain:010011": "Personal license can't have more than 1 developer!",
"Volo.AbpIo.Domain:010012": "License can't be extended one month after license expires!",
"Volo.AbpIo.Domain:020001": "Couldn't delete this NPM Package because \"{NugetPackages}\" Nuget Packages are dependent to this package.",
"Volo.AbpIo.Domain:020002": "Couldn't delete this NPM Package because \"{Modules}\" Modules are using this package.",
"Volo.AbpIo.Domain:020003": "Couldn't delete this NPM Package because \"{Modules}\" Modules are using this package and \"{NugetPackages}\" Nuget Packages are dependent to this package.",
"Volo.AbpIo.Domain:020004": "Couldn't delete this Nuget Package because \"{Modules}\" Modules are using this package.",
"WantToLearn?": "Want to learn?",
"ReadyToGetStarted?": "Ready to get started?",
"JoinOurCommunity": "Join our community",
"GetStartedUpper": "GET STARTED",
"ForkMeOnGitHub": "Fork me on GitHub",
"Features": "Features",
"GetStarted": "Get Started",
"Documents": "Documents",
"Community": "Community",
"ContributionGuide": "Contribution Guide",
"Blog": "Blog",
"Commercial": "Commercial",
"MyAccount": "My account",
"Permission:License": "License",
"Permission:UserInfo": "User info",
"SeeDocuments": "See Documents",
"Samples": "Samples"
}
}

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

@ -0,0 +1,39 @@
{
"culture": "en-GB",
"texts": {
"OrganizationManagement": "Organisation Management",
"OrganizationList": "Organisation list",
"Volo.AbpIo.Commercial:010003": "You are not owner of this organisation!",
"OrganizationNotFoundMessage": "Organisation not found!",
"DeveloperCount": "Allocated / total developers",
"QuestionCount": "Remaining / total questions",
"Unlimited": "Unlimited",
"Owners": "Owners",
"AddMember": "Add member",
"AddOwner": "Add owner",
"AddDeveloper": "Add developer",
"UserName": "Username",
"Name": "Name",
"EmailAddress": "Email address",
"Developers": "Developers",
"LicenseType": "License type",
"Manage": "Manage",
"StartDate": "Start date",
"EndDate": "End date",
"Modules": "Modules",
"LicenseExtendMessage": "Your license end date is extended to {0}",
"LicenseUpgradeMessage": "Your license is upgraded to {0}",
"LicenseAddDeveloperMessage": "{0} developers added to your license",
"Volo.AbpIo.Commercial:010004": "Cannot find the specified user! The user must have already registered.",
"MyOrganizations": "My organisations",
"ApiKey": "API key",
"UserNameNotFound": "There is no user with username {0}",
"SuccessfullyAddedToNewsletter": "Thank you for subscribing to our newsletter!",
"MyProfile": "My Profile",
"EmailNotValid": "Please enter a valid email address.",
"JoinOurMarketingNewsletter": "Join our marketing newsletter",
"WouldLikeToReceiveMarketingMaterials": "I would like to receive marketing materials e.g. product deals & special offers.",
"StartUsingYourLicenseNow": "Start using your license now!",
"WelcomePage": "Welcome Page"
}
}

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

@ -0,0 +1,106 @@
{
"culture": "en-GB",
"texts": {
"Permission:CommunityArticle": "Community Article",
"Permission:Edit": "Edit",
"Waiting": "Waiting",
"Approved": "Approved",
"Rejected": "Rejected",
"Wait": "Wait",
"Approve": "Approve",
"Reject": "Reject",
"ReadArticle": "Read Article",
"Status": "Status",
"ContentSource": "Content Source",
"Details": "Details",
"Url": "Url",
"Title": "Title",
"CreationTime": "Creation time",
"Save": "Save",
"SameUrlAlreadyExist": "The Url already exists. If you want to add this article, you should change the url!",
"UrlIsNotValid": "Url is not valid.",
"UrlNotFound": "Url not found.",
"UrlContentNotFound": "Url content not found.",
"Summary": "Summary",
"MostRead": "Most Read",
"Latest": "Latest",
"ContributeAbpCommunity": "Contribute to the ABP Community",
"SubmitYourArticle": "Submit Your Article",
"ContributionGuide": "Contribution Guide",
"BugReport": "Bug Report",
"SeeAllArticles": "See All Articles",
"WelcomeToABPCommunity!": "Welcome to the ABP Community!",
"MyProfile": "My Profile",
"MyOrganizations": "My Organisations",
"EmailNotValid": "Please enter a valid email address.",
"FeatureRequest": "Feature Request",
"CreateArticleTitleInfo": "Title of the article to be shown on the article list.",
"CreateArticleUrlInfo": "Original GitHub/External URL of the article.",
"CreateArticleSummaryInfo": "A short summary of the article to be shown on the article list.",
"CreateArticleCoverInfo": "To create an effective article, add a cover photo and an upload 16:9 aspect ratio pictures for the best view (Maximum file size: 1MB)",
"ThisExtensionIsNotAllowed": "The extension is not allowed.",
"TheFileIsTooLarge": "The file is too large.",
"GoToTheArticle": "Go to the Article",
"Contribute": "Contribute",
"OverallProgress": "Overall Progress",
"Done": "Done",
"Open": "Open",
"Closed": "Closed",
"LatestQuestionOnThe": "Latest Question on the",
"Stackoverflow": "Stackoverflow",
"Votes": "votes",
"Answer": "Answer",
"Views": "views",
"Answered": "Answered",
"WaitingForYourAnswer": "Waiting for your answer",
"Asked": "asked",
"AllQuestions": "All Questions",
"NextVersion": "Next Version",
"MilestoneErrorMessage": "Couldn't get the current milestone details from Github.",
"QuestionItemErrorMessage": "Couldn't get the latest question details from Stackoverflow.",
"Oops": "Oops!",
"CreateArticleSuccessMessage": "The Article has been successfully submitted. It will be published once it has been reviewed by the site admin.",
"ChooseCoverImage": "Choose a cover image...",
"CoverImage": "Cover Image",
"ShareYourExperiencesWithTheABPFramework": "Share your experiences with the ABP Framework!",
"Optional": "Optional",
"UpdateUserWebSiteInfo": "Example: https://johndoe.com",
"UpdateUserTwitterInfo": "Example: johndoe",
"UpdateUserGithubInfo": "Example: johndoe",
"UpdateUserLinkedinInfo": "Example: https://www.linkedin.com/...",
"UpdateUserCompanyInfo": "Example: Volosoft",
"UpdateUserJobTitleInfo": "Example: Software Developer",
"UserName": "UserName",
"Company": "Company",
"PersonalWebsite": "Personal website",
"RegistrationDate": "Registration date",
"Social": "Social",
"Biography": "Biography",
"HasNoPublishedArticlesYet": "has no published articles yet",
"Author": "Author",
"LatestGithubAnnouncements": "Latest GitHub Announcements",
"SeeAllAnnouncements": "View all Announcements",
"LatestBlogPost": "Latest Blog Post",
"Edit": "Edit",
"ProfileImageChange": "Change the profile image",
"BlogItemErrorMessage": "Couldn't get the latest blog post details from ABP.",
"PlannedReleaseDate": "Planned release date",
"CommunityArticleRequestErrorMessage": "Couldn't get the latest article request from GitHub.",
"ArticleRequestFromGithubIssue": "There aren't any article requests at the moment.",
"LatestArticles": "Latest Articles",
"ArticleRequests": "Article Requests",
"AllArticleRequests": "See all Article requests",
"SubscribeToTheNewsletter": "Subscribe to the Newsletter",
"NewsletterEmailDefinition": "Receive information about what's happening in ABP; new releases, free sources, articles, and more.",
"NoThanks": "No thanks",
"MaybeLater": "Maybe later",
"JoinOurArticleNewsletter": "Join our article newsletter",
"Community": "Community",
"Marketing": "Marketing",
"CommunityPrivacyPolicyConfirmation": "I agree to the Terms & Conditions and <a href=\"https://commercial.abp.io/Privacy\">Privacy Policy</a>.",
"ArticleRequestMessageTitle": "<a href=\"https://github.com/abpframework/abp/issues/new\">Open an issue</a> on the GitHub to request an article/tutorial you want to see on this web site.",
"ArticleRequestMessageBody": "Here is the list of the requested articles by the Community. Do you want to write a requested article? Please click on the request and join the discussion.",
"Language": "Language",
"CreateArticleLanguageInfo": "The language in which the article is written"
}
}

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

@ -37,7 +37,7 @@
"CreateArticleTitleInfo": "Title of the article to be shown on the article list.",
"CreateArticleUrlInfo": "Original GitHub/External URL of the article.",
"CreateArticleSummaryInfo": "A short summary of the article to be shown on the article list.",
"CreateArticleCoverInfo": "For creating an effective article, add a cover photo. Upload 16:9 aspect ratio pictures for the best view.",
"CreateArticleCoverInfo": "For creating an effective article, add a cover photo. Upload 16:9 aspect ratio pictures for the best view. Maximum file size: 1MB.",
"ThisExtensionIsNotAllowed": "This extension is not allowed.",
"TheFileIsTooLarge": "The file is too large.",
"GoToTheArticle": "Go to the Article",

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

@ -0,0 +1,197 @@
{
"culture": "en-GB",
"texts": {
"GetStarted": "Get Started - Startup Templates",
"Create": "Create",
"NewProject": "New Project",
"DirectDownload": "Direct Download",
"ProjectName": "Project name",
"ProjectType": "Project type",
"DatabaseProvider": "Database provider",
"NTier": "N-Tier",
"IncludeUserInterface": "Include user interface",
"CreateNow": "Create now",
"TheStartupProject": "The startup project",
"Tutorial": "Tutorial",
"UsingCLI": "Using CLI",
"SeeDetails": "See Details",
"AbpShortDescription": "ABP Framework is a complete infrastructure to create modern web applications by following the software development best practices and conventions.",
"SourceCodeUpper": "SOURCE CODE",
"LatestReleaseLogs": "Latest release logs",
"Infrastructure": "Infrastructure",
"Architecture": "Architecture",
"Modular": "Modular",
"DontRepeatYourself": "Don’t Repeat Yourself",
"DeveloperFocused": "Developer Focused",
"FullStackApplicationInfrastructure": "Full stack application infrastructure.",
"DomainDrivenDesign": "Domain Driven Design",
"DomainDrivenDesignExplanation": "Designed and developed based on DDD patterns and principles. Provides a layered model for your application.",
"Authorization": "Authorisation",
"AuthorizationExplanation": "Advanced authorisation with user, role and fine-grained permission system. Built on the Microsoft Identity library.",
"MultiTenancy": "Multi-Tenancy",
"MultiTenancyExplanationShort": "SaaS applications made easy! Integrated multi-tenancy from database to UI.",
"CrossCuttingConcerns": "Cross Cutting Concerns",
"CrossCuttingConcernsExplanationShort": "Complete infrastructure for authorization, validation, exception handling, caching, audit logging, transaction management and more.",
"BuiltInBundlingMinification": "Built-In Bundling & Minification",
"BuiltInBundlingMinificationExplanation": "No need to use external tools for bundling & minification. ABP offers a simpler, dynamic, powerful, modular and built-in way!",
"VirtualFileSystem": "Virtual File System",
"VirtualFileSystemExplanation": "Embed views, scripts, styles, images... into packages/libraries and reuse them in different applications.",
"Theming": "Theming",
"ThemingExplanationShort": "Use and customise the bootstrap-based standard UI theme or create your own.",
"BootstrapTagHelpersDynamicForms": "Bootstrap Tag Helpers & Dynamic Forms",
"BootstrapTagHelpersDynamicFormsExplanation": "Instead of manually writing bootstrap components, Use ABP's tag helpers to simplify and take advantage of intellisense. Quickly build UI forms based on a C# model using the dynamic form tag helper.",
"HTTPAPIsDynamicProxies": "HTTP APIs & Dynamic Proxies",
"HTTPAPIsDynamicProxiesExplanation": "Automatically expose application services as REST style HTTP APIs, and consume them with dynamic JavaScript and C# proxies.",
"CompleteArchitectureInfo": "Modern architecture to create maintainable software solutions.",
"DomainDrivenDesignBasedLayeringModelExplanation": "Helps you to implement a DDD based layered architecture and build a maintainable code base.",
"DomainDrivenDesignBasedLayeringModelExplanationCont": "Provides startup templates, abstractions, base classes, services, documentation and guides to help you to develop your application based on DDD patterns & principles.",
"MicroserviceCompatibleModelExplanation": "The core framework & pre-build modules are designed with microservice architecture in mind.",
"MicroserviceCompatibleModelExplanationCont": "Provides infrastructure, integrations, samples and documentation to implement microservice solutions easier, while it doesn’t bring additional complexity if you want a monolithic application.",
"ModularInfo": "ABP provides a module system that allows you to develop reusable application modules, tie into application lifecycle events, and express dependencies between core parts of your system.",
"PreBuiltModulesThemes": "Pre-Built Modules & Themes",
"PreBuiltModulesThemesExplanation": "Open source and commercial modules & themes are ready to use in your business application.",
"NuGetNPMPackages": "NuGet & NPM Packages",
"NuGetNPMPackagesExplanation": "Distributed as NuGet & NPM packages. Easy to install and upgrade.",
"ExtensibleReplaceable": "Extensible/Replaceable",
"ExtensibleReplaceableExplanation": "All services & modules are designed extensibility in mind. You can replace services, pages, styles and components.",
"CrossCuttingConcernsExplanation2": "Keep your codebase smaller so you can maintain focus on the code that’s specific to your business.",
"CrossCuttingConcernsExplanation3": "Don’t spend time implementing common application requirements on multiple projects.",
"AuthenticationAuthorization": "Authentication & Authorization",
"ExceptionHandling": "Exception Handling",
"Validation": "Validation",
"DatabaseConnection": "Database Connection",
"TransactionManagement": "Transaction management",
"AuditLogging": "Audit Logging",
"Caching": "Caching",
"Multitenancy": "Multitenancy",
"DataFiltering": "Data filtering",
"ConventionOverConfiguration": "Convention Over Configuration",
"ConventionOverConfigurationExplanation": "ABP implements common application conventions by default with a minimal or zero configuration.",
"ConventionOverConfigurationExplanationList1": "Auto registers known services to dependency injection.",
"ConventionOverConfigurationExplanationList2": "Exposes application services as HTTP APIs by naming conventions.",
"ConventionOverConfigurationExplanationList3": "Creates dynamic HTTP client proxies for C# and JavaScript.",
"ConventionOverConfigurationExplanationList4": "Provides default repositories for your entities.",
"ConventionOverConfigurationExplanationList5": "Manages Unit of Work per web request or application service method.",
"ConventionOverConfigurationExplanationList6": "Publishes create, update & delete events for your entities.",
"BaseClasses": "Base Classes",
"BaseClassesExplanation": "Pre-built base classes for common application patterns.",
"DeveloperFocusedExplanation": "ABP is for developers.",
"DeveloperFocusedExplanationCont": "It aims to simplify your daily software development while not restricting you from writing low level code.",
"SeeAllFeatures": "See All Features",
"CLI_CommandLineInterface": "CLI (Command Line Interface)",
"CLI_CommandLineInterfaceExplanation": "Includes a CLI to help you automate the creation of new projects and the addition of new modules.",
"StartupTemplates": "Startup Templates",
"StartupTemplatesExplanation": "Various startup templates provide a fully configured solution to jump start your development.",
"BasedOnFamiliarTools": "Based on Familiar Tools",
"BasedOnFamiliarToolsExplanation": "Built and integrated with popular tools you already know. Low learning curve, easy adaptation, comfortable development.",
"ORMIndependent": "ORM Independent",
"ORMIndependentExplanation": "The core framework is ORM/database independent and can work with any data source. Entity Framework Core and MongoDB providers are already available.",
"Features": "Explore the ABP Framework Features",
"ABPCLI": "ABP CLI",
"Modularity": "Modularity",
"BootstrapTagHelpers": "Bootstrap Tag Helpers",
"DynamicForms": "Dynamic Forms",
"BundlingMinification": "Bundling & Minification",
"BackgroundJobs": "Background Jobs",
"BackgroundJobsExplanation": "Define simple classes to execute jobs in the background as queued. Use the built-in job manager or integrate your own. <a href=\"{0}\">Hangfire</a> & <a href=\"{1}\">RabbitMQ</a> integrations are already available.",
"DDDInfrastructure": "DDD Infrastructure",
"DomainDrivenDesignInfrastructure": "Domain Driven Design Infrastructure",
"AutoRESTAPIs": "Auto REST APIs",
"DynamicClientProxies": "Dynamic Client Proxies",
"DistributedEventBus": "Distributed Event Bus",
"DistributedEventBusWithRabbitMQIntegration": "Distributed Event Bus with RabbitMQ Integration",
"TestInfrastructure": "Test Infrastructure",
"AuditLoggingEntityHistories": "Audit Logging & Entity Histories",
"ObjectToObjectMapping": "Object to Object Mapping",
"ObjectToObjectMappingExplanation": "<a href=\"{0}\">Object to object mapping</a> abstraction with AutoMapper integration.",
"EmailSMSAbstractions": "Email & SMS Abstractions",
"EmailSMSAbstractionsWithTemplatingSupport": "Email & SMS Abstractions with Templating Support",
"Localization": "Localization",
"SettingManagement": "Setting Management",
"ExtensionMethods": "Extension Methods",
"ExtensionMethodsHelpers": "Extension Methods & Helpers",
"AspectOrientedProgramming": "Aspect Oriented Programming",
"DependencyInjection": "Dependency Injection",
"DependencyInjectionByConventions": "Dependency Injection by Conventions",
"ABPCLIExplanation": "The ABP CLI (Command Line Interface) is a command line tool to perform common operations for ABP based solutions.",
"ModularityExplanation": "ABP provides a complete infrastructure to build your own application modules those may have entities, services, database integration, APIs, UI components and so on.",
"MultiTenancyExplanation": "ABP framework not only supports to develop multi-tenant applications, but also makes your code mostly unaware of the multi-tenancy.",
"MultiTenancyExplanation2": "Can automatically determine the current Tenant and isolate each Tenant's data from each other.",
"MultiTenancyExplanation3": "Supports single database, database per tenant and hybrid approaches.",
"MultiTenancyExplanation4": "You focus on your business code and let the framework to handle multi-tenancy on behalf of you.",
"BootstrapTagHelpersExplanation": "Instead of manually writing the repeating details of bootstrap components, use ABP's tag helpers to simplify and take advantage of intellisense. You can use Bootstrap whenever you need it.",
"DynamicFormsExplanation": "Dynamic form & input tag helpers can create the complete form from a C# class as the model.",
"AuthenticationAuthorizationExplanation": "Rich authentication & authorization options integrated to ASP.NET Core Identity & IdentityServer4. Provides an extensible & detailed permission system.",
"CrossCuttingConcernsExplanation": "Don't repeat yourself when implementing common features. Instead, focus on your business logic and let ABP automate by convention.",
"DatabaseConnectionTransactionManagement": "Database Connection & Transaction Management",
"CorrelationIdTracking": "Correlation-Id Tracking",
"BundlingMinificationExplanation": "ABP offers a simple, dynamic, powerful, modular and built-in bundling & minification system.",
"VirtualFileSystemnExplanation": "The Virtual File System makes it possible to manage files those do not physically exist on the file system (disk). It's mainly used to embed (js, css, image, cshtml...) files into assemblies and use them like physical files on runtime.",
"ThemingExplanation": "Theming system allows to develop your application & modules theme independent by defining a set of common base libraries and layouts, based on the latest Bootstrap framework.",
"DomainDrivenDesignInfrastructureExplanation": "A complete infrastructure to build layered applications based on the Domain Driven Design patterns & principles.",
"Specification": "Specification",
"Repository": "Repository",
"DomainService": "Domain Service",
"ValueObject": "Value Object",
"ApplicationService": "Application Service",
"DataTransferObject": "Data Transfer Object",
"AggregateRootEntity": "Aggregate Root, Entity",
"AutoRESTAPIsExplanation": "ABP can automagically configure your application services as API Controllers by convention.",
"DynamicClientProxiesExplanation": "Easily consume your APIs from JavaScript and C# clients.",
"DistributedEventBusWithRabbitMQIntegrationExplanation": "Easily publish & consume distributed events using built-in Distributed Event Bus with RabbitMQ integration available.",
"TestInfrastructureExplanation": "The framework has been developed unit & integration testing in mind. Provides you base classes to make it easier. Startup templates come with pre-configured for testing.",
"AuditLoggingEntityHistoriesExplanation": "Built-in audit logging for business-critical applications. Request, service, method level audit logging and entity histories with property-level details.",
"EmailSMSAbstractionsWithTemplatingSupportExplanation": "IEmailSender and ISmsSender abstractions decouples your application logic from the infrastructure. Advanced email template system allows to create & localize email templates and easily use whenever needed.",
"LocalizationExplanation": "Localization system allows to create resources in plain JSON files and use them to localize your UI. It supports advanced scenarios like inheritance, extensions and JavaScript integration while it is fully compatible with AspNet Core's localization system.",
"SettingManagementExplanation": "Define settings for your application and get values on runtime based on the current configuration, tenant and user.",
"ExtensionMethodsHelpersExplanation": "Don't repeat yourself even for trivial code parts. Extensions & helpers for standard types makes your code much cleaner and easy to write.",
"AspectOrientedProgrammingExplanation": "Provides a comfortable infrastructure to create dynamic proxies and implement Aspect Oriented Programming. Intercept any class and execute your code before & after every method execution.",
"DependencyInjectionByConventionsExplanation": "No need to register your classes to dependency injection manually. Automatically registers common service types by convention. For other type of services, you can use interfaces and attributes to make it easier and in-place.",
"DataFilteringExplanation": "Define and use data filters those are automatically applied when you query entities from database. Soft Delete & Multi-Tenant filters are provided out of the box when you implement simple interfaces.",
"PublishEvents": "Publish Events",
"HandleEvents": "Handle Events",
"AndMore": "and more...",
"Code": "Code",
"Result": "Result",
"SeeTheDocumentForMoreInformation": "See the <a href=\"{1}\">{0} document</a> for more information",
"IndexPageHeroSection": "<span class=\"first-line shine\"><strong>open source</strong></span><span class=\"second-line text-uppercase\">Web Application<br />Framework </span><span class=\"third-line shine2\"><strong>for asp.net core</strong></span>",
"UiFramework": "UI Framework",
"EmailAddress": "Email address",
"Mobile": "Mobile",
"ReactNative": "React Native",
"Strong": "Strong",
"Complete": "Complete",
"BasedLayeringModel": "Based Layering Model",
"Microservice": "Microservice",
"Compatible": "Compatible",
"MeeTTheABPCommunityInfo": "Our mission is to create an environment where developers can help each other with articles, tutorials, case studies, etc. and meet like-minded people.",
"JoinTheABPCommunityInfo": "Get involved with a vibrant community and become a contributor to the ABP Framework!",
"AllArticles": "All Articles",
"SubmitYourArticle": "Submit Your Article",
"DynamicClientProxyDocument": "See the dynamic client proxy documentations for <a href=\"{0}\">JavaScript</a> & <a href=\"{1}\">C#</a>.",
"EmailSMSAbstractionsDocument": "See the <a href=\"{0}\">emailing</a> and <a href=\"{1}\">SMS sending</a> documents for more information.",
"CreateProjectWizard": "This wizard creates a new project from the startup template which is properly configured to jump start to your project.",
"TieredOption": "Creates a tiered solution where Web and Http API layers are physically separated. If not checked, creates a layered solution which is less complex and suitable for most scenarios.",
"SeparateIdentityServerOption": "Separates server side into two applications: First one is for the identity server and the second one is for your server side HTTP API.",
"UseslatestPreVersion": "Uses latest pre-release version",
"ReadTheDocumentation": "<span class=\"text-primary\">Read</span><span class=\"text-success\">The Documentation</span>",
"Documentation": "Documentation",
"GettingStartedTutorial": "Getting Started Tutorial",
"ApplicationDevelopmentTutorial": "Application Development Tutorial",
"TheStartupTemplate": "The Startup Template",
"InstallABPCLIInfo": "ABP CLI is the fastest way to start a new solution with the ABP framework. Install the ABP CLI using a command line window:",
"DifferentLevelOfNamespaces": "You can use different level of namespaces; e.g. BookStore, Acme.BookStore or Acme.Retail.BookStore.",
"ABPCLIExamplesInfo": "<strong>new</strong> command creates a <strong>layered MVC application</strong> with <strong>Entity Framework Core</strong> as the database provider. However, it has additional options. Examples:",
"SeeCliDocumentForMoreInformation": "See the <a href=\"{0}\">ABP CLI document</a> for more options or select the \"Direct Download\" tab above.",
"Optional": "Optional",
"LocalFrameworkRef": "Keep local project reference for the framework packages.",
"BlobStoring": "BLOB Storing",
"BlobStoringExplanation": "BLOB Storing system provides an abstraction to work with BLOBs. ABP provides some pre-built storage provider integrations (Azure, AWS, File System, Database, etc.) that you can easily use in your applications.",
"TextTemplating": "Text Templating",
"TextTemplatingExplanation": "Text templating is used to dynamically render contents based on a template and a model (a data object). For example, you can use it to create dynamic email contents with a pre-built template.",
"MultipleUIOptions": "Multiple UI Options",
"MultipleDBOptions": "Multiple Database Providers",
"MultipleUIOptionsExplanation": "The core framework is designed as UI independent and can work with any type of UI system, while there are multiple pre-built and integrated options are provided out of the box.",
"MultipleDBOptionsExplanation": "The framework can work with any data source, while the following providers are officially developed and supported:"
}
}

2
common.props

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

4
docs/en/Background-Workers.md

@ -80,7 +80,7 @@ public class PassiveUserCheckerWorker : AsyncPeriodicBackgroundWorkerBase
## Register Background Worker
After creating a background worker class, you should to add it to the `IBackgroundWorkerManager`. The most common place is the `OnApplicationInitialization` method of your module class:
After creating a background worker class, you should add it to the `IBackgroundWorkerManager`. The most common place is the `OnApplicationInitialization` method of your module class:
````csharp
[DependsOn(typeof(AbpBackgroundWorkersModule))]
@ -137,4 +137,4 @@ ABP Framework's background worker system is good to implement periodic tasks. Ho
## See Also
* [Quartz Integration for the background workers](Background-Workers-Quartz.md)
* [Background Jobs](Background-Jobs.md)
* [Background Jobs](Background-Jobs.md)

2
docs/en/Blob-Storing-Aliyun.md

@ -55,7 +55,7 @@ Configure<AbpBlobStoringOptions>(options =>
* **RoleSessionName** ([NotNull]string): Used to identify the temporary access credentials, it is recommended to use different application users to distinguish.
* **Policy** (string): Additional permission restrictions. See the [document](https://help.aliyun.com/document_detail/100680.html) for details.
* **DurationSeconds** (int): Validity period(s) of a temporary access certificate,minimum is 900 and the maximum is 3600.
* **ContainerName** (string): You can specify the container name in Aliyun. If this is not specified, it uses the name of the BLOB container defined with the `BlogContainerName` attribute (see the [BLOB storing document](Blob-Storing.md)). Please note that Aliyun has some **rules for naming containers**. A container name must be a valid DNS name, conforming to the [following naming rules](https://help.aliyun.com/knowledge_detail/39668.html):
* **ContainerName** (string): You can specify the container name in Aliyun. If this is not specified, it uses the name of the BLOB container defined with the `BlobContainerName` attribute (see the [BLOB storing document](Blob-Storing.md)). Please note that Aliyun has some **rules for naming containers**. A container name must be a valid DNS name, conforming to the [following naming rules](https://help.aliyun.com/knowledge_detail/39668.html):
* Container names must start or end with a letter or number, and can contain only letters, numbers, and the dash (-) character.
* Container names Must start and end with lowercase letters and numbers.
* Container names must be from **3** through **63** characters long.

2
docs/en/Blob-Storing-Aws.md

@ -60,7 +60,7 @@ Configure<AbpBlobStoringOptions>(options =>
* **Region** (string): The system name of the service.
* **Policy** (string): An IAM policy in JSON format that you want to use as an inline session policy.
* **DurationSeconds** (int): Validity period(s) of a temporary access certificate,minimum is 900 and the maximum is 3600. **note**: Using subaccounts operated OSS,if the value is 0.
* **ContainerName** (string): You can specify the container name in Aws. If this is not specified, it uses the name of the BLOB container defined with the `BlogContainerName` attribute (see the [BLOB storing document](Blob-Storing.md)). Please note that Aws has some **rules for naming containers**. A container name must be a valid DNS name, conforming to the [following naming rules](https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html):
* **ContainerName** (string): You can specify the container name in Aws. If this is not specified, it uses the name of the BLOB container defined with the `BlobContainerName` attribute (see the [BLOB storing document](Blob-Storing.md)). Please note that Aws has some **rules for naming containers**. A container name must be a valid DNS name, conforming to the [following naming rules](https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html):
* Bucket names must be between **3** and **63** characters long.
* Bucket names can consist only of **lowercase** letters, numbers, dots (.), and hyphens (-).
* Bucket names must begin and end with a letter or number.

2
docs/en/Blob-Storing-Azure.md

@ -40,7 +40,7 @@ Configure<AbpBlobStoringOptions>(options =>
### Options
* **ConnectionString** (string): A connection string includes the authorization information required for your application to access data in an Azure Storage account at runtime using Shared Key authorization. Please refer to Azure documentation: https://docs.microsoft.com/en-us/azure/storage/common/storage-configure-connection-string
* **ContainerName** (string): You can specify the container name in azure. If this is not specified, it uses the name of the BLOB container defined with the `BlogContainerName` attribute (see the [BLOB storing document](Blob-Storing.md)). Please note that Azure has some **rules for naming containers**. A container name must be a valid DNS name, conforming to the [following naming rules](https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names):
* **ContainerName** (string): You can specify the container name in azure. If this is not specified, it uses the name of the BLOB container defined with the `BlobContainerName` attribute (see the [BLOB storing document](Blob-Storing.md)). Please note that Azure has some **rules for naming containers**. A container name must be a valid DNS name, conforming to the [following naming rules](https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names):
* Container names must start or end with a letter or number, and can contain only letters, numbers, and the dash (-) character.
* Every dash (-) character must be immediately preceded and followed by a letter or number; consecutive dashes are not permitted in container names.
* All letters in a container name must be **lowercase**.

2
docs/en/Blob-Storing-Minio.md

@ -43,7 +43,7 @@ Configure<AbpBlobStoringOptions>(options =>
* **EndPoint** (string): URL to object storage service. Please refer to MinIO Client SDK for .NET: https://docs.min.io/docs/dotnet-client-quickstart-guide.html
* **AccessKey** (string): Access key is the user ID that uniquely identifies your account.
* **SecretKey** (string): Secret key is the password to your account.
* **BucketName** (string): You can specify the bucket name in MinIO. If this is not specified, it uses the name of the BLOB container defined with the `BlogContainerName` attribute (see the [BLOB storing document](Blob-Storing.md)).MinIO is the defacto standard for S3 compatibility, So MinIO has some **rules for naming bucket**. The [following rules](https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html) apply for naming MinIO buckets:
* **BucketName** (string): You can specify the bucket name in MinIO. If this is not specified, it uses the name of the BLOB container defined with the `BlobContainerName` attribute (see the [BLOB storing document](Blob-Storing.md)).MinIO is the defacto standard for S3 compatibility, So MinIO has some **rules for naming bucket**. The [following rules](https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html) apply for naming MinIO buckets:
* Bucket names must be between **3** and **63** characters long.
* Bucket names can consist only of **lowercase** letters, numbers, dots (.), and hyphens (-).
* Bucket names must begin and end with a letter or number.

2
docs/en/Blob-Storing.md

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

51
docs/en/Blog-Posts/2021-01-07 v4_1_Release_Stable/POST.md

@ -0,0 +1,51 @@
# ABP.IO Platform 4.1 Final Has Been Released!
[ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) 4.1 versions have been released today.
## What's New With 4.1?
Since all the new features are already explained in details with the [4.1 RC Announcement Post](https://blog.abp.io/abp/ABP.IO-Platform-v4.1-RC-Has-Been-Released), I will not repeat all the details again. See the [RC Blog Post](https://blog.abp.io/abp/ABP.IO-Platform-v4.1-RC-Has-Been-Released) for all the features and enhancements.
## Creating New Solutions
You can create a new solution with the ABP Framework version 4.1 by either using the `abp new` command or using the **direct download** tab on the [get started page](https://abp.io/get-started).
> See the [getting started document](https://docs.abp.io/en/abp/latest/Getting-Started) for details.
## How to Upgrade an Existing Solution
### Install/Update the ABP CLI
First of all, install the ABP CLI or upgrade to the latest version.
If you haven't installed yet:
```bash
dotnet tool install -g Volo.Abp.Cli
```
To update an existing installation:
```bash
dotnet tool update -g Volo.Abp.Cli
```
### ABP UPDATE Command
[ABP CLI](https://docs.abp.io/en/abp/latest/CLI) provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:
```bash
abp update
```
Run this command in the root folder of your solution.
## ABP Community
We started to get more contributions by the community for the [ABP Community](https://community.abp.io/) contents. Thank you all!
We will be adding **Video Content** sharing system in a short time. We are planning to create short video contents, especially to explore the new features in every release. Again, we will be waiting video contributions by the community :)
## About the Next Versions
Planned preview date for the version **4.2 is January 14, 2021**. See the [Road Map](https://docs.abp.io/en/abp/latest/Road-Map) document and [GitHub Milestones](https://github.com/abpframework/abp/milestones) to learn what's planned for the next versions. We are trying to be clear about the coming features and the next release dates.

8
docs/en/CLI.md

@ -105,7 +105,13 @@ abp new Acme.BookStore
* `--preview`: Use latest preview version.
* `--template-source` or `-ts`: Specifies a custom template source to use to build the project. Local and network sources can be used(Like `D:\local-template` or `https://.../my-template-file.zip`).
* `--create-solution-folder` or `-csf`: Specifies if the project will be in a new folder in the output folder or directly the output folder.
* `--connection-string` or `-cs`: Overwrites the default connection strings in all `appsettings.json` files. The default connection string is `Server=localhost;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true` for EF Core and it is configured to use the SQL Server. If you want to use the EF Core, but need to change the DBMS, you can change it as [described here](Entity-Framework-Core-Other-DBMS.md) (after creating the solution).
* `--connection-string` or `-cs`: Overwrites the default connection strings in all `appsettings.json` files. The default connection string is `Server=localhost;Database=MyProjectName;Trusted_Connection=True` for EF Core and it is configured to use the SQL Server. If you want to use the EF Core, but need to change the DBMS, you can change it as [described here](Entity-Framework-Core-Other-DBMS.md) (after creating the solution).
* `--database-management-system` or `-dbms`: Sets the database management system. Default is **SQL Server**. Supported DBMS's:
* `SqlServer`
* `MySQL`
* `SQLite`
* `Oracle-Devart`
* `PostgreSQL`
* `--local-framework-ref --abp-path`: Uses local projects references to the ABP framework instead of using the NuGet packages. This can be useful if you download the ABP Framework source code and have a local reference to the framework from your application.
* `--no-random-port`: Uses template's default ports.

5
docs/en/Community-Articles/2020-12-10-How-to-Integrate-the-Telerik-Blazor-Component/POST.md

@ -52,7 +52,10 @@ abp new TelerikComponents --ui blazor --database-provider ef
```html
...
<link rel="stylesheet" href="https:unpkg.com/@progress/kendo-theme-default@latest/dist/all.css" />
<link rel="stylesheet" href="_content/Telerik.UI.for.Blazor/css/kendo-theme-default/all.css" />
<!-- For Trial licenses use
<link rel="stylesheet" href="_content/Telerik.UI.for.Blazor.Trial/css/kendo-theme-default/all.css" />
-->
<script src="_content/Telerik.UI.for.Blazor/js/telerik-blazor.js" defer></script>
<!-- For Trial licenses use
<script src="_content/Telerik.UI.for.Blazor.Trial/js/telerik-blazor.js" defer></script>

2
docs/en/Contribution/Index.md

@ -10,7 +10,7 @@ If you want to write **articles** or **how to guides** related to the ABP Framew
You can always send pull requests to the GitHub repository.
- Clone the [ABP repository](https://github.com/abpframework/abp/) from GitHub.
- [Fork](https://docs.github.com/en/free-pro-team@latest/github/getting-started-with-github/fork-a-repo) the [ABP repository](https://github.com/abpframework/abp/) from GitHub.
- Build the repository using the `/build/build-all.ps1 -f` for one time.
- Make the necessary changes, including unit/integration tests.
- Send a pull request.

4
docs/en/Emailing.md

@ -223,7 +223,7 @@ Pathes of the templates in the virtual file system are shown below:
* `/Volo/Abp/Emailing/Templates/Layout.tpl`
* `/Volo/Abp/Emailing/Templates/Message.tpl`
If you add files to the same localization in the virtual file system, your files will override them.
If you add files to the same location in the virtual file system, your files will override them.
Templates are inline localized, that means you can take the power of the [localization system](Localization.md) to make your templates multi-cultural.
@ -247,4 +247,4 @@ So, don't confuse if you don't receive emails on DEBUG mode. Emails will be sent
## See Also
* [MailKit integration for sending emails](MailKit.md)
* [MailKit integration for sending emails](MailKit.md)

10
docs/en/Entity-Framework-Core-Migrations.md

@ -586,7 +586,7 @@ First step is to change the connection string section inside all the `appsetting
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True;MultipleActiveResultSets=true"
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True"
}
````
@ -594,10 +594,10 @@ Change it as shown below:
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True;MultipleActiveResultSets=true",
"AbpPermissionManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true",
"AbpSettingManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true",
"AbpAuditLogging": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true"
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True",
"AbpPermissionManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True",
"AbpSettingManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True",
"AbpAuditLogging": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True"
}
````

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

@ -735,6 +735,47 @@ Configure<AbpDbContextOptions>(options =>
});
````
### Customize Bulk Operations
If you have better logic or using an external library for bulk operations, you can override the logic via implementing`IEfCoreBulkOperationProvider`.
- You may use example template below:
```csharp
public class MyCustomEfCoreBulkOperationProvider : IEfCoreBulkOperationProvider, ITransientDependency
{
public async Task DeleteManyAsync<TDbContext, TEntity>(IEfCoreRepository<TEntity> repository,
IEnumerable<TEntity> entities,
bool autoSave,
CancellationToken cancellationToken)
where TDbContext : IEfCoreDbContext
where TEntity : class, IEntity
{
// Your logic here.
}
public async Task InsertManyAsync<TDbContext, TEntity>(IEfCoreRepository<TEntity> repository,
IEnumerable<TEntity> entities,
bool autoSave,
CancellationToken cancellationToken)
where TDbContext : IEfCoreDbContext
where TEntity : class, IEntity
{
// Your logic here.
}
public async Task UpdateManyAsync<TDbContext, TEntity>(IEfCoreRepository<TEntity> repository,
IEnumerable<TEntity> entities,
bool autoSave,
CancellationToken cancellationToken)
where TDbContext : IEfCoreDbContext
where TEntity : class, IEntity
{
// Your logic here.
}
}
```
## See Also
* [Entities](Entities.md)

2
docs/en/Modules/Docs.md

@ -47,7 +47,7 @@ The database connection string is located in `appsettings.json` of your `Acme.My
```json
{
"ConnectionStrings": {
"Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProject;Trusted_Connection=True;MultipleActiveResultSets=true"
"Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProject;Trusted_Connection=True"
}
}
```

41
docs/en/MongoDB.md

@ -382,3 +382,44 @@ context.Services.AddMongoDbContext<OtherMongoDbContext>(options =>
```
In this example, `OtherMongoDbContext` implements `IBookStoreMongoDbContext`. This feature allows you to have multiple MongoDbContext (one per module) on development, but single MongoDbContext (implements all interfaces of all MongoDbContexts) on runtime.
### Customize Bulk Operations
If you have better logic or using an external library for bulk operations, you can override the logic via implementing `IMongoDbBulkOperationProvider`.
- You may use example template below:
```csharp
public class MyCustomMongoDbBulkOperationProvider : IMongoDbBulkOperationProvider, ITransientDependency
{
public async Task DeleteManyAsync<TEntity>(IMongoDbRepository<TEntity> repository,
IEnumerable<TEntity> entities,
IClientSessionHandle sessionHandle,
bool autoSave,
CancellationToken cancellationToken)
where TEntity : class, IEntity
{
// Your logic here.
}
public async Task InsertManyAsync<TEntity>(IMongoDbRepository<TEntity> repository,
IEnumerable<TEntity> entities,
IClientSessionHandle sessionHandle,
bool autoSave,
CancellationToken cancellationToken)
where TEntity : class, IEntity
{
// Your logic here.
}
public async Task UpdateManyAsync<TEntity>(IMongoDbRepository<TEntity> repository,
IEnumerable<TEntity> entities,
IClientSessionHandle sessionHandle,
bool autoSave,
CancellationToken cancellationToken)
where TEntity : class, IEntity
{
// Your logic here.
}
}
```

5
docs/en/Repositories.md

@ -87,6 +87,11 @@ If your entity is a soft-delete entity, you can use the `HardDeleteAsync` method
See the [Data Filtering](Data-Filtering.md) documentation for more about soft-delete.
## Bulk Operations
You can execute bulk operations with `InsertManyAsync`, `UpdateManyAsync`, `DeleteManyAsync` methods.
> **WARNING:** ConcurrencyStamp can't be checked at bulk operations!
## Custom Repositories
Default generic repositories will be sufficient for most cases. However, you may need to create a custom repository class for your entity.

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

@ -19,7 +19,7 @@ This sample aims to demonstrate a simple yet complete microservice solution;
* Has a **console application** to show the simplest way of using a service by authenticating.
* Uses [Redis](https://redis.io/) for **distributed caching**.
* Uses [RabbitMQ](https://www.rabbitmq.com/) for service-to-service **messaging**.
* Uses [Docker](https://www.docker.com/) & [Kubernates](https://kubernetes.io/) to **deploy** & run all services and applications.
* Uses [Docker](https://www.docker.com/) & [Kubernetes](https://kubernetes.io/) to **deploy** & run all services and applications.
* Uses [Elasticsearch](https://www.elastic.co/products/elasticsearch) & [Kibana](https://www.elastic.co/products/kibana) to store and visualize the logs (written using [Serilog](https://serilog.net/)).
The diagram below shows the system:
@ -842,7 +842,7 @@ It has a dedicated MongoDB database (MsDemo_Blogging) to store blog and posts. I
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True;MultipleActiveResultSets=true",
"Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True",
"Blogging": "mongodb://localhost/MsDemo_Blogging"
}
````
@ -968,8 +968,8 @@ There are two connection strings in the `appsettings.json` file:
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True;MultipleActiveResultSets=true",
"ProductManagement": "Server=localhost;Database=MsDemo_ProductManagement;Trusted_Connection=True;MultipleActiveResultSets=true"
"Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True",
"ProductManagement": "Server=localhost;Database=MsDemo_ProductManagement;Trusted_Connection=True"
}
````
@ -1416,4 +1416,4 @@ An Audit Log record has a `CorrelationId` property that can be used to track a r
### Multi-Tenancy
The solution has been configured to provide a [multi-tenant](../Multi-Tenancy.md) system, where each tenant can have their isolated users, roles, permissions and other data.
The solution has been configured to provide a [multi-tenant](../Multi-Tenancy.md) system, where each tenant can have their isolated users, roles, permissions and other data.

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

@ -20,13 +20,15 @@ namespace MyProject.Web
public class MyProjectBrandingProvider : DefaultBrandingProvider
{
public override string AppName => "Book Store";
public override string LogoUrl => "logo.png";
}
}
````
The result will be like shown below:
![branding-appname](../../images/branding-appname.png)
![bookstore-added-logo](../../images/bookstore-added-logo.png)
`IBrandingProvider` has the following properties:
@ -38,8 +40,4 @@ The result will be like shown below:
## Overriding the Branding Area
The [Basic Theme](Basic-Theme.md) doesn't implement the logos. However, you can see the [UI Customization Guide](Customization-User-Interface.md) to learn how you can replace the branding area with a custom view component.
An example screenshot with an image is used in the branding area:
![bookstore-added-logo](../../images/bookstore-added-logo.png)
You can see the [UI Customization Guide](Customization-User-Interface.md) to learn how you can replace the branding area with a custom view component.

3
docs/en/UI/Blazor/Page-Progress.md

@ -0,0 +1,3 @@
# Blazor UI: Page Progress
TODO

2
docs/zh-Hans/Blob-Storing-Aliyun.md

@ -55,7 +55,7 @@ Configure<AbpBlobStoringOptions>(options =>
* **RoleSessionName** ([NotNull]string): 用来标识临时访问凭证的名称,建议使用不同的应用程序用户来区分.
* **Policy** (string): 在扮演角色的时候额外添加的权限限制. 请参见[基于RAM Policy的权限控制](https://help.aliyun.com/document_detail/100680.html).
* **DurationSeconds** (int): 设置临时访问凭证的有效期,单位是s,最小为900,最大为3600.
* **ContainerName** (string): 你可以在aliyun中指定容器名称. 如果没有指定它将使用 `BlogContainerName` 属性定义的BLOB容器的名称(请参阅[BLOB存储文档](Blob-Storing.md)). 请注意Aliyun有一些**命名容器的规则**,容器名称必须是有效的DNS名称,[符合以下命名规则](https://help.aliyun.com/knowledge_detail/39668.html):
* **ContainerName** (string): 你可以在aliyun中指定容器名称. 如果没有指定它将使用 `BlobContainerName` 属性定义的BLOB容器的名称(请参阅[BLOB存储文档](Blob-Storing.md)). 请注意Aliyun有一些**命名容器的规则**,容器名称必须是有效的DNS名称,[符合以下命名规则](https://help.aliyun.com/knowledge_detail/39668.html):
* 只能包含小写字母,数字和短横线(-)
* 必须以小写字母和数字开头和结尾
* Bucket名称的长度限制在**3**到**63**个字符之间

2
docs/zh-Hans/Blob-Storing-Aws.md

@ -59,7 +59,7 @@ Configure<AbpBlobStoringOptions>(options =>
* **Region** (string): 服务的地区名称.
* **Policy** (string): JSON格式的IAM策略.
* **DurationSeconds** (int): 设置临时访问凭证的有效期,单位是s,最小为900,最大为129600.
* **ContainerName** (string): 你可以在Aws中指定容器名称. 如果没有指定它将使用 `BlogContainerName` 属性定义的BLOB容器的名称(请参阅[BLOB存储文档](Blob-Storing.md)). 请注意Aws有一些**命名容器的规则**,容器名称必须是有效的DNS名称,[符合以下命名规则](https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html):
* **ContainerName** (string): 你可以在Aws中指定容器名称. 如果没有指定它将使用 `BlobContainerName` 属性定义的BLOB容器的名称(请参阅[BLOB存储文档](Blob-Storing.md)). 请注意Aws有一些**命名容器的规则**,容器名称必须是有效的DNS名称,[符合以下命名规则](https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html):
* Bucket名称必须介于 3 到 63 个字符之间.
* Bucket名称只能由小写字母、数字、句点 (.) 和连字符 (-) 组成.
* Bucket名称必须以字母或数字开头和结尾.

2
docs/zh-Hans/Blob-Storing-Azure.md

@ -40,7 +40,7 @@ Configure<AbpBlobStoringOptions>(options =>
### 选项
* **ConnectionString** (string): 连接字符串包括应用程序在运行时使用共享密钥授权访问Azure存储帐户中的数据所需的授权信息. 请参考[Azure文档](https://docs.microsoft.com/en-us/azure/storage/common/storage-configure-connection-string).
* **ContainerName** (string): 你可以在azure中指定容器名称. 如果没有指定它将使用 `BlogContainerName` 属性定义的BLOB容器的名称(请参阅[BLOB存储文档](Blob-Storing.md)). 请注意Azure有一些**命名容器的规则**,容器名称必须是有效的DNS名称,[符合以下命名规则](https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names):
* **ContainerName** (string): 你可以在azure中指定容器名称. 如果没有指定它将使用 `BlobContainerName` 属性定义的BLOB容器的名称(请参阅[BLOB存储文档](Blob-Storing.md)). 请注意Azure有一些**命名容器的规则**,容器名称必须是有效的DNS名称,[符合以下命名规则](https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names):
* 容器名称必须以字母或数字开头或结尾,并且只能包含字母,数字和破折号(-)字符.
* 每个破折号(-)必须紧跟在字母或数字之后;容器名称中不允许使用连续的破折号.
* 容器名称中的所有字母都必须**小写**.

2
docs/zh-Hans/Blob-Storing-Minio.md

@ -43,7 +43,7 @@ Configure<AbpBlobStoringOptions>(options =>
* **EndPoint** (string): 你的Minio对象存储服务的URL, 查看文档:https://docs.min.io/docs/dotnet-client-quickstart-guide.html
* **AccessKey** (string): Access key是唯一标识你的账户的用户ID,
* **SecretKey** (string): Access key是唯一标识你的账户的用户ID
* **BucketName** (string):你可以指定bucket名称,如果没有指定,将使用 `BlogContainerName` 属性定义的BLOB容器的名称(查阅[BLOB storing document](Blob-Storing.md)),MinIO完全兼容S3标准,所以有一些 **bucket命名规则**,必须符合[规则](https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html):
* **BucketName** (string):你可以指定bucket名称,如果没有指定,将使用 `BlobContainerName` 属性定义的BLOB容器的名称(查阅[BLOB storing document](Blob-Storing.md)),MinIO完全兼容S3标准,所以有一些 **bucket命名规则**,必须符合[规则](https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html):
* Bucket名称必须介于 3 到 63 个字符之间.
* Bucket名称只能由小写字母、数字、句点 (.) 和连字符 (-) 组成.
* Bucket名称必须以字母或数字开头和结尾.

12
docs/zh-Hans/Blob-Storing.md

@ -10,7 +10,7 @@ ABP框架为BLOB提供了抽象,并提供了一些可以轻松集成到的预构
* 你可以**轻松的更改**BLOB存储,而不用改变你的应用程序代码.
* 如果你想创建**可重用的应用程序模块**,无需假设BLOB的存储方式.
ABP BLOG存储系统兼容ABP框架其他功能,如[多租户](Multi-Tenancy.md).
ABP BLOB存储系统兼容ABP框架其他功能,如[多租户](Multi-Tenancy.md).
## BLOB 存储提供程序
@ -18,9 +18,9 @@ ABP框架已经有以下存储提供程序的实现;
* [File System](Blob-Storing-File-System.md):将BLOB作为标准文件存储在本地文件系统的文件夹中.
* [Database](Blob-Storing-Database.md): 将BLOB存储在数据库中.
* [Azure](Blob-Storing-Azure.md): 将BLOG存储在 [Azure BLOB storage](https://azure.microsoft.com/en-us/services/storage/blobs/)中.
* [Azure](Blob-Storing-Azure.md): 将BLOB存储在 [Azure BLOB storage](https://azure.microsoft.com/en-us/services/storage/blobs/)中.
* [Aliyun](Blob-Storing-Aliyun.md): 将BLOB存储在[Aliyun Storage Service](https://help.aliyun.com/product/31815.html)中.
* [Ninio](Blob-Storing-Minio.md): 将BLOB存储在[MinIO Object storage](https://min.io/)中.
* [Minio](Blob-Storing-Minio.md): 将BLOB存储在[MinIO Object storage](https://min.io/)中.
* [Aws](Blob-Storing-Aws.md): 将BLOB存储在[Amazon Simple Storage Service](https://aws.amazon.com/s3/)中.
以后会实现更多的提供程序,你可以为自己喜欢的提供程序创建[请求](https://github.com/abpframework/abp/issues/new),或者你也可以[自己实现](Blob-Storing-Custom-Provider.md)它并[贡献](Contribution/Index.md)到ABP框架.
@ -95,9 +95,9 @@ namespace AbpDemo
### 读取/获取 BLOB
* `GetAsync`: 返回给定BLOB名称可用于读取BLOB内容的 `Stream` 对象. 使用后始终要**dispose流**. 如果找不到具有给定名称的BLOB,则抛出异常.
* `GetOrNullAsync`: 与 `GetAsync` 方法相反,如果未找到给定名称的BLOG,则返回 `null`.
* `GetOrNullAsync`: 与 `GetAsync` 方法相反,如果未找到给定名称的BLOB,则返回 `null`.
* `GetAllBytesAsync`: 返回 `byte[]` 而不是 `Stream`. 如果找不到具有给定名称的BLOB,则抛出异常.
* `GetAllBytesOrNullAsync`: 与 `GetAllBytesAsync` 方法相反,如果未找到给定名称的BLOG,则返回 `null`.
* `GetAllBytesOrNullAsync`: 与 `GetAllBytesAsync` 方法相反,如果未找到给定名称的BLOB,则返回 `null`.
### 删除 BLOB
@ -300,7 +300,7 @@ Configure<AbpBlobStoringOptions>(options =>
## BLOB 存储 vs 文件管理系统
注意BLOB存储不是一个文件管理系统. 它是一个用于保存,获取和删除命名BLOG的低级别系统. 它不提供目录那样的层次结构,这是典型文件系统所期望的.
注意BLOB存储不是一个文件管理系统. 它是一个用于保存,获取和删除命名BLOB的低级别系统. 它不提供目录那样的层次结构,这是典型文件系统所期望的.
如果你想创建文件夹并在文件夹之间移动文件,为文件分配权限并在用户之间共享文件,那么你需要在BLOB存储系统上实现你自己的应用程序.

2
docs/zh-Hans/CLI.md

@ -103,7 +103,7 @@ abp new Acme.BookStore
* `--preview`: 使用最新的预览版本.
* `--template-source` 或者 `-ts`: 指定自定义模板源用于生成项目,可以使用本地源和网络源(例如 `D:\local-templat``https://.../my-template-file.zip`).
* `--create-solution-folder` 或者 `-csf`: 指定项目是在输出文件夹中的新文件夹中还是直接在输出文件夹中.
* `--connection-string` 或者 `-cs`: 重写所有 `appsettings.json` 文件的默认连接字符串. 默认连接字符串是 `Server=localhost;Database=MyProjectName;Trusted_Connection=True;MultipleActiveResultSets=true`. 默认的数据库提供程序是 `SQL Server`. 如果你使用EF Core但需要更改DBMS,可以按[这里所述](Entity-Framework-Core-Other-DBMS.md)进行更改(创建解决方案之后).
* `--connection-string` 或者 `-cs`: 重写所有 `appsettings.json` 文件的默认连接字符串. 默认连接字符串是 `Server=localhost;Database=MyProjectName;Trusted_Connection=True`. 默认的数据库提供程序是 `SQL Server`. 如果你使用EF Core但需要更改DBMS,可以按[这里所述](Entity-Framework-Core-Other-DBMS.md)进行更改(创建解决方案之后).
* `--local-framework-ref --abp-path`: 使用对项目的本地引用,而不是替换为NuGet包引用.
### update

2
docs/zh-Hans/Domain-Driven-Design-Implementation-Guide.md

@ -1920,7 +1920,7 @@ public class OrganizationAppService : ApplicationService
你可能想知道为什么付款逻辑代码不在`OrganizationManager`中.付款是非常**重要的事情**,我们不能**遗漏任何一次付款**.
它确实非常重要,但是,它不能放到领域服务中.我们可能还**其它用例**来创建组织但不收取任何费用.例如:
它确实非常重要,但是,它不能放到领域服务中.我们可能还**其它用例**来创建组织但不收取任何费用.例如:
* 管理员可以在后台管理系统创建新组织,而无需支付任何费用.
* 后台作业系统导入,集成,同步组织而无需支付费用.

10
docs/zh-Hans/Entity-Framework-Core-Migrations.md

@ -588,7 +588,7 @@ public class IdentityRoleExtendingService : ITransientDependency
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True;MultipleActiveResultSets=true"
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True"
}
````
@ -596,10 +596,10 @@ public class IdentityRoleExtendingService : ITransientDependency
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True;MultipleActiveResultSets=true",
"AbpPermissionManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true",
"AbpSettingManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true",
"AbpAuditLogging": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True;MultipleActiveResultSets=true"
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True",
"AbpPermissionManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True",
"AbpSettingManagement": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True",
"AbpAuditLogging": "Server=localhost;Database=BookStore_SecondDb;Trusted_Connection=True"
}
````

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

@ -47,7 +47,7 @@ ABP框架的[文档](docs.abp.io)也是使用的此模块.
```json
{
"ConnectionStrings": {
"Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProject;Trusted_Connection=True;MultipleActiveResultSets=true"
"Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProject;Trusted_Connection=True"
}
}
```

6
docs/zh-Hans/Samples/Microservice-Demo.md

@ -843,7 +843,7 @@ Swagger UI已配置,是此服务的默认页面. 如果你导航到URL`http://lo
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True;MultipleActiveResultSets=true",
"Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True",
"Blogging": "mongodb://localhost/MsDemo_Blogging"
}
````
@ -969,8 +969,8 @@ public class ProductServiceMigrationDbContext : AbpDbContext<ProductServiceMigra
````json
"ConnectionStrings": {
"Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True;MultipleActiveResultSets=true",
"ProductManagement": "Server=localhost;Database=MsDemo_ProductManagement;Trusted_Connection=True;MultipleActiveResultSets=true"
"Default": "Server=localhost;Database=MsDemo_Identity;Trusted_Connection=True",
"ProductManagement": "Server=localhost;Database=MsDemo_ProductManagement;Trusted_Connection=True"
}
````

37
framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs

@ -25,26 +25,29 @@ namespace Microsoft.Extensions.DependencyInjection
{
options.ClaimActions.MapAbpClaimTypes();
options.Events = new OpenIdConnectEvents
configureOptions?.Invoke(options);
options.Events ??= new OpenIdConnectEvents();
var authorizationCodeReceived = options.Events.OnAuthorizationCodeReceived ?? (_ => Task.CompletedTask);
options.Events.OnAuthorizationCodeReceived = receivedContext =>
{
OnAuthorizationCodeReceived = receivedContext =>
{
var tenantKey = receivedContext.HttpContext.RequestServices
.GetRequiredService<IOptionsSnapshot<AbpAspNetCoreMultiTenancyOptions>>().Value.TenantKey;
if (receivedContext.HttpContext.Request != null &&
receivedContext.Request.Cookies.ContainsKey(tenantKey))
{
receivedContext.TokenEndpointRequest.SetParameter(tenantKey,
receivedContext.Request.Cookies[tenantKey]);
}
return Task.CompletedTask;
}
SetAbpTenantId(receivedContext);
return authorizationCodeReceived.Invoke(receivedContext);
};
configureOptions?.Invoke(options);
});
}
private static void SetAbpTenantId(AuthorizationCodeReceivedContext receivedContext)
{
var tenantKey = receivedContext.HttpContext.RequestServices
.GetRequiredService<IOptionsSnapshot<AbpAspNetCoreMultiTenancyOptions>>().Value.TenantKey;
if (receivedContext.Request.Cookies.ContainsKey(tenantKey))
{
receivedContext.TokenEndpointRequest.SetParameter(tenantKey,
receivedContext.Request.Cookies[tenantKey]);
}
}
}
}

10
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/Branding.razor

@ -1,3 +1,9 @@
@using Volo.Abp.Ui.Branding
@using Volo.Abp.Ui.Branding
@inject IBrandingProvider BrandingProvider
<a class="navbar-brand" href="">@BrandingProvider.AppName</a>
<a class="navbar-brand" href="">
@if (!BrandingProvider.LogoUrl.IsNullOrWhiteSpace())
{
<img src="@BrandingProvider.LogoUrl" alt="@BrandingProvider.AppName" >
}
@BrandingProvider.AppName
</a>

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor

@ -10,7 +10,7 @@
if (MenuItem.Url != null)
{
<li class="nav-item @cssClass @disabled" id="@elementId">
<a class="nav-link" href="@url">
<a class="nav-link" href="@url" target="@MenuItem.Target">
@if (MenuItem.Icon != null)
{
if (MenuItem.Icon.StartsWith("fa"))

16
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor

@ -3,6 +3,7 @@
@using Volo.Abp.MultiTenancy
@inject ICurrentUser CurrentUser
@inject ICurrentTenant CurrentTenant
@inject IJSRuntime JsRuntime
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager
<AuthorizeView>
@ -23,7 +24,7 @@
{
@foreach (var menuItem in Menu.Items)
{
<DropdownItem Clicked="@(() => NavigateTo(menuItem.Url))">@menuItem.DisplayName</DropdownItem>
<DropdownItem Clicked="@(() => NavigateToAsync(menuItem.Url, menuItem.Target))">@menuItem.DisplayName</DropdownItem>
}
}
<DropdownDivider />
@ -37,14 +38,21 @@
</AuthorizeView>
@code{
private void NavigateTo(string uri)
private async Task NavigateToAsync(string uri, string target = null)
{
Navigation.NavigateTo(uri);
if (target == "_blank")
{
await JsRuntime.InvokeVoidAsync("open", uri, target);
}
else
{
Navigation.NavigateTo(uri);
}
}
private async Task BeginSignOut()
{
await SignOutManager.SetSignOutState();
NavigateTo("authentication/logout");
await NavigateToAsync("authentication/logout");
}
}

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/SecondLevelNavMenuItem.razor

@ -9,7 +9,7 @@
{
if (MenuItem.Url != null)
{
<a class="dropdown-item @cssClass @disabled" href="@url" id="@elementId">
<a class="dropdown-item @cssClass @disabled" href="@url" target="@MenuItem.Target" id="@elementId">
@if (MenuItem.Icon != null)
{
if (MenuItem.Icon.StartsWith("fa"))

9
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs

@ -4,11 +4,13 @@ using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Localization.Resources.AbpUi;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions;
@ -20,15 +22,18 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
private readonly HtmlEncoder _htmlEncoder;
private readonly IHtmlGenerator _htmlGenerator;
private readonly IServiceProvider _serviceProvider;
private readonly IStringLocalizer<AbpUiResource> _localizer;
public AbpDynamicFormTagHelperService(
HtmlEncoder htmlEncoder,
IHtmlGenerator htmlGenerator,
IServiceProvider serviceProvider)
IServiceProvider serviceProvider,
IStringLocalizer<AbpUiResource> localizer)
{
_htmlEncoder = htmlEncoder;
_htmlGenerator = htmlGenerator;
_serviceProvider = serviceProvider;
_localizer = localizer;
}
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
@ -191,7 +196,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
var abpButtonTagHelper = _serviceProvider.GetRequiredService<AbpButtonTagHelper>();
var attributes = new TagHelperAttributeList { new TagHelperAttribute("type", "submit") };
abpButtonTagHelper.Text = "Submit";
abpButtonTagHelper.Text = _localizer["Submit"];
abpButtonTagHelper.ButtonType = AbpButtonType.Primary;
return await abpButtonTagHelper.RenderAsync(attributes, context, _htmlEncoder, "button", TagMode.StartTagAndEndTag);

49
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpIdNameTagHelper.cs

@ -0,0 +1,49 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Options;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form
{
[HtmlTargetElement(Attributes = "abp-id-name")]
public class AbpIdNameTagHelper : AbpTagHelper
{
/// <summary>
/// Make sure this TagHelper is executed first.
/// </summary>
public override int Order => -1000 - 1;
[HtmlAttributeName("abp-id-name")]
public ModelExpression IdNameFor { get; set; }
private readonly MvcViewOptions _mvcViewOptions;
public AbpIdNameTagHelper(IOptions<MvcViewOptions> mvcViewOptions)
{
_mvcViewOptions = mvcViewOptions.Value;
}
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (IdNameFor != null)
{
if (!context.AllAttributes.Any(x => x.Name.Equals("id", StringComparison.OrdinalIgnoreCase)))
{
var id = TagBuilder.CreateSanitizedId(IdNameFor.Name, _mvcViewOptions.HtmlHelperOptions.IdAttributeDotReplacement);
output.Attributes.Add("id", id);
}
if (!context.AllAttributes.Any(x => x.Name.Equals("name", StringComparison.OrdinalIgnoreCase)))
{
output.Attributes.Add("name", IdNameFor.Name);
}
}
return Task.CompletedTask;
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Pagination/PagerModel.cs

@ -69,7 +69,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination
}
/// <summary>
/// Gets first two, previous & current & next, last two pages
/// Gets first two, previous, current, next, last two pages
/// </summary>
private List<PageItem> GetPagesWithGaps()
{

12
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo/Abp/AspNetCore/Mvc/UI/MultiTenancy/Localization/en-GB.json

@ -0,0 +1,12 @@
{
"culture": "en-GB",
"texts": {
"GivenTenantIsNotAvailable": "Given tenant is not available: {0}",
"Tenant": "Tenant",
"Switch": "switch",
"Name": "Name",
"SwitchTenantHint": "Leave the name field blank to switch to the host side.",
"SwitchTenant": "Switch tenant",
"NotSelected": "Not selected"
}
}

8
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml

@ -1,3 +1,9 @@
@using Volo.Abp.Ui.Branding
@inject IBrandingProvider BrandingProvider
<a class="navbar-brand" href="~/">@BrandingProvider.AppName</a>
<a class="navbar-brand" href="~/">
@if (!BrandingProvider.LogoUrl.IsNullOrWhiteSpace())
{
<img src="@BrandingProvider.LogoUrl" alt="@BrandingProvider.AppName" >
}
@BrandingProvider.AppName
</a>

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js

@ -55,7 +55,8 @@ $.validator.defaults.ignore = ''; //TODO: Would be better if we can apply only f
function _createContainer() {
_removeContainer();
_$modalContainer = $('<div id="' + _modalId + 'Container' + '"></div>').appendTo('body');
_$modalContainer = $('<div id="' + _modalId + 'Container' + '"></div>');
$('body').prepend(_$modalContainer);
return _$modalContainer;
}

41
framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs

@ -16,6 +16,7 @@ using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Settings;
using Volo.Abp.Timing;
using Volo.Abp.UI.Navigation.Urls;
using Volo.Abp.Uow;
using Volo.Abp.Users;
@ -125,6 +126,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.RazorPages
protected ILogger Logger => _lazyLogger.Value;
private Lazy<ILogger> _lazyLogger => new Lazy<ILogger>(() => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance, true);
protected IAppUrlProvider AppUrlProvider => LazyGetRequiredService(ref _appUrlProvider);
private IAppUrlProvider _appUrlProvider;
protected virtual NoContentResult NoContent() //TODO: Is that true to return empty result like that?
{
return new NoContentResult();
@ -165,5 +169,42 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.RazorPages
return localizer;
}
protected RedirectResult RedirectSafely(string returnUrl, string returnUrlHash = null)
{
return Redirect(GetRedirectUrl(returnUrl, returnUrlHash));
}
protected virtual string GetRedirectUrl(string returnUrl, string returnUrlHash = null)
{
returnUrl = NormalizeReturnUrl(returnUrl);
if (!returnUrlHash.IsNullOrWhiteSpace())
{
returnUrl = returnUrl + returnUrlHash;
}
return returnUrl;
}
private string NormalizeReturnUrl(string returnUrl)
{
if (returnUrl.IsNullOrEmpty())
{
return GetAppHomeUrl();
}
if (Url.IsLocalUrl(returnUrl) || AppUrlProvider.IsRedirectAllowedUrl(returnUrl))
{
return returnUrl;
}
return GetAppHomeUrl();
}
protected virtual string GetAppHomeUrl()
{
return "~/"; //TODO: ???
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj

@ -23,7 +23,7 @@
<ProjectReference Include="..\Volo.Abp.AspNetCore\Volo.Abp.AspNetCore.csproj" />
<ProjectReference Include="..\Volo.Abp.GlobalFeatures\Volo.Abp.GlobalFeatures.csproj" />
<ProjectReference Include="..\Volo.Abp.Localization\Volo.Abp.Localization.csproj" />
<ProjectReference Include="..\Volo.Abp.UI\Volo.Abp.UI.csproj" />
<ProjectReference Include="..\Volo.Abp.UI.Navigation\Volo.Abp.UI.Navigation.csproj" />
</ItemGroup>
<ItemGroup>

3
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs

@ -39,6 +39,7 @@ using Volo.Abp.Json;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.UI;
using Volo.Abp.UI.Navigation;
namespace Volo.Abp.AspNetCore.Mvc
{
@ -47,7 +48,7 @@ namespace Volo.Abp.AspNetCore.Mvc
typeof(AbpLocalizationModule),
typeof(AbpApiVersioningAbstractionsModule),
typeof(AbpAspNetCoreMvcContractsModule),
typeof(AbpUiModule),
typeof(AbpUiNavigationModule),
typeof(AbpGlobalFeaturesModule)
)]
public class AbpAspNetCoreMvcModule : AbpModule

41
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpController.cs

@ -14,6 +14,7 @@ using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Timing;
using Volo.Abp.UI.Navigation.Urls;
using Volo.Abp.Uow;
using Volo.Abp.Users;
@ -115,6 +116,9 @@ namespace Volo.Abp.AspNetCore.Mvc
}
private IStringLocalizer _localizer;
protected IAppUrlProvider AppUrlProvider => LazyGetRequiredService(ref _appUrlProvider);
private IAppUrlProvider _appUrlProvider;
protected Type LocalizationResource
{
get => _localizationResource;
@ -148,5 +152,42 @@ namespace Volo.Abp.AspNetCore.Mvc
return localizer;
}
protected RedirectResult RedirectSafely(string returnUrl, string returnUrlHash = null)
{
return Redirect(GetRedirectUrl(returnUrl, returnUrlHash));
}
private string GetRedirectUrl(string returnUrl, string returnUrlHash = null)
{
returnUrl = NormalizeReturnUrl(returnUrl);
if (!returnUrlHash.IsNullOrWhiteSpace())
{
returnUrl = returnUrl + returnUrlHash;
}
return returnUrl;
}
private string NormalizeReturnUrl(string returnUrl)
{
if (returnUrl.IsNullOrEmpty())
{
return GetAppHomeUrl();
}
if (Url.IsLocalUrl(returnUrl) || AppUrlProvider.IsRedirectAllowedUrl(returnUrl))
{
return returnUrl;
}
return GetAppHomeUrl();
}
protected virtual string GetAppHomeUrl()
{
return "~/";
}
}
}

37
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Authentication/ChallengeAccountController.cs

@ -66,42 +66,5 @@ namespace Volo.Abp.AspNetCore.Mvc.Authentication
return NoContent();
}
protected RedirectResult RedirectSafely(string returnUrl, string returnUrlHash = null)
{
return Redirect(GetRedirectUrl(returnUrl, returnUrlHash));
}
private string GetRedirectUrl(string returnUrl, string returnUrlHash = null)
{
returnUrl = NormalizeReturnUrl(returnUrl);
if (!returnUrlHash.IsNullOrWhiteSpace())
{
returnUrl = returnUrl + returnUrlHash;
}
return returnUrl;
}
private string NormalizeReturnUrl(string returnUrl)
{
if (returnUrl.IsNullOrEmpty())
{
return GetAppHomeUrl();
}
if (Url.IsLocalUrl(returnUrl))
{
return returnUrl;
}
return GetAppHomeUrl();
}
protected virtual string GetAppHomeUrl()
{
return "~/";
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs

@ -46,7 +46,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow
var options = CreateOptions(context, unitOfWorkAttr);
//Trying to begin a reserved UOW by AbpUnitOfWorkMiddleware
if (_unitOfWorkManager.TryBeginReserved(AbpUnitOfWorkMiddleware.UnitOfWorkReservationName, options))
if (_unitOfWorkManager.TryBeginReserved(UnitOfWork.UnitOfWorkReservationName, options))
{
var result = await next();
if (!Succeed(result))

2
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowPageFilter.cs

@ -50,7 +50,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow
var options = CreateOptions(context, unitOfWorkAttr);
//Trying to begin a reserved UOW by AbpUnitOfWorkMiddleware
if (_unitOfWorkManager.TryBeginReserved(AbpUnitOfWorkMiddleware.UnitOfWorkReservationName, options))
if (_unitOfWorkManager.TryBeginReserved(UnitOfWork.UnitOfWorkReservationName, options))
{
var result = await next();
if (!Succeed(result))

4
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs

@ -7,8 +7,6 @@ namespace Volo.Abp.AspNetCore.Uow
{
public class AbpUnitOfWorkMiddleware : IMiddleware, ITransientDependency
{
public const string UnitOfWorkReservationName = "_AbpActionUnitOfWork";
private readonly IUnitOfWorkManager _unitOfWorkManager;
public AbpUnitOfWorkMiddleware(IUnitOfWorkManager unitOfWorkManager)
@ -18,7 +16,7 @@ namespace Volo.Abp.AspNetCore.Uow
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
using (var uow = _unitOfWorkManager.Reserve(UnitOfWorkReservationName))
using (var uow = _unitOfWorkManager.Reserve(UnitOfWork.UnitOfWorkReservationName))
{
await next(context);
await uow.CompleteAsync(context.RequestAborted);

52
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProvider.cs

@ -0,0 +1,52 @@
using System;
using System.Net.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace Volo.Abp.AspNetCore.Uow
{
public class AspNetCoreUnitOfWorkTransactionBehaviourProvider : IUnitOfWorkTransactionBehaviourProvider, ISingletonDependency
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions _options;
public virtual bool? IsTransactional
{
get
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null)
{
return null;
}
var currentUrl = httpContext.Request.Path.Value;
if (currentUrl != null)
{
foreach (var url in _options.NonTransactionalUrls)
{
if (currentUrl.StartsWith(url, StringComparison.OrdinalIgnoreCase))
{
return false;
}
}
}
return !string.Equals(
httpContext.Request.Method,
HttpMethod.Get.Method, StringComparison.OrdinalIgnoreCase
);
}
}
public AspNetCoreUnitOfWorkTransactionBehaviourProvider(
IHttpContextAccessor httpContextAccessor,
IOptions<AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions> options)
{
_httpContextAccessor = httpContextAccessor;
_options = options.Value;
}
}
}

17
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions.cs

@ -0,0 +1,17 @@
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Uow
{
public class AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions
{
public List<string> NonTransactionalUrls { get; }
public AspNetCoreUnitOfWorkTransactionBehaviourProviderOptions()
{
NonTransactionalUrls = new List<string>
{
"/connect/"
};
}
}
}

6
framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AuthorizationOptionsExtensions.cs

@ -11,9 +11,9 @@ namespace Microsoft.AspNetCore.Authorization
/// <summary>
/// Gets all policies.
///
///
/// IMPORTANT NOTE: Use this method carefully.
/// It relies on reflection to get all policies from a private field of the <see cref="options"/>.
/// It relies on reflection to get all policies from a private field of the <paramref name="options"/>.
/// This method may be removed in the future if internals of <see cref="AuthorizationOptions"/> changes.
/// </summary>
/// <param name="options"></param>
@ -23,4 +23,4 @@ namespace Microsoft.AspNetCore.Authorization
return ((IDictionary<string, AuthorizationPolicy>) PolicyMapProperty.GetValue(options)).Keys.ToList();
}
}
}
}

10
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/en-GB.json

@ -0,0 +1,10 @@
{
"culture": "en-GB",
"texts": {
"Volo.Authorization:010001": "Authorisation failed! Given policy has not granted.",
"Volo.Authorization:010002": "Authorisation failed! Given policy has not granted: {PolicyName}",
"Volo.Authorization:010003": "Authorisation failed! Given policy has not granted for given resource: {ResourceName}",
"Volo.Authorization:010004": "Authorisation failed! Given requirement has not granted for given resource: {ResourceName}",
"Volo.Authorization:010005": "Authorisation failed! Given requirements has not granted for given resource: {ResourceName}"
}
}

16
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs

@ -54,7 +54,7 @@ namespace Volo.Abp.Authorization.Permissions
///
/// Disabling a permission would be helpful to hide a related application
/// functionality from users/clients.
///
///
/// Default: true.
/// </summary>
public bool IsEnabled { get; set; }
@ -64,8 +64,8 @@ namespace Volo.Abp.Authorization.Permissions
/// </summary>
/// <param name="name">Name of the property</param>
/// <returns>
/// Returns the value in the <see cref="Properties"/> dictionary by given <see cref="name"/>.
/// Returns null if given <see cref="name"/> is not present in the <see cref="Properties"/> dictionary.
/// Returns the value in the <see cref="Properties"/> dictionary by given <paramref name="name"/>.
/// Returns null if given <paramref name="name"/> is not present in the <see cref="Properties"/> dictionary.
/// </returns>
public object this[string name]
{
@ -74,7 +74,7 @@ namespace Volo.Abp.Authorization.Permissions
}
protected internal PermissionDefinition(
[NotNull] string name,
[NotNull] string name,
ILocalizableString displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true)
@ -90,14 +90,14 @@ namespace Volo.Abp.Authorization.Permissions
}
public virtual PermissionDefinition AddChild(
[NotNull] string name,
[NotNull] string name,
ILocalizableString displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true)
{
var child = new PermissionDefinition(
name,
displayName,
name,
displayName,
multiTenancySide,
isEnabled)
{
@ -138,4 +138,4 @@ namespace Volo.Abp.Authorization.Permissions
return $"[{nameof(PermissionDefinition)} {Name}]";
}
}
}
}

10
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs

@ -36,8 +36,8 @@ namespace Volo.Abp.Authorization.Permissions
/// </summary>
/// <param name="name">Name of the property</param>
/// <returns>
/// Returns the value in the <see cref="Properties"/> dictionary by given <see cref="name"/>.
/// Returns null if given <see cref="name"/> is not present in the <see cref="Properties"/> dictionary.
/// Returns the value in the <see cref="Properties"/> dictionary by given <paramref name="name"/>.
/// Returns null if given <paramref name="name"/> is not present in the <see cref="Properties"/> dictionary.
/// </returns>
public object this[string name]
{
@ -46,7 +46,7 @@ namespace Volo.Abp.Authorization.Permissions
}
protected internal PermissionGroupDefinition(
string name,
string name,
ILocalizableString displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both)
{
@ -59,7 +59,7 @@ namespace Volo.Abp.Authorization.Permissions
}
public virtual PermissionDefinition AddPermission(
string name,
string name,
ILocalizableString displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true)
@ -131,4 +131,4 @@ namespace Volo.Abp.Authorization.Permissions
return null;
}
}
}
}

34
framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperConventionalRegistrar.cs

@ -0,0 +1,34 @@
using System;
using System.Linq;
using AutoMapper;
using AutoMapper.Internal;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AutoMapper
{
public class AbpAutoMapperConventionalRegistrar : ConventionalRegistrarBase
{
protected readonly Type[] OpenTypes = {
typeof(IValueResolver<,,>),
typeof(IMemberValueResolver<,,,>),
typeof(ITypeConverter<,>),
typeof(IValueConverter<,>),
typeof(IMappingAction<,>)
};
public override void AddType(IServiceCollection services, Type type)
{
if (IsConventionalRegistrationDisabled(type))
{
return;
}
if (type.IsClass && !type.IsAbstract && OpenTypes.Any(type.ImplementsGenericInterface))
{
services.TryAddTransient(type);
}
}
}
}

26
framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs

@ -13,24 +13,23 @@ namespace Volo.Abp.AutoMapper
typeof(AbpObjectMappingModule),
typeof(AbpObjectExtendingModule),
typeof(AbpAuditingModule)
)]
)]
public class AbpAutoMapperModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper();
var mapperAccessor = new MapperAccessor();
context.Services.AddSingleton<IMapperAccessor>(_ => mapperAccessor);
context.Services.AddSingleton<MapperAccessor>(_ => mapperAccessor);
context.Services.AddConventionalRegistrar(new AbpAutoMapperConventionalRegistrar());
}
public override void OnPreApplicationInitialization(ApplicationInitializationContext context)
public override void ConfigureServices(ServiceConfigurationContext context)
{
CreateMappings(context.ServiceProvider);
context.Services.AddAutoMapperObjectMapper();
context.Services.AddSingleton<MapperAccessor>(provider => CreateMappings(provider));
context.Services.AddSingleton<IMapperAccessor>(provider => provider.GetRequiredService<MapperAccessor>());
}
private void CreateMappings(IServiceProvider serviceProvider)
private MapperAccessor CreateMappings(IServiceProvider serviceProvider)
{
using (var scope = serviceProvider.CreateScope())
{
@ -48,7 +47,7 @@ namespace Volo.Abp.AutoMapper
{
foreach (var profileType in options.ValidatingProfiles)
{
config.AssertConfigurationIsValid(((Profile)Activator.CreateInstance(profileType)).ProfileName);
config.AssertConfigurationIsValid(((Profile) Activator.CreateInstance(profileType)).ProfileName);
}
}
@ -59,7 +58,10 @@ namespace Volo.Abp.AutoMapper
ValidateAll(mapperConfiguration);
scope.ServiceProvider.GetRequiredService<MapperAccessor>().Mapper = mapperConfiguration.CreateMapper();
return new MapperAccessor
{
Mapper = new Mapper(mapperConfiguration, serviceProvider.GetService)
};
}
}
}

140
framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacRegistration.cs

@ -1,6 +1,6 @@
// This software is part of the Autofac IoC container
// Copyright © 2015 Autofac Contributors
// http://autofac.org
// https://autofac.org
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@ -24,10 +24,13 @@
// OTHER DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Autofac.Builder;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Autofac;
using Volo.Abp;
using Volo.Abp.Modularity;
namespace Autofac.Extensions.DependencyInjection
@ -46,16 +49,62 @@ namespace Autofac.Extensions.DependencyInjection
/// The <see cref="ContainerBuilder"/> into which the registrations should be made.
/// </param>
/// <param name="services">
/// The set of service descriptors to register in the container.
/// A container builder that can be used to create an <see cref="IServiceProvider" />.
/// </param>
public static void Populate(
this ContainerBuilder builder,
IServiceCollection services)
this ContainerBuilder builder,
IServiceCollection services)
{
builder.RegisterType<AutofacServiceProvider>().As<IServiceProvider>();
builder.RegisterType<AutofacServiceScopeFactory>().As<IServiceScopeFactory>();
Populate(builder, services, null);
}
/// <summary>
/// Populates the Autofac container builder with the set of registered service descriptors
/// and makes <see cref="IServiceProvider"/> and <see cref="IServiceScopeFactory"/>
/// available in the container. Using this overload is incompatible with the ASP.NET Core
/// support for <see cref="IServiceProviderFactory{TContainerBuilder}"/>.
/// </summary>
/// <param name="builder">
/// The <see cref="ContainerBuilder"/> into which the registrations should be made.
/// </param>
/// <param name="services">
/// A container builder that can be used to create an <see cref="IServiceProvider" />.
/// </param>
/// <param name="lifetimeScopeTagForSingletons">
/// If provided and not <see langword="null"/> then all registrations with lifetime <see cref="ServiceLifetime.Singleton" /> are registered
/// using <see cref="IRegistrationBuilder{TLimit,TActivatorData,TRegistrationStyle}.InstancePerMatchingLifetimeScope" />
/// with provided <paramref name="lifetimeScopeTagForSingletons"/>
/// instead of using <see cref="IRegistrationBuilder{TLimit,TActivatorData,TRegistrationStyle}.SingleInstance"/>.
/// </param>
/// <remarks>
/// <para>
/// Specifying a <paramref name="lifetimeScopeTagForSingletons"/> addresses a specific case where you have
/// an application that uses Autofac but where you need to isolate a set of services in a child scope. For example,
/// if you have a large application that self-hosts ASP.NET Core items, you may want to isolate the ASP.NET
/// Core registrations in a child lifetime scope so they don't show up for the rest of the application.
/// This overload allows that. Note it is the developer's responsibility to execute this and create an
/// <see cref="AutofacServiceProvider"/> using the child lifetime scope.
/// </para>
/// </remarks>
public static void Populate(
this ContainerBuilder builder,
IServiceCollection services,
object lifetimeScopeTagForSingletons)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
Register(builder, services);
builder.RegisterType<AutofacServiceProvider>().As<IServiceProvider>().ExternallyOwned();
var autofacServiceScopeFactory = typeof(AutofacServiceProvider).Assembly.GetType("Autofac.Extensions.DependencyInjection.AutofacServiceScopeFactory");
if (autofacServiceScopeFactory == null)
{
throw new AbpException("Unable get type of Autofac.Extensions.DependencyInjection.AutofacServiceScopeFactory!");
}
builder.RegisterType(autofacServiceScopeFactory).As<IServiceScopeFactory>();
Register(builder, services, lifetimeScopeTagForSingletons);
}
/// <summary>
@ -65,18 +114,33 @@ namespace Autofac.Extensions.DependencyInjection
/// <typeparam name="TRegistrationStyle">The object registration style.</typeparam>
/// <param name="registrationBuilder">The registration being built.</param>
/// <param name="lifecycleKind">The lifecycle specified on the service registration.</param>
/// <param name="lifetimeScopeTagForSingleton">
/// If not <see langword="null"/> then all registrations with lifetime <see cref="ServiceLifetime.Singleton" /> are registered
/// using <see cref="IRegistrationBuilder{TLimit,TActivatorData,TRegistrationStyle}.InstancePerMatchingLifetimeScope" />
/// with provided <paramref name="lifetimeScopeTagForSingleton"/>
/// instead of using <see cref="IRegistrationBuilder{TLimit,TActivatorData,TRegistrationStyle}.SingleInstance"/>.
/// </param>
/// <returns>
/// The <paramref name="registrationBuilder" />, configured with the proper lifetime scope,
/// and available for additional configuration.
/// </returns>
private static IRegistrationBuilder<object, TActivatorData, TRegistrationStyle> ConfigureLifecycle<TActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<object, TActivatorData, TRegistrationStyle> registrationBuilder,
ServiceLifetime lifecycleKind)
this IRegistrationBuilder<object, TActivatorData, TRegistrationStyle> registrationBuilder,
ServiceLifetime lifecycleKind,
object lifetimeScopeTagForSingleton)
{
switch (lifecycleKind)
{
case ServiceLifetime.Singleton:
registrationBuilder.SingleInstance();
if (lifetimeScopeTagForSingleton == null)
{
registrationBuilder.SingleInstance();
}
else
{
registrationBuilder.InstancePerMatchingLifetimeScope(lifetimeScopeTagForSingleton);
}
break;
case ServiceLifetime.Scoped:
registrationBuilder.InstancePerLifetimeScope();
@ -96,59 +160,67 @@ namespace Autofac.Extensions.DependencyInjection
/// The <see cref="ContainerBuilder"/> into which the registrations should be made.
/// </param>
/// <param name="services">
/// The set of service descriptors to register in the container.
/// A container builder that can be used to create an <see cref="IServiceProvider" />.
/// </param>
/// <param name="lifetimeScopeTagForSingletons">
/// If not <see langword="null"/> then all registrations with lifetime <see cref="ServiceLifetime.Singleton" /> are registered
/// using <see cref="IRegistrationBuilder{TLimit,TActivatorData,TRegistrationStyle}.InstancePerMatchingLifetimeScope" />
/// with provided <paramref name="lifetimeScopeTagForSingletons"/>
/// instead of using <see cref="IRegistrationBuilder{TLimit,TActivatorData,TRegistrationStyle}.SingleInstance"/>.
/// </param>
[SuppressMessage("CA2000", "CA2000", Justification = "Registrations created here are disposed when the built container is disposed.")]
private static void Register(
ContainerBuilder builder,
IServiceCollection services)
ContainerBuilder builder,
IServiceCollection services,
object lifetimeScopeTagForSingletons)
{
var moduleContainer = services.GetSingletonInstance<IModuleContainer>();
var registrationActionList = services.GetRegistrationActionList();
foreach (var service in services)
foreach (var descriptor in services)
{
if (service.ImplementationType != null)
if (descriptor.ImplementationType != null)
{
// Test if the an open generic type is being registered
var serviceTypeInfo = service.ServiceType.GetTypeInfo();
var serviceTypeInfo = descriptor.ServiceType.GetTypeInfo();
if (serviceTypeInfo.IsGenericTypeDefinition)
{
builder
.RegisterGeneric(service.ImplementationType)
.As(service.ServiceType)
.ConfigureLifecycle(service.Lifetime)
.RegisterGeneric(descriptor.ImplementationType)
.As(descriptor.ServiceType)
.ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons)
.FindConstructorsWith(new AbpAutofacConstructorFinder())
.ConfigureAbpConventions(moduleContainer, registrationActionList);
}
else
{
builder
.RegisterType(service.ImplementationType)
.As(service.ServiceType)
.ConfigureLifecycle(service.Lifetime)
.RegisterType(descriptor.ImplementationType)
.As(descriptor.ServiceType)
.ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons)
.FindConstructorsWith(new AbpAutofacConstructorFinder())
.ConfigureAbpConventions(moduleContainer, registrationActionList);
}
}
else if (service.ImplementationFactory != null)
else if (descriptor.ImplementationFactory != null)
{
var registration = RegistrationBuilder.ForDelegate(service.ServiceType, (context, parameters) =>
{
var serviceProvider = context.Resolve<IServiceProvider>();
return service.ImplementationFactory(serviceProvider);
})
.ConfigureLifecycle(service.Lifetime)
.CreateRegistration();
//TODO: ConfigureAbpConventions ?
var registration = RegistrationBuilder.ForDelegate(descriptor.ServiceType, (context, parameters) =>
{
var serviceProvider = context.Resolve<IServiceProvider>();
return descriptor.ImplementationFactory(serviceProvider);
})
.ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons)
.CreateRegistration();
//TODO: ConfigureAbpConventions ?
builder.RegisterComponent(registration);
}
else
{
builder
.RegisterInstance(service.ImplementationInstance)
.As(service.ServiceType)
.ConfigureLifecycle(service.Lifetime);
.RegisterInstance(descriptor.ImplementationInstance)
.As(descriptor.ServiceType)
.ConfigureLifecycle(descriptor.Lifetime, null);
}
}
}

122
framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProvider.cs

@ -1,122 +0,0 @@
// This software is part of the Autofac IoC container
// Copyright © 2015 Autofac Contributors
// https://autofac.org
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
using System;
using Microsoft.Extensions.DependencyInjection;
namespace Autofac.Extensions.DependencyInjection
{
/// <summary>
/// Autofac implementation of the ASP.NET Core <see cref="IServiceProvider"/>.
/// </summary>
/// <seealso cref="System.IServiceProvider" />
/// <seealso cref="Microsoft.Extensions.DependencyInjection.ISupportRequiredService" />
public class AutofacServiceProvider : IServiceProvider, ISupportRequiredService, IDisposable
{
private readonly ILifetimeScope _lifetimeScope;
private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="AutofacServiceProvider"/> class.
/// </summary>
/// <param name="lifetimeScope">
/// The lifetime scope from which services will be resolved.
/// </param>
public AutofacServiceProvider(ILifetimeScope lifetimeScope)
{
this._lifetimeScope = lifetimeScope;
}
/// <summary>
/// Gets service of type <paramref name="serviceType" /> from the
/// <see cref="AutofacServiceProvider" /> and requires it be present.
/// </summary>
/// <param name="serviceType">
/// An object that specifies the type of service object to get.
/// </param>
/// <returns>
/// A service object of type <paramref name="serviceType" />.
/// </returns>
/// <exception cref="Autofac.Core.Registration.ComponentNotRegisteredException">
/// Thrown if the <paramref name="serviceType" /> isn't registered with the container.
/// </exception>
/// <exception cref="Autofac.Core.DependencyResolutionException">
/// Thrown if the object can't be resolved from the container.
/// </exception>
public object GetRequiredService(Type serviceType)
{
return this._lifetimeScope.Resolve(serviceType);
}
/// <summary>
/// Gets the service object of the specified type.
/// </summary>
/// <param name="serviceType">
/// An object that specifies the type of service object to get.
/// </param>
/// <returns>
/// A service object of type <paramref name="serviceType" />; or <see langword="null" />
/// if there is no service object of type <paramref name="serviceType" />.
/// </returns>
public object GetService(Type serviceType)
{
return this._lifetimeScope.ResolveOptional(serviceType);
}
/// <summary>
/// Gets the underlying instance of <see cref="ILifetimeScope" />.
/// </summary>
public ILifetimeScope LifetimeScope => _lifetimeScope;
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
this._disposed = true;
if (disposing)
{
this._lifetimeScope.Dispose();
}
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
}
}

77
framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceProviderFactory.cs

@ -1,77 +0,0 @@
// This software is part of the Autofac IoC container
// Copyright © 2017 Autofac Contributors
// http://autofac.org
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
using System;
using Microsoft.Extensions.DependencyInjection;
namespace Autofac.Extensions.DependencyInjection
{
/// <summary>
/// A factory for creating a <see cref="ContainerBuilder"/> and an <see cref="T:System.IServiceProvider" />.
/// </summary>
public class AutofacServiceProviderFactory : IServiceProviderFactory<ContainerBuilder>
{
private readonly Action<ContainerBuilder> _configurationAction;
/// <summary>
/// Initializes a new instance of the <see cref="AutofacServiceProviderFactory"/> class.
/// </summary>
/// <param name="configurationAction">Action on a <see cref="ContainerBuilder"/> that adds component registrations to the container.</param>
public AutofacServiceProviderFactory(Action<ContainerBuilder> configurationAction = null)
{
_configurationAction = configurationAction ?? (builder => { });
}
/// <summary>
/// Creates a container builder from an <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" />.
/// </summary>
/// <param name="services">The collection of services</param>
/// <returns>A container builder that can be used to create an <see cref="T:System.IServiceProvider" />.</returns>
public ContainerBuilder CreateBuilder(IServiceCollection services)
{
var builder = new ContainerBuilder();
builder.Populate(services);
_configurationAction(builder);
return builder;
}
/// <summary>
/// Creates an <see cref="T:System.IServiceProvider" /> from the container builder.
/// </summary>
/// <param name="containerBuilder">The container builder</param>
/// <returns>An <see cref="T:System.IServiceProvider" /></returns>
public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder)
{
if (containerBuilder == null) throw new ArgumentNullException(nameof(containerBuilder));
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
}
}

67
framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceScope.cs

@ -1,67 +0,0 @@
// This software is part of the Autofac IoC container
// Copyright © 2015 Autofac Contributors
// http://autofac.org
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
using System;
using Microsoft.Extensions.DependencyInjection;
namespace Autofac.Extensions.DependencyInjection
{
/// <summary>
/// Autofac implementation of the ASP.NET Core <see cref="IServiceScope"/>.
/// </summary>
/// <seealso cref="Microsoft.Extensions.DependencyInjection.IServiceScope" />
internal class AutofacServiceScope : IServiceScope
{
private readonly ILifetimeScope _lifetimeScope;
/// <summary>
/// Initializes a new instance of the <see cref="AutofacServiceScope"/> class.
/// </summary>
/// <param name="lifetimeScope">
/// The lifetime scope from which services should be resolved for this service scope.
/// </param>
public AutofacServiceScope(ILifetimeScope lifetimeScope)
{
this._lifetimeScope = lifetimeScope;
this.ServiceProvider = this._lifetimeScope.Resolve<IServiceProvider>();
}
/// <summary>
/// Gets an <see cref="IServiceProvider" /> corresponding to this service scope.
/// </summary>
/// <value>
/// An <see cref="IServiceProvider" /> that can be used to resolve dependencies from the scope.
/// </value>
public IServiceProvider ServiceProvider { get; }
/// <summary>
/// Disposes of the lifetime scope and resolved disposable services.
/// </summary>
public void Dispose()
{
this._lifetimeScope.Dispose();
}
}
}

65
framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacServiceScopeFactory.cs

@ -1,65 +0,0 @@
// This software is part of the Autofac IoC container
// Copyright © 2015 Autofac Contributors
// http://autofac.org
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.DependencyInjection;
namespace Autofac.Extensions.DependencyInjection
{
/// <summary>
/// Autofac implementation of the ASP.NET Core <see cref="IServiceScopeFactory"/>.
/// </summary>
/// <seealso cref="Microsoft.Extensions.DependencyInjection.IServiceScopeFactory" />
[SuppressMessage("Microsoft.ApiDesignGuidelines", "CA2213", Justification = "The creator of the root service lifetime scope is responsible for disposal.")]
internal class AutofacServiceScopeFactory : IServiceScopeFactory
{
private readonly ILifetimeScope _lifetimeScope;
/// <summary>
/// Initializes a new instance of the <see cref="AutofacServiceScopeFactory"/> class.
/// </summary>
/// <param name="lifetimeScope">The lifetime scope.</param>
public AutofacServiceScopeFactory(ILifetimeScope lifetimeScope)
{
this._lifetimeScope = lifetimeScope;
}
/// <summary>
/// Creates an <see cref="IServiceScope" /> which contains an
/// <see cref="System.IServiceProvider" /> used to resolve dependencies within
/// the scope.
/// </summary>
/// <returns>
/// An <see cref="IServiceScope" /> controlling the lifetime of the scope. Once
/// this is disposed, any scoped services that have been resolved
/// from the <see cref="IServiceScope.ServiceProvider" />
/// will also be disposed.
/// </returns>
public IServiceScope CreateScope()
{
return new AutofacServiceScope(this._lifetimeScope.BeginLifetimeScope());
}
}
}

4
framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj

@ -15,8 +15,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Autofac.Extras.DynamicProxy" Version="6.0.0" />
<PackageReference Include="Autofac" Version="6.0.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Autofac.Extras.DynamicProxy" Version="6.0.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="$(MicrosoftPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(MicrosoftPackageVersion)" />
</ItemGroup>

4
framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IAsyncBackgroundJob.cs

@ -8,9 +8,9 @@ namespace Volo.Abp.BackgroundJobs
public interface IAsyncBackgroundJob<in TArgs>
{
/// <summary>
/// Executes the job with the <see cref="args"/>.
/// Executes the job with the <paramref name="args"/>.
/// </summary>
/// <param name="args">Job arguments.</param>
Task ExecuteAsync(TArgs args);
}
}
}

4
framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/IBackgroundJob.cs

@ -6,9 +6,9 @@
public interface IBackgroundJob<in TArgs>
{
/// <summary>
/// Executes the job with the <see cref="args"/>.
/// Executes the job with the <paramref name="args"/>.
/// </summary>
/// <param name="args">Job arguments.</param>
void Execute(TArgs args);
}
}
}

9
framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/AbpBackgroundJobsHangfireModule.cs

@ -1,4 +1,5 @@
using System;
using System.Linq;
using Hangfire;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
@ -13,6 +14,12 @@ namespace Volo.Abp.BackgroundJobs.Hangfire
)]
public class AbpBackgroundJobsHangfireModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddTransient(serviceProvider =>
serviceProvider.GetRequiredService<AbpDashboardOptionsProvider>().Get());
}
public override void OnPreApplicationInitialization(ApplicationInitializationContext context)
{
var options = context.ServiceProvider.GetRequiredService<IOptions<AbpBackgroundJobOptions>>().Value;
@ -29,4 +36,4 @@ namespace Volo.Abp.BackgroundJobs.Hangfire
return null;
}
}
}
}

26
framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/AbpDashboardOptionsProvider.cs

@ -0,0 +1,26 @@
using System.Linq;
using Hangfire;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.BackgroundJobs.Hangfire
{
public class AbpDashboardOptionsProvider : ITransientDependency
{
protected AbpBackgroundJobOptions AbpBackgroundJobOptions { get; }
public AbpDashboardOptionsProvider(IOptions<AbpBackgroundJobOptions> abpBackgroundJobOptions)
{
AbpBackgroundJobOptions = abpBackgroundJobOptions.Value;
}
public virtual DashboardOptions Get()
{
return new DashboardOptions
{
DisplayNameFunc = (dashboardContext, job) =>
AbpBackgroundJobOptions.GetJob(job.Args.First().GetType()).JobName
};
}
}
}

10
framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/AbpBackgroundWorkersQuartzModule.cs

@ -26,20 +26,20 @@ namespace Volo.Abp.BackgroundWorkers.Quartz
public override void OnPreApplicationInitialization(ApplicationInitializationContext context)
{
var options = context.ServiceProvider.GetService<IOptions<AbpBackgroundWorkerOptions>>().Value;
var options = context.ServiceProvider.GetRequiredService<IOptions<AbpBackgroundWorkerOptions>>().Value;
if (!options.IsEnabled)
{
var quartzOptions = context.ServiceProvider.GetService<IOptions<AbpQuartzOptions>>().Value;
quartzOptions.StartSchedulerFactory = scheduler => Task.CompletedTask;
var quartzOptions = context.ServiceProvider.GetRequiredService<IOptions<AbpQuartzOptions>>().Value;
quartzOptions.StartSchedulerFactory = _ => Task.CompletedTask;
}
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var quartzBackgroundWorkerOptions = context.ServiceProvider.GetService<IOptions<AbpBackgroundWorkerQuartzOptions>>().Value;
var quartzBackgroundWorkerOptions = context.ServiceProvider.GetRequiredService<IOptions<AbpBackgroundWorkerQuartzOptions>>().Value;
if (quartzBackgroundWorkerOptions.IsAutoRegisterEnabled)
{
var backgroundWorkerManager = context.ServiceProvider.GetService<IBackgroundWorkerManager>();
var backgroundWorkerManager = context.ServiceProvider.GetRequiredService<IBackgroundWorkerManager>();
var works = context.ServiceProvider.GetServices<IQuartzBackgroundWorker>().Where(x=>x.AutoRegister);
foreach (var work in works)

2
framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerAdapter.cs

@ -57,7 +57,7 @@ namespace Volo.Abp.BackgroundWorkers.Quartz
.Build();
}
public async override Task Execute(IJobExecutionContext context)
public override async Task Execute(IJobExecutionContext context)
{
var worker = (IBackgroundWorker) ServiceProvider.GetService(typeof(TWorker));
var workerContext = new PeriodicBackgroundWorkerContext(ServiceProvider);

9
framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs

@ -19,14 +19,17 @@ namespace Volo.Abp.BackgroundWorkers.Quartz
public virtual async Task StartAsync(CancellationToken cancellationToken = default)
{
await _scheduler.ResumeAll(cancellationToken);
if (_scheduler.IsStarted && _scheduler.InStandbyMode)
{
await _scheduler.Start(cancellationToken);
}
}
public virtual async Task StopAsync(CancellationToken cancellationToken = default)
{
if (!_scheduler.IsShutdown)
if (_scheduler.IsStarted && !_scheduler.InStandbyMode)
{
await _scheduler.PauseAll(cancellationToken);
await _scheduler.Standby(cancellationToken);
}
}

4
framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs

@ -439,10 +439,10 @@ namespace Volo.Abp.BlazoriseUI
}
/// <summary>
/// Calls IAuthorizationService.CheckAsync for the given <see cref="policyName"/>.
/// Calls IAuthorizationService.CheckAsync for the given <paramref name="policyName"/>.
/// Throws <see cref="AbpAuthorizationException"/> if given policy was not granted for the current user.
///
/// Does nothing if <see cref="policyName"/> is null or empty.
/// Does nothing if <paramref name="policyName"/> is null or empty.
/// </summary>
/// <param name="policyName">A policy name to check</param>
protected virtual async Task CheckPolicyAsync([CanBeNull] string policyName)

10
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs

@ -37,7 +37,7 @@ namespace Volo.Abp.BlobStoring.Aliyun
var blobName = AliyunBlobNameCalculator.Calculate(args);
var aliyunConfig = args.Configuration.GetAliyunConfiguration();
var ossClient = GetOssClient(aliyunConfig);
if (!args.OverrideExisting && BlobExistsAsync(ossClient, containerName, blobName))
if (!args.OverrideExisting && BlobExists(ossClient, containerName, blobName))
{
throw new BlobAlreadyExistsException($"Saving BLOB '{args.BlobName}' does already exists in the container '{containerName}'! Set {nameof(args.OverrideExisting)} if it should be overwritten.");
}
@ -57,7 +57,7 @@ namespace Volo.Abp.BlobStoring.Aliyun
var containerName = GetContainerName(args);
var blobName = AliyunBlobNameCalculator.Calculate(args);
var ossClient = GetOssClient(args.Configuration);
if(!BlobExistsAsync(ossClient, containerName, blobName))
if(!BlobExists(ossClient, containerName, blobName))
{
return Task.FromResult(false);
}
@ -70,7 +70,7 @@ namespace Volo.Abp.BlobStoring.Aliyun
var containerName = GetContainerName(args);
var blobName = AliyunBlobNameCalculator.Calculate(args);
var ossClient = GetOssClient(args.Configuration);
return Task.FromResult(BlobExistsAsync(ossClient, containerName, blobName));
return Task.FromResult(BlobExists(ossClient, containerName, blobName));
}
public async override Task<Stream> GetOrNullAsync(BlobProviderGetArgs args)
@ -78,7 +78,7 @@ namespace Volo.Abp.BlobStoring.Aliyun
var containerName = GetContainerName(args);
var blobName = AliyunBlobNameCalculator.Calculate(args);
var ossClient = GetOssClient(args.Configuration);
if (!BlobExistsAsync(ossClient, containerName, blobName))
if (!BlobExists(ossClient, containerName, blobName))
{
return null;
}
@ -96,7 +96,7 @@ namespace Volo.Abp.BlobStoring.Aliyun
: configuration.ContainerName;
}
private bool BlobExistsAsync(IOss ossClient,string containerName, string blobName)
private bool BlobExists(IOss ossClient,string containerName, string blobName)
{
// Make sure Blob Container exists.
return ossClient.DoesBucketExist(containerName) &&

2
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs

@ -81,7 +81,7 @@ namespace Volo.Abp.BlobStoring.Aliyun
/// </summary>
public string ContainerName
{
get => _containerConfiguration.GetConfiguration<string>(AliyunBlobProviderConfigurationNames.ContainerName);
get => _containerConfiguration.GetConfigurationOrDefault<string>(AliyunBlobProviderConfigurationNames.ContainerName);
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.ContainerName, Check.NotNullOrWhiteSpace(value, nameof(value)));
}

2
framework/src/Volo.Abp.BlobStoring.Aws/Volo/Abp/BlobStoring/Aws/AwsBlobProviderConfiguration.cs

@ -81,7 +81,7 @@ namespace Volo.Abp.BlobStoring.Aws
/// </summary>
public string ContainerName
{
get => _containerConfiguration.GetConfiguration<string>(AwsBlobProviderConfigurationNames.ContainerName);
get => _containerConfiguration.GetConfigurationOrDefault<string>(AwsBlobProviderConfigurationNames.ContainerName);
set => _containerConfiguration.SetConfiguration(AwsBlobProviderConfigurationNames.ContainerName, Check.NotNullOrWhiteSpace(value, nameof(value)));
}

2
framework/src/Volo.Abp.BlobStoring.Azure/Volo/Abp/BlobStoring/Azure/AzureBlobProviderConfiguration.cs

@ -16,7 +16,7 @@
/// </summary>
public string ContainerName
{
get => _containerConfiguration.GetConfiguration<string>(AzureBlobProviderConfigurationNames.ContainerName);
get => _containerConfiguration.GetConfigurationOrDefault<string>(AzureBlobProviderConfigurationNames.ContainerName);
set => _containerConfiguration.SetConfiguration(AzureBlobProviderConfigurationNames.ContainerName, Check.NotNullOrWhiteSpace(value, nameof(value)));
}

4
framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProviderConfiguration.cs

@ -4,7 +4,7 @@
{
public string BucketName
{
get => _containerConfiguration.GetConfiguration<string>(MinioBlobProviderConfigurationNames.BucketName);
get => _containerConfiguration.GetConfigurationOrDefault<string>(MinioBlobProviderConfigurationNames.BucketName);
set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.BucketName, Check.NotNullOrWhiteSpace(value, nameof(value)));
}
@ -42,7 +42,7 @@
{
get => _containerConfiguration.GetConfigurationOrDefault(MinioBlobProviderConfigurationNames.WithSSL, false);
set => _containerConfiguration.SetConfiguration(MinioBlobProviderConfigurationNames.WithSSL, value);
}
}
/// <summary>
///Default value: false.

3
framework/src/Volo.Abp.BlobStoring/Volo/Abp/BlobStoring/BlobContainerFactoryExtensions.cs

@ -6,7 +6,6 @@
/// Gets a named container.
/// </summary>
/// <param name="blobContainerFactory">The blob container manager</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>
/// The container object.
/// </returns>
@ -19,4 +18,4 @@
);
}
}
}
}

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

@ -40,6 +40,7 @@ namespace Volo.Abp.Cli
options.Commands["translate"] = typeof(TranslateCommand);
options.Commands["build"] = typeof(BuildCommand);
options.Commands["bundle"] = typeof(BundleCommand);
options.Commands["create-migration-and-run-migrator"] = typeof(CreateMigrationAndRunMigrator);
});
}
}

61
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigrator.cs

@ -0,0 +1,61 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.Commands
{
public class CreateMigrationAndRunMigrator : IConsoleCommand, ITransientDependency
{
public virtual async Task ExecuteAsync(CommandLineArgs commandLineArgs)
{
if (commandLineArgs.Target.IsNullOrEmpty())
{
throw new CliUsageException(
"DbMigrations folder path is missing!"
);
}
var dbMigratorProjectPath = GetDbMigratorProjectPath(commandLineArgs.Target);
if (dbMigratorProjectPath == null)
{
throw new Exception("DbMigrator is not found!");
}
var output = CmdHelper.RunCmdAndGetOutput("cd \"" + commandLineArgs.Target + "\" && dotnet ef migrations add Initial -s " + dbMigratorProjectPath);
if (output.Contains("Done.") && output.Contains("To undo this action") && output.Contains("ef migrations remove")) // Migration added successfully
{
CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(dbMigratorProjectPath) + "\" && dotnet run");
}
}
private string GetDbMigratorProjectPath(string dbMigrationsFolderPath)
{
var srcFolder = Directory.GetParent(dbMigrationsFolderPath);
var dbMigratorFolderPath = Directory.GetDirectories(srcFolder.FullName).FirstOrDefault(d => d.EndsWith(".DbMigrator"));
if (dbMigratorFolderPath == null)
{
return null;
}
return Directory.GetFiles(dbMigratorFolderPath).FirstOrDefault(f => f.EndsWith(".csproj"));
}
public string GetUsageInfo()
{
return string.Empty;
}
public string GetShortDescription()
{
return string.Empty;
}
}
}

106
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs

@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
@ -16,6 +17,7 @@ using Volo.Abp.Cli.ProjectBuilding;
using Volo.Abp.Cli.ProjectBuilding.Building;
using Volo.Abp.Cli.ProjectBuilding.Templates.App;
using Volo.Abp.Cli.ProjectBuilding.Templates.Console;
using Volo.Abp.Cli.ProjectModification;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
@ -24,14 +26,17 @@ namespace Volo.Abp.Cli.Commands
{
public class NewCommand : IConsoleCommand, ITransientDependency
{
private readonly EfCoreMigrationManager _efCoreMigrationManager;
public ILogger<NewCommand> Logger { get; set; }
protected TemplateProjectBuilder TemplateProjectBuilder { get; }
public ITemplateInfoProvider TemplateInfoProvider { get; }
public NewCommand(TemplateProjectBuilder templateProjectBuilder
, ITemplateInfoProvider templateInfoProvider)
, ITemplateInfoProvider templateInfoProvider,
EfCoreMigrationManager efCoreMigrationManager)
{
_efCoreMigrationManager = efCoreMigrationManager;
TemplateProjectBuilder = templateProjectBuilder;
TemplateInfoProvider = templateInfoProvider;
@ -84,18 +89,24 @@ namespace Volo.Abp.Cli.Commands
Logger.LogInformation("Database provider: " + databaseProvider);
}
var uiFramework = GetUiFramework(commandLineArgs);
if (uiFramework != UiFramework.NotSpecified)
{
Logger.LogInformation("UI Framework: " + uiFramework);
}
var connectionString = GetConnectionString(commandLineArgs);
if (connectionString != null)
{
Logger.LogInformation("Connection string: " + connectionString);
}
var databaseManagementSystem = GetDatabaseManagementSystem(commandLineArgs);
if (databaseManagementSystem != DatabaseManagementSystem.NotSpecified)
{
Logger.LogInformation("DBMS: " + databaseManagementSystem);
}
var uiFramework = GetUiFramework(commandLineArgs);
if (uiFramework != UiFramework.NotSpecified)
{
Logger.LogInformation("UI Framework: " + uiFramework);
}
var mobileApp = GetMobilePreference(commandLineArgs);
if (mobileApp != MobileApp.None)
{
@ -139,6 +150,13 @@ namespace Volo.Abp.Cli.Commands
Logger.LogInformation("Output folder: " + outputFolder);
if (connectionString == null &&
databaseManagementSystem != DatabaseManagementSystem.NotSpecified &&
databaseManagementSystem != DatabaseManagementSystem.SQLServer)
{
connectionString = GetNewConnectionStringByDbms(databaseManagementSystem, outputFolder);
}
commandLineArgs.Options.Add(CliConsts.Command, commandLineArgs.Command);
var result = await TemplateProjectBuilder.BuildAsync(
@ -147,6 +165,7 @@ namespace Volo.Abp.Cli.Commands
template,
version,
databaseProvider,
databaseManagementSystem,
uiFramework,
mobileApp,
gitHubAbpLocalRepositoryPath,
@ -196,6 +215,8 @@ namespace Volo.Abp.Cli.Commands
}
}
DeleteMigrationsIfNeeded(databaseProvider, databaseManagementSystem, outputFolder);
Logger.LogInformation($"'{projectName}' has been successfully created to '{outputFolder}'");
if (AppTemplateBase.IsAppTemplate(template ?? (await TemplateInfoProvider.GetDefaultAsync()).Name))
@ -205,6 +226,41 @@ namespace Volo.Abp.Cli.Commands
}
}
private string GetNewConnectionStringByDbms(DatabaseManagementSystem databaseManagementSystem, string outputFolder)
{
switch (databaseManagementSystem)
{
case DatabaseManagementSystem.MySQL:
return "Server=localhost;Port=3306;Database=MyProjectName;Uid=root;Pwd=myPassword;";
case DatabaseManagementSystem.PostgreSQL:
return "User ID=root;Password=myPassword;Host=localhost;Port=5432;Database=MyProjectName;Pooling=true;Min Pool Size=0;Max Pool Size=100;Connection Lifetime=0;";
//case DatabaseManagementSystem.Oracle:
case DatabaseManagementSystem.OracleDevart:
return "Data Source=MyProjectName;Integrated Security=yes;";
case DatabaseManagementSystem.SQLite:
return $"Data Source={Path.Combine(outputFolder,"database\\MyProjectName.db")};Version=3;";
default:
return null;
}
}
private void DeleteMigrationsIfNeeded(DatabaseProvider databaseProvider, DatabaseManagementSystem databaseManagementSystem, string outputFolder)
{
if (databaseManagementSystem == DatabaseManagementSystem.NotSpecified || databaseManagementSystem == DatabaseManagementSystem.SQLServer)
{
return;
}
if (databaseProvider != DatabaseProvider.NotSpecified && databaseProvider != DatabaseProvider.EntityFrameworkCore)
{
return;
}
Logger.LogInformation($"Deleting migrations...");
_efCoreMigrationManager.RemoveAllMigrations(outputFolder);
}
private void OpenThanksPage(UiFramework uiFramework, DatabaseProvider databaseProvider, bool tiered, bool commercial)
{
uiFramework = uiFramework == UiFramework.NotSpecified || uiFramework == UiFramework.None ? UiFramework.Mvc : uiFramework;
@ -268,6 +324,7 @@ namespace Volo.Abp.Cli.Commands
sb.AppendLine("-ts|--template-source <template-source> (your local or network abp template source)");
sb.AppendLine("-csf|--create-solution-folder (default: true)");
sb.AppendLine("-cs|--connection-string <connection-string> (your database connection string)");
sb.AppendLine("--dbms <database-management-system> (your database management system)");
sb.AppendLine("--tiered (if supported by the template)");
sb.AppendLine("--no-ui (if supported by the template)");
sb.AppendLine("--no-random-port (Use template's default ports)");
@ -290,6 +347,7 @@ namespace Volo.Abp.Cli.Commands
sb.AppendLine(" abp new Acme.BookStore -ts \"D:\\localTemplate\\abp\"");
sb.AppendLine(" abp new Acme.BookStore -csf false");
sb.AppendLine(" abp new Acme.BookStore --local-framework-ref --abp-path \"D:\\github\\abp\"");
sb.AppendLine(" abp new Acme.BookStore --dbms mysql");
sb.AppendLine(" abp new Acme.BookStore --connection-string \"Server=myServerName\\myInstanceName;Database=myDatabase;User Id=myUsername;Password=myPassword\"");
sb.AppendLine("");
sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI");
@ -316,6 +374,34 @@ namespace Volo.Abp.Cli.Commands
}
}
protected virtual DatabaseManagementSystem GetDatabaseManagementSystem(CommandLineArgs commandLineArgs)
{
var optionValue = commandLineArgs.Options.GetOrNull(Options.DatabaseManagementSystem.Short, Options.DatabaseManagementSystem.Long);
if (optionValue == null)
{
return DatabaseManagementSystem.NotSpecified;
}
switch (optionValue.ToLowerInvariant())
{
case "sqlserver":
return DatabaseManagementSystem.SQLServer;
case "mysql":
return DatabaseManagementSystem.MySQL;
case "postgresql":
return DatabaseManagementSystem.PostgreSQL;
case "oracle-devart":
return DatabaseManagementSystem.OracleDevart;
case "sqlite":
return DatabaseManagementSystem.SQLite;
case "oracle": // Currently disabled. See https://github.com/abpframework/abp/issues/6513
// return DatabaseManagementSystem.Oracle;
default:
return DatabaseManagementSystem.NotSpecified;
}
}
protected virtual UiFramework GetUiFramework(CommandLineArgs commandLineArgs)
{
var optionValue = commandLineArgs.Options.GetOrNull(Options.UiFramework.Short, Options.UiFramework.Long);
@ -363,6 +449,12 @@ namespace Volo.Abp.Cli.Commands
public const string Long = "database-provider";
}
public static class DatabaseManagementSystem
{
public const string Short = "dbms";
public const string Long = "database-management-system";
}
public static class OutputFolder
{
public const string Short = "o";

1
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs

@ -37,6 +37,7 @@ namespace Volo.Abp.Cli.Commands.Services
moduleName,
version,
DatabaseProvider.NotSpecified,
DatabaseManagementSystem.NotSpecified,
UiFramework.NotSpecified,
null,
gitHubAbpLocalRepositoryPath,

13
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/DatabaseManagementSystem.cs

@ -0,0 +1,13 @@
namespace Volo.Abp.Cli.ProjectBuilding.Building
{
public enum DatabaseManagementSystem
{
NotSpecified,
SQLServer,
MySQL,
PostgreSQL,
Oracle,
OracleDevart,
SQLite
}
}

97
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs

@ -0,0 +1,97 @@
using System;
using System.Linq;
using Volo.Abp.Cli.ProjectBuilding.Files;
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps
{
public class DatabaseManagementSystemChangeStep : ProjectBuildPipelineStep
{
public override void Execute(ProjectBuildContext context)
{
switch (context.BuildArgs.DatabaseManagementSystem)
{
case DatabaseManagementSystem.MySQL:
ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.MySQL",
"Volo.Abp.EntityFrameworkCore.MySQL",
"AbpEntityFrameworkCoreMySQLModule");
AddMySqlServerVersion(context);
ChangeUseSqlServer(context,"UseMySQL", "UseMySql");
break;
case DatabaseManagementSystem.PostgreSQL:
ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.PostgreSql",
"Volo.Abp.EntityFrameworkCore.PostgreSql",
"AbpEntityFrameworkCorePostgreSqlModule");
ChangeUseSqlServer(context,"UseNpgsql");
break;
case DatabaseManagementSystem.Oracle:
ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.Oracle",
"Volo.Abp.EntityFrameworkCore.Oracle",
"AbpEntityFrameworkCoreOracleModule");
ChangeUseSqlServer(context,"UseOracle");
break;
case DatabaseManagementSystem.OracleDevart:
ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.Oracle.Devart",
"Volo.Abp.EntityFrameworkCore.Oracle.Devart",
"AbpEntityFrameworkCoreOracleDevartModule");
AdjustOracleDbContextOptionsBuilder(context);
ChangeUseSqlServer(context,"UseOracle");
break;
case DatabaseManagementSystem.SQLite:
ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.Sqlite",
"Volo.Abp.EntityFrameworkCore.Sqlite",
"AbpEntityFrameworkCoreSqliteModule");
ChangeUseSqlServer(context,"UseSqlite");
break;
default:
return;
}
}
private void AdjustOracleDbContextOptionsBuilder(ProjectBuildContext context)
{
var dbContextFactoryFile = context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase));
dbContextFactoryFile.ReplaceText("new DbContextOptionsBuilder",
$"(DbContextOptionsBuilder<{context.BuildArgs.SolutionName.ProjectName}MigrationsDbContext>) new DbContextOptionsBuilder");
}
private void AddMySqlServerVersion(ProjectBuildContext context)
{
var dbContextFactoryFile = context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase));
dbContextFactoryFile.ReplaceText("configuration.GetConnectionString(\"Default\")",
"configuration.GetConnectionString(\"Default\"), MySqlServerVersion.LatestSupportedServerVersion");
}
private void ChangeEntityFrameworkCoreDependency(ProjectBuildContext context, string newPackageName, string newModuleNamespace, string newModuleClass)
{
var efCoreProjectFile = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCore.csproj", StringComparison.OrdinalIgnoreCase));
efCoreProjectFile.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newPackageName);
var efCoreModuleClass = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCoreModule.cs", StringComparison.OrdinalIgnoreCase));
efCoreModuleClass.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newModuleNamespace);
efCoreModuleClass.ReplaceText("AbpEntityFrameworkCoreSqlServerModule", newModuleClass);
}
private void ChangeUseSqlServer(ProjectBuildContext context, string newUseMethodForEfModule, string newUseMethodForDbContext = null)
{
if (newUseMethodForDbContext == null)
{
newUseMethodForDbContext = newUseMethodForEfModule;
}
var oldUseMethod = "UseSqlServer";
var efCoreModuleClass = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCoreModule.cs", StringComparison.OrdinalIgnoreCase));
efCoreModuleClass.ReplaceText(oldUseMethod, newUseMethodForEfModule);
var dbContextFactoryFile = context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase));
dbContextFactoryFile.ReplaceText(oldUseMethod, newUseMethodForDbContext);
}
}
}

17
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs

@ -17,6 +17,12 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building
pipeline.Steps.Add(new ProjectReferenceReplaceStep());
pipeline.Steps.Add(new TemplateCodeDeleteStep());
if (context.BuildArgs.ConnectionString != null)
{
pipeline.Steps.Add(new ConnectionStringChangeStep());
}
pipeline.Steps.Add(new SolutionRenameStep());
if (context.Template.Name == AppProTemplate.TemplateName ||
@ -25,15 +31,16 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building
pipeline.Steps.Add(new LicenseCodeReplaceStep());
}
if ((context.BuildArgs.UiFramework == UiFramework.Mvc || context.BuildArgs.UiFramework == UiFramework.Blazor)
&& context.BuildArgs.MobileApp == MobileApp.None)
if (context.Template.Name == AppTemplate.TemplateName ||
context.Template.Name == AppProTemplate.TemplateName)
{
pipeline.Steps.Add(new RemoveRootFolderStep());
pipeline.Steps.Add(new DatabaseManagementSystemChangeStep());
}
if (context.BuildArgs.ConnectionString != null)
if ((context.BuildArgs.UiFramework == UiFramework.Mvc || context.BuildArgs.UiFramework == UiFramework.Blazor)
&& context.BuildArgs.MobileApp == MobileApp.None)
{
pipeline.Steps.Add(new ConnectionStringChangeStep());
pipeline.Steps.Add(new RemoveRootFolderStep());
}
pipeline.Steps.Add(new CreateProjectResultZipStep());

6
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs

@ -17,6 +17,8 @@ namespace Volo.Abp.Cli.ProjectBuilding
public DatabaseProvider DatabaseProvider { get; set; }
public DatabaseManagementSystem DatabaseManagementSystem { get; set; }
public UiFramework UiFramework { get; set; }
public MobileApp? MobileApp { get; set; }
@ -41,6 +43,7 @@ namespace Volo.Abp.Cli.ProjectBuilding
[CanBeNull] string templateName = null,
[CanBeNull] string version = null,
DatabaseProvider databaseProvider = DatabaseProvider.NotSpecified,
DatabaseManagementSystem databaseManagementSystem = DatabaseManagementSystem.NotSpecified,
UiFramework uiFramework = UiFramework.NotSpecified,
MobileApp? mobileApp = null,
[CanBeNull] string abpGitHubLocalRepositoryPath = null,
@ -53,6 +56,7 @@ namespace Volo.Abp.Cli.ProjectBuilding
TemplateName = templateName;
Version = version;
DatabaseProvider = databaseProvider;
DatabaseManagementSystem = databaseManagementSystem;
UiFramework = uiFramework;
MobileApp = mobileApp;
AbpGitHubLocalRepositoryPath = abpGitHubLocalRepositoryPath;
@ -62,4 +66,4 @@ namespace Volo.Abp.Cli.ProjectBuilding
ConnectionString = connectionString;
}
}
}
}

10
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs

@ -24,6 +24,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
SwitchDatabaseProvider(context, steps);
DeleteUnrelatedProjects(context, steps);
RemoveUnnecessaryPorts(context, steps);
RandomizeSslPorts(context, steps);
RandomizeStringEncryption(context, steps);
UpdateNuGetConfig(context, steps);
@ -102,6 +103,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
if (context.BuildArgs.ExtraProperties.ContainsKey("separate-identity-server"))
{
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.HttpApi.HostWithIds"));
steps.Add(new AppTemplateChangeDbMigratorPortSettingsStep("44300"));
}
else
{
@ -122,6 +124,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
{
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.HttpApi.HostWithIds"));
steps.Add(new BlazorAppsettingsFilePortChangeForSeparatedIdentityServersStep());
steps.Add(new AppTemplateChangeDbMigratorPortSettingsStep("44300"));
}
else
{
@ -139,6 +142,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Tests", projectFolderPath: "/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests"));
steps.Add(new AppTemplateProjectRenameStep("MyCompanyName.MyProjectName.Web.Host", "MyCompanyName.MyProjectName.Web"));
steps.Add(new AppTemplateChangeDbMigratorPortSettingsStep("44300"));
}
else
{
@ -161,6 +165,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
{
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.HttpApi.HostWithIds"));
steps.Add(new AngularEnvironmentFilePortChangeForSeparatedIdentityServersStep());
steps.Add(new AppTemplateChangeDbMigratorPortSettingsStep("44300"));
if (context.BuildArgs.MobileApp == MobileApp.ReactNative)
{
@ -176,6 +181,11 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
}
}
private static void RemoveUnnecessaryPorts(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps)
{
steps.Add(new RemoveUnnecessaryPortsStep());
}
private static void RandomizeSslPorts(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps)
{
if (context.BuildArgs.ExtraProperties.ContainsKey("no-random-port"))

24
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateChangeDbMigratorPortSettingsStep.cs

@ -0,0 +1,24 @@
using Volo.Abp.Cli.ProjectBuilding.Building;
using Volo.Abp.Cli.ProjectBuilding.Files;
namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
{
public class AppTemplateChangeDbMigratorPortSettingsStep : ProjectBuildPipelineStep
{
public string IdentityServerPort { get; }
/// <param name="identityServerPort"></param>
public AppTemplateChangeDbMigratorPortSettingsStep(
string identityServerPort)
{
IdentityServerPort = identityServerPort;
}
public override void Execute(ProjectBuildContext context)
{
context
.GetFile("/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/appsettings.json")
.ReplaceText("44305", IdentityServerPort);
}
}
}

46
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/RemoveUnnecessaryPortsStep.cs

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Volo.Abp.Cli.ProjectBuilding.Building;
namespace Volo.Abp.Cli.ProjectBuilding.Templates
{
public class RemoveUnnecessaryPortsStep : ProjectBuildPipelineStep
{
public override void Execute(ProjectBuildContext context)
{
var httpApiHostAppSettings = context.Files.FirstOrDefault(f => f.Name.EndsWith(".HttpApi.Host/appsettings.json"));
if (httpApiHostAppSettings == null)
{
return;
}
var portsToRemoveFromCors = new List<string>();
var appSettingsJson = JObject.Parse(httpApiHostAppSettings.Content);
var appJson = (JObject) appSettingsJson["App"];
if (context.BuildArgs.UiFramework != UiFramework.Angular)
{
appJson.Property("ClientUrl")?.Remove();
portsToRemoveFromCors.Add("4200");
}
if (context.BuildArgs.UiFramework != UiFramework.Blazor)
{
portsToRemoveFromCors.Add("44307");
}
if (appJson["CorsOrigins"] != null)
{
appJson["CorsOrigins"] = string.Join(",",
appJson["CorsOrigins"].ToString().Split(",").Where(u=> !portsToRemoveFromCors.Any(u.EndsWith))
);
}
httpApiHostAppSettings.SetContent(JsonConvert.SerializeObject(appSettingsJson, Formatting.Indented));
}
}
}

40
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationAdder.cs

@ -1,40 +0,0 @@
using System;
using System.IO;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.ProjectModification
{
public class EfCoreMigrationAdder : ITransientDependency
{
public void AddMigration(string dbMigrationsCsprojFile, string module, string startupProject)
{
var moduleName = ParseModuleName(module);
var migrationName = "Added_" + moduleName + "_Module" + GetUniquePostFix();
CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(dbMigrationsCsprojFile) + "\" && dotnet ef migrations add " + migrationName + GetStartupProjectOption(startupProject));
}
protected virtual string ParseModuleName(string fullModuleName)
{
var words = fullModuleName?.Split('.');
if (words == null || words.Length <= 1)
{
return "";
}
return words[words.Length - 1];
}
protected virtual string GetUniquePostFix()
{
return "_" + new Random().Next(1,99999);
}
protected virtual string GetStartupProjectOption(string startupProject)
{
return startupProject.IsNullOrWhiteSpace() ? "" : $" -s {startupProject}";
}
}
}

73
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationManager.cs

@ -0,0 +1,73 @@
using System;
using System.IO;
using System.Linq;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.ProjectModification
{
public class EfCoreMigrationManager : ITransientDependency
{
public ILogger<EfCoreMigrationManager> Logger { get; set; }
public EfCoreMigrationManager()
{
Logger = NullLogger<EfCoreMigrationManager>.Instance;
}
public void AddMigration(string dbMigrationsCsprojFile, string module, string startupProject)
{
var moduleName = ParseModuleName(module);
var migrationName = "Added_" + moduleName + "_Module" + GetUniquePostFix();
CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(dbMigrationsCsprojFile) +
"\" && dotnet ef migrations add " + migrationName +
GetStartupProjectOption(startupProject));
}
public void RemoveAllMigrations(string solutionFolder)
{
if (Directory.Exists(Path.Combine(solutionFolder, "aspnet-core")))
{
solutionFolder = Path.Combine(solutionFolder, "aspnet-core");
}
var srcFolder = Path.Combine(solutionFolder, "src");
var migrationsFolder = Directory.GetDirectories(srcFolder)
.FirstOrDefault(d => d.EndsWith(".EntityFrameworkCore.DbMigrations"));
if (migrationsFolder != null)
{
Directory.Delete(Path.Combine(migrationsFolder, "Migrations"), true);
}
else
{
Logger.LogWarning("No migration found to delete.");
}
}
protected virtual string ParseModuleName(string fullModuleName)
{
var words = fullModuleName?.Split('.');
if (words == null || words.Length <= 1)
{
return "";
}
return words[words.Length - 1];
}
protected virtual string GetUniquePostFix()
{
return "_" + new Random().Next(1, 99999);
}
protected virtual string GetStartupProjectOption(string startupProject)
{
return startupProject.IsNullOrWhiteSpace() ? "" : $" -s {startupProject}";
}
}
}

8
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs

@ -26,7 +26,7 @@ namespace Volo.Abp.Cli.ProjectModification
protected IJsonSerializer JsonSerializer { get; }
protected ProjectNugetPackageAdder ProjectNugetPackageAdder { get; }
protected DbContextFileBuilderConfigureAdder DbContextFileBuilderConfigureAdder { get; }
protected EfCoreMigrationAdder EfCoreMigrationAdder { get; }
protected EfCoreMigrationManager EfCoreMigrationManager { get; }
protected DerivedClassFinder DerivedClassFinder { get; }
protected ProjectNpmPackageAdder ProjectNpmPackageAdder { get; }
protected NpmGlobalPackagesChecker NpmGlobalPackagesChecker { get; }
@ -42,7 +42,7 @@ namespace Volo.Abp.Cli.ProjectModification
IJsonSerializer jsonSerializer,
ProjectNugetPackageAdder projectNugetPackageAdder,
DbContextFileBuilderConfigureAdder dbContextFileBuilderConfigureAdder,
EfCoreMigrationAdder efCoreMigrationAdder,
EfCoreMigrationManager efCoreMigrationManager,
DerivedClassFinder derivedClassFinder,
ProjectNpmPackageAdder projectNpmPackageAdder,
NpmGlobalPackagesChecker npmGlobalPackagesChecker,
@ -57,7 +57,7 @@ namespace Volo.Abp.Cli.ProjectModification
JsonSerializer = jsonSerializer;
ProjectNugetPackageAdder = projectNugetPackageAdder;
DbContextFileBuilderConfigureAdder = dbContextFileBuilderConfigureAdder;
EfCoreMigrationAdder = efCoreMigrationAdder;
EfCoreMigrationManager = efCoreMigrationManager;
DerivedClassFinder = derivedClassFinder;
ProjectNpmPackageAdder = projectNpmPackageAdder;
NpmGlobalPackagesChecker = npmGlobalPackagesChecker;
@ -465,7 +465,7 @@ namespace Volo.Abp.Cli.ProjectModification
{
if (addedNewBuilder)
{
EfCoreMigrationAdder.AddMigration(dbMigrationsProject, module.Name, startupProject);
EfCoreMigrationManager.AddMigration(dbMigrationsProject, module.Name, startupProject);
}
RunMigrator(projectFiles);

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

Loading…
Cancel
Save