Browse Source

Merge branch 'dev' into maliming/IdentityUser-Active

pull/9991/head
maliming 5 years ago
parent
commit
0cef35cea7
  1. 2
      .github/workflows/build-and-test.yml
  2. 6
      Directory.Build.props
  3. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/en-GB.json
  4. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/en.json
  5. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/tr.json
  6. 41
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  7. 8
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
  8. 13
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  9. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json
  10. 5
      common.props
  11. 2
      configureawait.props
  12. 22
      docs/en/Background-Jobs-Hangfire.md
  13. 29
      docs/en/Best-Practices/Entity-Framework-Core-Integration.md
  14. 26
      docs/en/Best-Practices/MongoDB-Integration.md
  15. 46
      docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/POST.md
  16. BIN
      docs/en/Community-Articles/2021-09-25-How-to-Override-Localization-Strings-Of-Depending-Modules/1.png
  17. BIN
      docs/en/Community-Articles/2021-09-25-How-to-Override-Localization-Strings-Of-Depending-Modules/2.png
  18. 88
      docs/en/Community-Articles/2021-09-25-How-to-Override-Localization-Strings-Of-Depending-Modules/POST.md
  19. 8
      docs/en/Dapper.md
  20. 9
      docs/en/Road-Map.md
  21. 5
      docs/en/Tutorials/Part-1.md
  22. 5
      docs/en/Tutorials/Part-10.md
  23. 7
      docs/en/Tutorials/Part-2.md
  24. 5
      docs/en/Tutorials/Part-3.md
  25. 5
      docs/en/Tutorials/Part-4.md
  26. 7
      docs/en/Tutorials/Part-5.md
  27. 7
      docs/en/Tutorials/Part-6.md
  28. 5
      docs/en/Tutorials/Part-7.md
  29. 5
      docs/en/Tutorials/Part-8.md
  30. 5
      docs/en/Tutorials/Part-9.md
  31. 67
      docs/en/UI/Angular/How-Replaceable-Components-Work-with-Extensions.md
  32. 276
      docs/en/UI/Angular/Permission-Management-Component-Replacement.md
  33. 6
      docs/zh-Hans/Text-Templating.md
  34. 21
      framework/Volo.Abp.sln
  35. 2
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj
  36. 2
      framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj
  37. 2
      framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo.Abp.AspNetCore.Authentication.OpenIdConnect.csproj
  38. 2
      framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Volo.Abp.AspNetCore.Components.Server.Theming.csproj
  39. 2
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj
  40. 2
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Volo.Abp.AspNetCore.Components.Web.Theming.csproj
  41. 2
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo.Abp.AspNetCore.Components.Web.csproj
  42. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.csproj
  43. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo.Abp.AspNetCore.Components.WebAssembly.csproj
  44. 2
      framework/src/Volo.Abp.AspNetCore.Components/Volo.Abp.AspNetCore.Components.csproj
  45. 2
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo.Abp.AspNetCore.MultiTenancy.csproj
  46. 1
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpMultiTenancyCookieHelper.cs
  47. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.csproj
  48. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs
  49. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj
  50. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions.csproj
  51. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj
  52. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantAppService.cs
  53. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantController.cs
  54. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs
  55. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.csproj
  56. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo.Abp.AspNetCore.Mvc.UI.Packages.csproj
  57. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/SweetAlert2/Sweetalert2ScriptContributor.cs
  58. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj
  59. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalScriptContributor.cs
  60. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj
  61. 24
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js
  62. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj
  63. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj
  64. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj
  65. 25
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs
  66. 13
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/AbpServiceConvention.cs
  67. 24
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs
  68. 24
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs
  69. 7
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Response/AbpNoContentActionFilter.cs
  70. 2
      framework/src/Volo.Abp.AspNetCore.Serilog/Volo.Abp.AspNetCore.Serilog.csproj
  71. 2
      framework/src/Volo.Abp.AspNetCore.SignalR/Volo.Abp.AspNetCore.SignalR.csproj
  72. 2
      framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj
  73. 6
      framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestProxyHttpClientFactory.cs
  74. 17
      framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Http/AbpHttpRequestExtensions.cs
  75. 1
      framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestCultureCookieHelper.cs
  76. 2
      framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj
  77. 7
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs
  78. 45
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs
  79. 67
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs
  80. 11
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IAbpAuthorizationExceptionHandler.cs
  81. 3
      framework/src/Volo.Abp.Auditing.Contracts/FodyWeavers.xml
  82. 30
      framework/src/Volo.Abp.Auditing.Contracts/FodyWeavers.xsd
  83. 21
      framework/src/Volo.Abp.Auditing.Contracts/Volo.Abp.Auditing.Contracts.csproj
  84. 9
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/AbpAuditingContractsModule.cs
  85. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/AuditedAttribute.cs
  86. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/DisableAuditingAttribute.cs
  87. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/EntityChangeType.cs
  88. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IAuditedObject.cs
  89. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IAuditingEnabled.cs
  90. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/ICreationAuditedObject.cs
  91. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IDeletionAuditedObject.cs
  92. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IFullAuditedObject.cs
  93. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasCreationTime.cs
  94. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasDeletionTime.cs
  95. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasModificationTime.cs
  96. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IMayHaveCreator.cs
  97. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IModificationAuditedObject.cs
  98. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IMustHaveCreator.cs
  99. 1
      framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj
  100. 3
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs

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

@ -21,7 +21,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-dotnet@master - uses: actions/setup-dotnet@master
with: with:
dotnet-version: 5.0.201 dotnet-version: 6.0.100-rc.1.21458.32
- name: Build All - name: Build All
run: .\build-all.ps1 run: .\build-all.ps1

6
Directory.Build.props

@ -2,10 +2,10 @@
<PropertyGroup> <PropertyGroup>
<!-- All Microsoft packages --> <!-- All Microsoft packages -->
<MicrosoftPackageVersion>5.0.*</MicrosoftPackageVersion> <MicrosoftPackageVersion>6.0.0-rc.*</MicrosoftPackageVersion>
<!-- Microsoft.NET.Test.Sdk https://www.nuget.org/packages/Microsoft.NET.Test.Sdk --> <!-- Microsoft.NET.Test.Sdk https://www.nuget.org/packages/Microsoft.NET.Test.Sdk -->
<MicrosoftNETTestSdkPackageVersion>16.9.1</MicrosoftNETTestSdkPackageVersion> <MicrosoftNETTestSdkPackageVersion>16.11.0</MicrosoftNETTestSdkPackageVersion>
<!-- NSubstitute https://www.nuget.org/packages/NSubstitute --> <!-- NSubstitute https://www.nuget.org/packages/NSubstitute -->
<NSubstitutePackageVersion>4.2.2</NSubstitutePackageVersion> <NSubstitutePackageVersion>4.2.2</NSubstitutePackageVersion>
@ -23,7 +23,7 @@
<xUnitRunnerVisualstudioPackageVersion>2.4.3</xUnitRunnerVisualstudioPackageVersion> <xUnitRunnerVisualstudioPackageVersion>2.4.3</xUnitRunnerVisualstudioPackageVersion>
<!-- Mongo2Go https://www.nuget.org/packages/Mongo2Go --> <!-- Mongo2Go https://www.nuget.org/packages/Mongo2Go -->
<Mongo2GoPackageVersion>3.1.1</Mongo2GoPackageVersion> <Mongo2GoPackageVersion>3.1.3</Mongo2GoPackageVersion>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

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

@ -9,6 +9,7 @@
"OfficialBlog": "Official blog", "OfficialBlog": "Official blog",
"CommercialHomePage": "Commercial home page", "CommercialHomePage": "Commercial home page",
"CommercialSupportWebSite": "Commercial support web site", "CommercialSupportWebSite": "Commercial support web site",
"CommunityWebSite": "ABP community web site" "CommunityWebSite": "ABP community web site",
"ManageAccount": "My Account | ABP.IO"
} }
} }

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

@ -9,6 +9,7 @@
"OfficialBlog": "Official blog", "OfficialBlog": "Official blog",
"CommercialHomePage": "Commercial home page", "CommercialHomePage": "Commercial home page",
"CommercialSupportWebSite": "Commercial support web site", "CommercialSupportWebSite": "Commercial support web site",
"CommunityWebSite": "ABP community web site" "CommunityWebSite": "ABP community web site",
"ManageAccount": "My Account | ABP.IO"
} }
} }

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

@ -9,6 +9,7 @@
"OfficialBlog": "Resmi blog", "OfficialBlog": "Resmi blog",
"CommercialHomePage": "Kurumsal ana sayfa", "CommercialHomePage": "Kurumsal ana sayfa",
"CommercialSupportWebSite": "Kurumsal destek web sitesi", "CommercialSupportWebSite": "Kurumsal destek web sitesi",
"CommunityWebSite": "ABP topluluk web sitesi" "CommunityWebSite": "ABP topluluk web sitesi",
"ManageAccount": "Hesabım | ABP.IO"
} }
} }

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

@ -310,6 +310,45 @@
"DeleteInvoice" : "Delete Invoice", "DeleteInvoice" : "Delete Invoice",
"SuccessfullyDeleted": "Successfully deleted!", "SuccessfullyDeleted": "Successfully deleted!",
"PaymentStateSetTo" : "Payment state set to {0}", "PaymentStateSetTo" : "Payment state set to {0}",
"ChangeState": "Change State" "ChangeState": "Change State",
"Permission:TrialLicense" : "Trial License",
"Permission:ManageTrialLicense": "Manage Trial License",
"Menu:TrialLicenses": "Trial Licenses",
"TrialLicenses": "Trial Licenses",
"UserNameFilter": "Username",
"TrialLicenseStatusFilter": "Status",
"TrialLicenseStartDateFilter": "Start date",
"TrialLicenseEndDateFilter": "End date",
"FirsName": "First name",
"LastName": "Last name",
"Status": "Status",
"StartDate": "Start date",
"EndDate": "End date",
"CompanyName": "Company name",
"PurchasedDate": "Purchased date",
"OrganizationDetail": "Organization Detail",
"SendActivationMail": "Send Activation Mail",
"ActivationMailSentSuccessfully": "Activation mail sent successfully!",
"TrialLicenseStatus": "Trial license status",
"TrialLicenseDetail": "Trial License Detail",
"AcceptsMarketingCommunications": "Marketing Communications",
"PurposeOfUsage": "Purpose of usage",
"CountryName": "Country name",
"CompanySize": "Company size",
"DetailTrialLicense": "Details",
"Requested": "Requested",
"Activated": "Activated",
"PurchasedToNormalLicense": "Purchased",
"Expired": "Expired",
"TrialLicenseDeletionWarningMessage": "Trial license and if any organization and qa organization will be deleted!",
"IsTrial": "Is trial",
"Volo.AbpIo.Commercial:030000": "You already used your trial period.",
"Volo.AbpIo.Commercial:030001": "This organization name already exists.",
"Volo.AbpIo.Commercial:030002": "Once activated, trial license cannot be set to requested!",
"Volo.AbpIo.Commercial:030003": "There is no such status!",
"Volo.AbpIo.Commercial:030004": "Status could not be changed due to an unexpected error!",
"Volo.AbpIo.Commercial:030005": "Start date and end date cannot be given when the trial license is in the requested state!",
"Volo.AbpIo.Commercial:030006": "End date must always be greater than start date!",
"Volo.AbpIo.Commercial:030007": "This trial license has already been activated once!"
} }
} }

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

@ -35,6 +35,10 @@
"Support": "Support", "Support": "Support",
"FreeDDDBook": "Free DDD E-book", "FreeDDDBook": "Free DDD E-book",
"New": "New", "New": "New",
"Volo.AbpIo.Domain:020005": "License extend year can not be lower than {MinExtendLicenseYear} year and greater than {MaxExtendLicenseYear} years " "Volo.AbpIo.Domain:020005": "License extend year can not be lower than {MinExtendLicenseYear} year(s) and greater than {MaxExtendLicenseYear} year(s) ",
"TrialLicensePeriodHasExpired": "Your trial license period expired {0} days ago.",
"TrialLicensePeriodWillExpire": "Your trial license period will be expired in {0} days.",
"TrialLicensePeriodExpireToday": "Your trial license period will be expired today.",
"PurchaseNow": "Purchase Now!"
} }
} }

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

@ -377,6 +377,17 @@
"AddressValidationMessage": "Address is too long!", "AddressValidationMessage": "Address is too long!",
"TaxNoValidationMessage": "TAX/VAT No is too long!", "TaxNoValidationMessage": "TAX/VAT No is too long!",
"NotesValidationMessage": "Notes field is too long!", "NotesValidationMessage": "Notes field is too long!",
"CheckYourBillingInfo": "You can create your invoice only once! Check your billing information before creating your invoice." "CheckYourBillingInfo": "You can create your invoice only once! Check your billing information before creating your invoice.",
"Volo.AbpIo.Commercial:030000": "You already used your trial period.",
"Volo.AbpIo.Commercial:030001": "This organization name already exists.",
"StartYourFreeTrial": "Start your free trial",
"TrialLicenseModelInvalidErrorMessage": "One of the following fields are invalid: Country Name, Company Size, Industry or Purpose Of Usage.",
"Trial": "Trial",
"Purchased": "Purchased",
"PurchaseLicense": "Purchase License",
"PurchaseTrialLicenseMessage": "Your license expiration date is {0}. <br> If you want to continue using the projects you created during your free trial period, you need to change the license keys in your <code>appsettings.secrets.json</code> files. Here is your license key:",
"TrialLicenseExpireMessage": "You are using the trial license and your trial license will expire on {0}.",
"TryForFree": "Try For Free",
"TrialLicenseExpiredInfo": "Your trial license period has expired!"
} }
} }

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

@ -218,7 +218,7 @@
"LicenseURL": "许可URL", "LicenseURL": "许可URL",
"License": "许可", "License": "许可",
"ProjectCreationSuccessMessage": "你的项目创建成功", "ProjectCreationSuccessMessage": "你的项目创建成功",
"HowToRunSolution": "如何运行你的解决方案n?", "HowToRunSolution": "如何运行你的解决方案?",
"GettingStartedMessage": "查看入门文档了解如何配置和运行你的解决方案.", "GettingStartedMessage": "查看入门文档了解如何配置和运行你的解决方案.",
"WebAppDevTutorial": "Web App 开发教程", "WebAppDevTutorial": "Web App 开发教程",
"WebAppDevTutorialMessage": "查看web应用程序开发教程文档,一步一步的开发示例.", "WebAppDevTutorialMessage": "查看web应用程序开发教程文档,一步一步的开发示例.",
@ -231,4 +231,4 @@
"DatabaseProviderDocumentationMessage": "查看{0}文档来学习用数据库层开发.", "DatabaseProviderDocumentationMessage": "查看{0}文档来学习用数据库层开发.",
"ABPCommercialExplanationMessage": "ABP商业版为ABP框架提供了高级模块,主题,工具和支持." "ABPCommercialExplanationMessage": "ABP商业版为ABP框架提供了高级模块,主题,工具和支持."
} }
} }

5
common.props

@ -28,4 +28,9 @@
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup Condition="$(AssemblyName.EndsWith('HttpApi.Client'))">
<EmbeddedResource Include="**\*generate-proxy.json" />
<Content Remove="**\*generate-proxy.json" />
</ItemGroup>
</Project> </Project>

2
configureawait.props

@ -1,7 +1,7 @@
<Project> <Project>
<ItemGroup> <ItemGroup>
<PackageReference Include="ConfigureAwait.Fody" Version="3.3.1" PrivateAssets="All" /> <PackageReference Include="ConfigureAwait.Fody" Version="3.3.1" PrivateAssets="All" />
<PackageReference Include="Fody" Version="6.5.0"> <PackageReference Include="Fody" Version="6.5.3">
<PrivateAssets>All</PrivateAssets> <PrivateAssets>All</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>

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

@ -88,17 +88,21 @@ To make it secure by default, only local requests are allowed, however you can c
You can integrate the Hangfire dashboard to [ABP authorization system](Authorization.md) using the **AbpHangfireAuthorizationFilter** You can integrate the Hangfire dashboard to [ABP authorization system](Authorization.md) using the **AbpHangfireAuthorizationFilter**
class. This class is defined in the `Volo.Abp.Hangfire` package. The following example, checks if the current user is logged in to the application: class. This class is defined in the `Volo.Abp.Hangfire` package. The following example, checks if the current user is logged in to the application:
app.UseHangfireDashboard("/hangfire", new DashboardOptions ```csharp
{ app.UseHangfireDashboard("/hangfire", new DashboardOptions
AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter() } {
}); AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter() }
});
```
If you want to require an additional permission, you can pass it into the constructor as below: If you want to require an additional permission, you can pass it into the constructor as below:
app.UseHangfireDashboard("/hangfire", new DashboardOptions ```csharp
{ app.UseHangfireDashboard("/hangfire", new DashboardOptions
AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter("MyHangFireDashboardPermissionName") } {
}); AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter("MyHangFireDashboardPermissionName") }
});
```
**Important**: `UseHangfireDashboard` should be called after the authentication middleware in your `Startup` class (probably at the last line). Otherwise, **Important**: `UseHangfireDashboard` should be called after the authentication and authorization middlewares in your `Startup` class (probably at the last line). Otherwise,
authorization will always fail! authorization will always fail!

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

@ -66,12 +66,7 @@ public static string Schema { get; set; } = AbpIdentityConsts.DefaultDbSchema;
protected override void OnModelCreating(ModelBuilder builder) protected override void OnModelCreating(ModelBuilder builder)
{ {
base.OnModelCreating(builder); base.OnModelCreating(builder);
builder.ConfigureIdentity();
builder.ConfigureIdentity(options =>
{
options.TablePrefix = TablePrefix;
options.Schema = Schema;
});
} }
```` ````
@ -80,25 +75,20 @@ protected override void OnModelCreating(ModelBuilder builder)
````C# ````C#
public static class IdentityDbContextModelBuilderExtensions public static class IdentityDbContextModelBuilderExtensions
{ {
public static void ConfigureIdentity( public static void ConfigureIdentity([NotNull] this ModelBuilder builder)
[NotNull] this ModelBuilder builder,
Action<IdentityModelBuilderConfigurationOptions> optionsAction = null)
{ {
Check.NotNull(builder, nameof(builder)); Check.NotNull(builder, nameof(builder));
var options = new IdentityModelBuilderConfigurationOptions();
optionsAction?.Invoke(options);
builder.Entity<IdentityUser>(b => builder.Entity<IdentityUser>(b =>
{ {
b.ToTable(options.TablePrefix + "Users", options.Schema); b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "Users", AbpIdentityDbProperties.DbSchema);
b.ConfigureByConvention(); b.ConfigureByConvention();
//code omitted for brevity //code omitted for brevity
}); });
builder.Entity<IdentityUserClaim>(b => builder.Entity<IdentityUserClaim>(b =>
{ {
b.ToTable(options.TablePrefix + "UserClaims", options.Schema); b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "UserClaims", AbpIdentityDbProperties.DbSchema);
b.ConfigureByConvention(); b.ConfigureByConvention();
//code omitted for brevity //code omitted for brevity
}); });
@ -109,17 +99,6 @@ public static class IdentityDbContextModelBuilderExtensions
```` ````
* **Do** call `b.ConfigureByConvention();` for each entity mapping (as shown above). * **Do** call `b.ConfigureByConvention();` for each entity mapping (as shown above).
* **Do** create a **configuration options** class by inheriting from the `AbpModelBuilderConfigurationOptions`. Example:
````C#
public class IdentityModelBuilderConfigurationOptions : AbpModelBuilderConfigurationOptions
{
public IdentityModelBuilderConfigurationOptions()
: base(AbpIdentityConsts.DefaultDbTablePrefix, AbpIdentityConsts.DefaultDbSchema)
{
}
}
````
### Repository Implementation ### Repository Implementation

26
docs/en/Best-Practices/MongoDB-Integration.md

@ -55,10 +55,7 @@ protected override void CreateModel(IMongoModelBuilder modelBuilder)
{ {
base.CreateModel(modelBuilder); base.CreateModel(modelBuilder);
modelBuilder.ConfigureIdentity(options => modelBuilder.ConfigureIdentity();
{
options.CollectionPrefix = CollectionPrefix;
});
} }
``` ```
@ -73,36 +70,19 @@ public static class AbpIdentityMongoDbContextExtensions
{ {
Check.NotNull(builder, nameof(builder)); Check.NotNull(builder, nameof(builder));
var options = new IdentityMongoModelBuilderConfigurationOptions();
optionsAction?.Invoke(options);
builder.Entity<IdentityUser>(b => builder.Entity<IdentityUser>(b =>
{ {
b.CollectionName = options.CollectionPrefix + "Users"; b.CollectionName = AbpIdentityDbProperties.DbTablePrefix + "Users";
}); });
builder.Entity<IdentityRole>(b => builder.Entity<IdentityRole>(b =>
{ {
b.CollectionName = options.CollectionPrefix + "Roles"; b.CollectionName = AbpIdentityDbProperties.DbTablePrefix + "Roles";
}); });
} }
} }
``` ```
- **Do** create a **configuration options** class by inheriting from the `AbpMongoModelBuilderConfigurationOptions`. Example:
```c#
public class IdentityMongoModelBuilderConfigurationOptions
: AbpMongoModelBuilderConfigurationOptions
{
public IdentityMongoModelBuilderConfigurationOptions()
: base(AbpIdentityConsts.DefaultDbTablePrefix)
{
}
}
```
### Repository Implementation ### Repository Implementation
- **Do** **inherit** the repository from the `MongoDbRepository<TMongoDbContext, TEntity, TKey>` class and implement the corresponding repository interface. Example: - **Do** **inherit** the repository from the `MongoDbRepository<TMongoDbContext, TEntity, TKey>` class and implement the corresponding repository interface. Example:

46
docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/POST.md

@ -194,16 +194,11 @@ We implemented token generation infrastructure, now it's time validate the token
```csharp ```csharp
using System; using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Identity; using Volo.Abp.Identity;
using Volo.Abp.Security.Claims; using Volo.Abp.Identity.AspNetCore;
using Volo.Abp.Users;
namespace PasswordlessAuthentication.Web.Controllers namespace PasswordlessAuthentication.Web.Controllers
{ {
@ -211,9 +206,12 @@ namespace PasswordlessAuthentication.Web.Controllers
{ {
protected IdentityUserManager UserManager { get; } protected IdentityUserManager UserManager { get; }
public PasswordlessController(IdentityUserManager userManager) protected AbpSignInManager SignInManager { get; }
public PasswordlessController(IdentityUserManager userManager, AbpSignInManager signInManager)
{ {
UserManager = userManager; UserManager = userManager;
SignInManager = signInManager;
} }
public virtual async Task<IActionResult> Login(string token, string userId) public virtual async Task<IActionResult> Login(string token, string userId)
@ -228,45 +226,15 @@ namespace PasswordlessAuthentication.Web.Controllers
await UserManager.UpdateSecurityStampAsync(user); await UserManager.UpdateSecurityStampAsync(user);
var roles = await UserManager.GetRolesAsync(user); await SignInManager.SignInAsync(user, isPersistent: false);
var principal = new ClaimsPrincipal(
new ClaimsIdentity(CreateClaims(user, roles), IdentityConstants.ApplicationScheme)
);
await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, principal);
return Redirect("/"); return Redirect("/");
} }
private static IEnumerable<Claim> CreateClaims(IUser user, IEnumerable<string> roles)
{
var claims = new List<Claim>
{
new Claim("sub", user.Id.ToString()),
new Claim(AbpClaimTypes.UserId, user.Id.ToString()),
new Claim(AbpClaimTypes.Email, user.Email),
new Claim(AbpClaimTypes.UserName, user.UserName),
new Claim(AbpClaimTypes.EmailVerified, user.EmailConfirmed.ToString().ToLower()),
};
if (!string.IsNullOrWhiteSpace(user.PhoneNumber))
{
claims.Add(new Claim(AbpClaimTypes.PhoneNumber, user.PhoneNumber));
}
foreach (var role in roles)
{
claims.Add(new Claim(AbpClaimTypes.Role, role));
}
return claims;
}
} }
} }
``` ```
We created an endpoint for `/Passwordless/Login` that gets the token and the user Id. In this action, we find the user via repository and validate the token via `UserManager.VerifyUserTokenAsync()` method. If it's valid, we create claims of the user then call `HttpContext.SignInAsync` to be able to create an encrypted cookie and add it to the current response. Finally we redirect the page to the root URL. We created an endpoint for `/Passwordless/Login` that gets the token and the user Id. In this action, we find the user via repository and validate the token via `UserManager.VerifyUserTokenAsync()` method. If it's valid, we call `SignInManager.SignInAsync` to be able to create an encrypted cookie and add it to the current response. Finally we redirect the page to the root URL.
That's all! We created a passwordless login with 7 steps. That's all! We created a passwordless login with 7 steps.

BIN
docs/en/Community-Articles/2021-09-25-How-to-Override-Localization-Strings-Of-Depending-Modules/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
docs/en/Community-Articles/2021-09-25-How-to-Override-Localization-Strings-Of-Depending-Modules/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

88
docs/en/Community-Articles/2021-09-25-How-to-Override-Localization-Strings-Of-Depending-Modules/POST.md

@ -0,0 +1,88 @@
# How to override localization strings of depending modules
## Source Code
You can find the source of the example solution used in this article [here](https://github.com/abpframework/abp-samples/tree/master/DocumentationSamples/ExtendLocalizationResource).
## Getting Started
This example is based on the following document
https://docs.abp.io/en/abp/latest/Localization#extending-existing-resource
We will change the default `DisplayName:Abp.Timing.Timezone` and `Description:Abp.Timing.Timezone` of [`AbpTimingResource`](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Localization/AbpTimingResource.cs) and add localized text in [Russian language(`ru`)](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Localization/en.json).
I created the `AbpTiming` folder in the `Localization` directory of the `ExtendLocalizationResource.Domain.Shared` project.
Create `en.json` and `ru.json` in its directory.
`en.json`
```json
{
"culture": "en",
"texts": {
"DisplayName:Abp.Timing.Timezone": "My Time zone",
"Description:Abp.Timing.Timezone": "My Application time zone"
}
}
```
`ru.json`
```json
{
"culture": "ru",
"texts": {
"DisplayName:Abp.Timing.Timezone": "Часовой пояс",
"Description:Abp.Timing.Timezone": "Часовой пояс приложения"
}
}
```
![](1.png)
We have below content in `ExtendLocalizationResource.Domain.Shared.csproj` file, See [Virtual-File-System](https://docs.abp.io/en/abp/latest/Virtual-File-System#working-with-the-embedded-files) understand how it works.
```xml
<ItemGroup>
<EmbeddedResource Include="Localization\ExtendLocalizationResource\*.json" />
<Content Remove="Localization\ExtendLocalizationResource\*.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="5.0.*" />
</ItemGroup>
```
Change the code of the `ConfigureServices` method in `ExtendLocalizationResourceDomainSharedModule`.
```cs
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<ExtendLocalizationResourceResource>("en")
.AddBaseTypes(typeof(AbpValidationResource))
.AddVirtualJson("/Localization/ExtendLocalizationResource");
//add following code
options.Resources
.Get<AbpTimingResource>()
.AddVirtualJson("/Localization/AbpTiming");
options.DefaultResourceType = typeof(ExtendLocalizationResourceResource);
});
```
Execute `ExtendLocalizationResource.DbMigrator` to migrate the database and run `ExtendLocalizationResource.Web`.
We have changed the English localization text and added Russian localization.
### Index page
```cs
<p>@AbpTimingResource["DisplayName:Abp.Timing.Timezone"]</p>
@using(CultureHelper.Use("ru"))
{
<p>@AbpTimingResource["DisplayName:Abp.Timing.Timezone"]</p>
}
```
![](2.png)

8
docs/en/Dapper.md

@ -53,14 +53,16 @@ public class PersonDapperRepository : DapperRepository<MyAppDbContext>, ITransie
public virtual async Task<List<string>> GetAllPersonNames() public virtual async Task<List<string>> GetAllPersonNames()
{ {
return (await DbConnection.QueryAsync<string>("select Name from People", transaction: DbTransaction)) var dbConnection = await GetDbConnectionAsync();
return (await dbConnection.QueryAsync<string>("select Name from People", transaction: await GetDbTransactionAsync()))
.ToList(); .ToList();
} }
public virtual async Task<int> UpdatePersonNames(string name) public virtual async Task<int> UpdatePersonNames(string name)
{ {
return await DbConnection.ExecuteAsync("update People set Name = @NewName", new { NewName = name }, var dbConnection = await GetDbConnectionAsync();
DbTransaction); return await dbConnection.ExecuteAsync("update People set Name = @NewName", new { NewName = name },
await GetDbTransactionAsync());
} }
} }
``` ```

9
docs/en/Road-Map.md

@ -10,12 +10,9 @@ This version will focus on the following works:
* Upgrading to .NET 6.0 ([#9004](https://github.com/abpframework/abp/issues/9004)) * Upgrading to .NET 6.0 ([#9004](https://github.com/abpframework/abp/issues/9004))
* Upgrading to Bootstrap 5.x ([#8922](https://github.com/abpframework/abp/issues/8922)) * Upgrading to Bootstrap 5.x ([#8922](https://github.com/abpframework/abp/issues/8922))
* Alternative to IdentityServer4 ([#7221](https://github.com/abpframework/abp/issues/7221)) * C# and JavaScript Static Client Proxy Generation ([#9864](https://github.com/abpframework/abp/issues/9864))
* Revisit the microservice demo solution ([#8385](https://github.com/abpframework/abp/issues/8385)) * Revisit the microservice demo solution ([#8385](https://github.com/abpframework/abp/issues/8385))
* Dapr integration ([#2183](https://github.com/abpframework/abp/issues/2183))
* Publishing distributed events as transactional ([#6126](https://github.com/abpframework/abp/issues/6126)) * Publishing distributed events as transactional ([#6126](https://github.com/abpframework/abp/issues/6126))
* Resource based authorization system ([#236](https://github.com/abpframework/abp/issues/236))
* API Versioning system: finalize & document ([#497](https://github.com/abpframework/abp/issues/497))
* Performance optimizations; Enabling .NET Trimming, using source generators and reducing reflection, etc. * Performance optimizations; Enabling .NET Trimming, using source generators and reducing reflection, etc.
* Improving the abp.io platform and work more on contents and documents * Improving the abp.io platform and work more on contents and documents
@ -27,6 +24,10 @@ The *Next Versions* section above shows the main focus of the planned versions.
Here, a list of major items in the backlog we are considering to work on in the next versions. Here, a list of major items in the backlog we are considering to work on in the next versions.
* ([#497](https://github.com/abpframework/abp/issues/497)) API Versioning system: finalize & document
* ([#7221](https://github.com/abpframework/abp/issues/7221)) Alternative to IdentityServer4
* ([#2183](https://github.com/abpframework/abp/issues/2183)) Dapr integration
* ([#236](https://github.com/abpframework/abp/issues/236)) Resource based authorization system
* [#2882](https://github.com/abpframework/abp/issues/2882) / Providing a gRPC integration infrastructure (while it is [already possible](https://github.com/abpframework/abp-samples/tree/master/GrpcDemo) to create or consume gRPC endpoints for your application, we plan to create endpoints for the [standard application modules](https://docs.abp.io/en/abp/latest/Modules/Index)) * [#2882](https://github.com/abpframework/abp/issues/2882) / Providing a gRPC integration infrastructure (while it is [already possible](https://github.com/abpframework/abp-samples/tree/master/GrpcDemo) to create or consume gRPC endpoints for your application, we plan to create endpoints for the [standard application modules](https://docs.abp.io/en/abp/latest/Modules/Index))
* [#1754](https://github.com/abpframework/abp/issues/1754) / Multi-lingual entities * [#1754](https://github.com/abpframework/abp/issues/1754) / Multi-lingual entities
* [#57](https://github.com/abpframework/abp/issues/57) / Built-in CQRS infrastructure * [#57](https://github.com/abpframework/abp/issues/57) / Built-in CQRS infrastructure

5
docs/en/Tutorials/Part-1.md

@ -34,6 +34,11 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer
* [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) * [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore)
* [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb)
> If you encounter the "filename too long" or "unzip error" on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later).
> If you face long path errors related to Git, try the following command to enable long paths in Windows. See https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path
> `git config --system core.longpaths true`
{{if UI == "MVC" && DB == "EF"}} {{if UI == "MVC" && DB == "EF"}}
### Video Tutorial ### Video Tutorial

5
docs/en/Tutorials/Part-10.md

@ -34,6 +34,11 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer
* [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) * [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore)
* [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb)
> If you encounter the "filename too long" or "unzip error" on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later).
> If you face long path errors related to Git, try the following command to enable long paths in Windows. See https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path
> `git config --system core.longpaths true`
## Introduction ## Introduction
We have created `Book` and `Author` functionalities for the book store application. However, currently there is no relation between these entities. We have created `Book` and `Author` functionalities for the book store application. However, currently there is no relation between these entities.

7
docs/en/Tutorials/Part-2.md

@ -34,6 +34,11 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer
* [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) * [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore)
* [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb)
> If you encounter the "filename too long" or "unzip error" on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later).
> If you face long path errors related to Git, try the following command to enable long paths in Windows. See https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path
> `git config --system core.longpaths true`
{{if UI == "MVC" && DB == "EF"}} {{if UI == "MVC" && DB == "EF"}}
### Video Tutorial ### Video Tutorial
@ -85,6 +90,8 @@ acme.bookStore.books.book.create({
}); });
```` ````
> If you downloaded the source code of the tutorial and following the steps from the sample, you should also pass the `authorId` parameter to the create method for **creating a new book**.
You should see a message in the console something like that: You should see a message in the console something like that:
````text ````text

5
docs/en/Tutorials/Part-3.md

@ -34,6 +34,11 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer
* [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) * [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore)
* [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb)
> If you encounter the "filename too long" or "unzip error" on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later).
> If you face long path errors related to Git, try the following command to enable long paths in Windows. See https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path
> `git config --system core.longpaths true`
{{if UI == "MVC" && DB == "EF"}} {{if UI == "MVC" && DB == "EF"}}
### Video Tutorial ### Video Tutorial

5
docs/en/Tutorials/Part-4.md

@ -34,6 +34,11 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer
* [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) * [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore)
* [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb)
> If you encounter the "filename too long" or "unzip error" on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later).
> If you face long path errors related to Git, try the following command to enable long paths in Windows. See https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path
> `git config --system core.longpaths true`
{{if UI == "MVC" && DB == "EF"}} {{if UI == "MVC" && DB == "EF"}}
### Video Tutorial ### Video Tutorial

7
docs/en/Tutorials/Part-5.md

@ -34,6 +34,11 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer
* [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) * [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore)
* [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb)
> If you encounter the "filename too long" or "unzip error" on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later).
> If you face long path errors related to Git, try the following command to enable long paths in Windows. See https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path
> `git config --system core.longpaths true`
{{if UI == "MVC" && DB == "EF"}} {{if UI == "MVC" && DB == "EF"}}
### Video Tutorial ### Video Tutorial
@ -627,4 +632,4 @@ private async Task ConfigureMainMenuAsync(MenuConfigurationContext context)
## The Next Part ## The Next Part
See the [next part](Part-6.md) of this tutorial. See the [next part](Part-6.md) of this tutorial.

7
docs/en/Tutorials/Part-6.md

@ -34,6 +34,11 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer
* [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) * [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore)
* [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb)
> If you encounter the "filename too long" or "unzip error" on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later).
> If you face long path errors related to Git, try the following command to enable long paths in Windows. See https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path
> `git config --system core.longpaths true`
## Introduction ## Introduction
In the previous parts, we've used the ABP infrastructure to easily build some services; In the previous parts, we've used the ABP infrastructure to easily build some services;
@ -270,4 +275,4 @@ This part covered the domain layer of the authors functionality of the book stor
## The Next Part ## The Next Part
See the [next part](Part-7.md) of this tutorial. See the [next part](Part-7.md) of this tutorial.

5
docs/en/Tutorials/Part-7.md

@ -34,6 +34,11 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer
* [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) * [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore)
* [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb)
> If you encounter the "filename too long" or "unzip error" on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later).
> If you face long path errors related to Git, try the following command to enable long paths in Windows. See https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path
> `git config --system core.longpaths true`
## Introduction ## Introduction
This part explains how to configure the database integration for the `Author` entity introduced in the previous part. This part explains how to configure the database integration for the `Author` entity introduced in the previous part.

5
docs/en/Tutorials/Part-8.md

@ -34,6 +34,11 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer
* [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) * [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore)
* [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb)
> If you encounter the "filename too long" or "unzip error" on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later).
> If you face long path errors related to Git, try the following command to enable long paths in Windows. See https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path
> `git config --system core.longpaths true`
## Introduction ## Introduction
This part explains to create an application layer for the `Author` entity created before. This part explains to create an application layer for the `Author` entity created before.

5
docs/en/Tutorials/Part-9.md

@ -34,6 +34,11 @@ This tutorial has multiple versions based on your **UI** and **Database** prefer
* [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore) * [Blazor UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore)
* [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb)
> If you encounter the "filename too long" or "unzip error" on Windows, it's probably related to the Windows maximum file path limitation. Windows has a maximum file path limitation of 250 characters. To solve this, [enable the long path option in Windows 10](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later).
> If you face long path errors related to Git, try the following command to enable long paths in Windows. See https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path
> `git config --system core.longpaths true`
## Introduction ## Introduction
This part explains how to create a CRUD page for the `Author` entity introduced in the previous parts. This part explains how to create a CRUD page for the `Author` entity introduced in the previous parts.

67
docs/en/UI/Angular/How-Replaceable-Components-Work-with-Extensions.md

@ -17,30 +17,18 @@ yarn ng generate component my-roles/my-roles --flat --export
Open the generated `src/app/my-roles/my-roles.component.ts` file and replace its content with the following: Open the generated `src/app/my-roles/my-roles.component.ts` file and replace its content with the following:
```js ```js
import { ListService, PagedAndSortedResultRequestDto } from '@abp/ng.core'; import { ListService, PagedAndSortedResultRequestDto, PagedResultDto } from '@abp/ng.core';
import { import { eIdentityComponents, IdentityRoleDto, IdentityRoleService, RolesComponent } from '@abp/ng.identity';
CreateRole,
DeleteRole,
eIdentityComponents,
GetRoleById,
GetRoles,
IdentityRoleDto,
IdentityState,
RolesComponent,
UpdateRole,
} from '@abp/ng.identity';
import { ePermissionManagementComponents } from '@abp/ng.permission-management'; import { ePermissionManagementComponents } from '@abp/ng.permission-management';
import { Confirmation, ConfirmationService } from '@abp/ng.theme.shared'; import { Confirmation, ConfirmationService } from '@abp/ng.theme.shared';
import { import {
EXTENSIONS_IDENTIFIER, EXTENSIONS_IDENTIFIER,
FormPropData, FormPropData,
generateFormFromProps, generateFormFromProps
} from '@abp/ng.theme.shared/extensions'; } from '@abp/ng.theme.shared/extensions';
import { Component, Injector, OnInit } from '@angular/core'; import { Component, Injector, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms'; import { FormGroup } from '@angular/forms';
import { Select, Store } from '@ngxs/store'; import { finalize } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { finalize, pluck } from 'rxjs/operators';
@Component({ @Component({
selector: 'app-my-roles', selector: 'app-my-roles',
@ -51,15 +39,14 @@ import { finalize, pluck } from 'rxjs/operators';
provide: EXTENSIONS_IDENTIFIER, provide: EXTENSIONS_IDENTIFIER,
useValue: eIdentityComponents.Roles, useValue: eIdentityComponents.Roles,
}, },
{ provide: RolesComponent, useExisting: MyRolesComponent }, {
provide: RolesComponent,
useExisting: MyRolesComponent
}
], ],
}) })
export class MyRolesComponent implements OnInit { export class MyRolesComponent implements OnInit {
@Select(IdentityState.getRoles) data: PagedResultDto<IdentityRoleDto> = { items: [], totalCount: 0 };
data$: Observable<IdentityRoleDto[]>;
@Select(IdentityState.getRolesTotalCount)
totalCount$: Observable<number>;
form: FormGroup; form: FormGroup;
@ -82,8 +69,8 @@ export class MyRolesComponent implements OnInit {
constructor( constructor(
public readonly list: ListService<PagedAndSortedResultRequestDto>, public readonly list: ListService<PagedAndSortedResultRequestDto>,
protected confirmationService: ConfirmationService, protected confirmationService: ConfirmationService,
protected store: Store, protected injector: Injector,
protected injector: Injector protected service: IdentityRoleService,
) {} ) {}
ngOnInit() { ngOnInit() {
@ -106,25 +93,21 @@ export class MyRolesComponent implements OnInit {
} }
edit(id: string) { edit(id: string) {
this.store this.service.get(id).subscribe(res => {
.dispatch(new GetRoleById(id)) this.selected = res;
.pipe(pluck('IdentityState', 'selectedRole')) this.openModal();
.subscribe(selectedRole => { });
this.selected = selectedRole;
this.openModal();
});
} }
save() { save() {
if (!this.form.valid) return; if (!this.form.valid) return;
this.modalBusy = true; this.modalBusy = true;
this.store const { id } = this.selected;
.dispatch( (id
this.selected.id ? this.service.update(id, { ...this.selected, ...this.form.value })
? new UpdateRole({ ...this.selected, ...this.form.value, id: this.selected.id }) : this.service.create(this.form.value)
: new CreateRole(this.form.value) )
)
.pipe(finalize(() => (this.modalBusy = false))) .pipe(finalize(() => (this.modalBusy = false)))
.subscribe(() => { .subscribe(() => {
this.isModalVisible = false; this.isModalVisible = false;
@ -139,13 +122,13 @@ export class MyRolesComponent implements OnInit {
}) })
.subscribe((status: Confirmation.Status) => { .subscribe((status: Confirmation.Status) => {
if (status === Confirmation.Status.confirm) { if (status === Confirmation.Status.confirm) {
this.store.dispatch(new DeleteRole(id)).subscribe(() => this.list.get()); this.service.delete(id).subscribe(() => this.list.get());
} }
}); });
} }
private hookToQuery() { private hookToQuery() {
this.list.hookToQuery(query => this.store.dispatch(new GetRoles(query))).subscribe(); this.list.hookToQuery(query => this.service.getList(query)).subscribe(res => (this.data = res));
} }
openPermissionsModal(providerKey: string) { openPermissionsModal(providerKey: string) {
@ -189,15 +172,15 @@ Open the generated `src/app/my-role/my-role.component.html` file and replace its
<h5 class="card-title">My Roles</h5> <h5 class="card-title">My Roles</h5>
</div> </div>
<div class="text-right col col-md-6"> <div class="text-right col col-md-6">
<abp-page-toolbar [record]="data$ | async"></abp-page-toolbar> <abp-page-toolbar [record]="data.items"></abp-page-toolbar>
</div> </div>
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">
<abp-extensible-table <abp-extensible-table
[data]="data$ | async" [data]="data.items"
[recordsTotal]="totalCount$ | async" [recordsTotal]="data.totalCount"
[list]="list" [list]="list"
></abp-extensible-table> ></abp-extensible-table>
</div> </div>

276
docs/en/UI/Angular/Permission-Management-Component-Replacement.md

@ -5,37 +5,27 @@
Run the following command in `angular` folder to create a new component called `PermissionManagementComponent`. Run the following command in `angular` folder to create a new component called `PermissionManagementComponent`.
```bash ```bash
yarn ng generate component permission-management --entryComponent --inlineStyle yarn ng generate component permission-management --inlineStyle
# You don't need the --entryComponent option in Angular 9
``` ```
Open the generated `permission-management.component.ts` in `src/app/permission-management` folder and replace the content with the following: Open the generated `permission-management.component.ts` in `src/app/permission-management` folder and replace the content with the following:
```js ```js
import { ConfigStateService, CurrentUserDto, ReplaceableComponents } from '@abp/ng.core';
import {
GetPermissionListResultDto,
PermissionGrantInfoDto, PermissionGroupDto, PermissionManagement, PermissionsService, ProviderInfoDto, UpdatePermissionDto
} from '@abp/ng.permission-management';
import { LocaleDirection } from '@abp/ng.theme.shared';
import { import {
Component, Component,
EventEmitter, EventEmitter, Inject, Input, Optional, Output, TrackByFunction
Input,
Output,
Renderer2,
TrackByFunction,
Inject,
Optional,
} from '@angular/core'; } from '@angular/core';
import { ReplaceableComponents } from '@abp/ng.core'; import { of } from 'rxjs';
import { Select, Store } from '@ngxs/store'; import { finalize, switchMap, tap } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { finalize, map, pluck, take, tap } from 'rxjs/operators';
import {
GetPermissions,
UpdatePermissions,
PermissionManagement,
PermissionManagementState,
} from '@abp/ng.permission-management';
type PermissionWithMargin = PermissionManagement.Permission & { type PermissionWithStyle = PermissionGrantInfoDto & {
margin: number; style: string;
}; };
@Component({ @Component({
@ -52,8 +42,8 @@ type PermissionWithMargin = PermissionManagement.Permission & {
}) })
export class PermissionManagementComponent export class PermissionManagementComponent
implements implements
PermissionManagement.PermissionManagementComponentInputs, PermissionManagement.PermissionManagementComponentInputs,
PermissionManagement.PermissionManagementComponentOutputs { PermissionManagement.PermissionManagementComponentOutputs {
protected _providerName: string; protected _providerName: string;
@Input() @Input()
get providerName(): string { get providerName(): string {
@ -115,15 +105,11 @@ export class PermissionManagementComponent
@Output() readonly visibleChange = new EventEmitter<boolean>(); @Output() readonly visibleChange = new EventEmitter<boolean>();
@Select(PermissionManagementState.getPermissionGroups) data: GetPermissionListResultDto = { groups: [], entityDisplayName: null };
groups$: Observable<PermissionManagement.Group[]>;
@Select(PermissionManagementState.getEntityDisplayName) selectedGroup: PermissionGroupDto;
entityName$: Observable<string>;
selectedGroup: PermissionManagement.Group; permissions: PermissionGrantInfoDto[] = [];
permissions: PermissionManagement.Permission[] = [];
selectThisTab = false; selectThisTab = false;
@ -131,25 +117,26 @@ export class PermissionManagementComponent
modalBusy = false; modalBusy = false;
trackByFn: TrackByFunction<PermissionManagement.Group> = (_, item) => item.name; trackByFn: TrackByFunction<PermissionGroupDto> = (_, item) => item.name;
get selectedGroupPermissions$(): Observable<PermissionWithMargin[]> { get selectedGroupPermissions(): PermissionWithStyle[] {
return this.groups$.pipe( if (!this.selectedGroup) return [];
map((groups) =>
this.selectedGroup const margin = `margin-${
? groups.find((group) => group.name === this.selectedGroup.name).permissions (document.body.dir as LocaleDirection) === 'rtl' ? 'right' : 'left'
: [] }.px`;
),
map<PermissionManagement.Permission[], PermissionWithMargin[]>((permissions) => const permissions = this.data.groups.find(
permissions.map( group => group.name === this.selectedGroup.name,
(permission) => ).permissions;
(({
...permission, return permissions.map(
margin: findMargin(permissions, permission), permission =>
isGranted: this.permissions.find((per) => per.name === permission.name).isGranted, ({
} as any) as PermissionWithMargin) ...permission,
) style: { [margin]: findMargin(permissions, permission) },
) isGranted: this.permissions.find(per => per.name === permission.name).isGranted,
} as unknown as PermissionWithStyle),
); );
} }
@ -166,21 +153,22 @@ export class PermissionManagementComponent
PermissionManagement.PermissionManagementComponentInputs, PermissionManagement.PermissionManagementComponentInputs,
PermissionManagement.PermissionManagementComponentOutputs PermissionManagement.PermissionManagementComponentOutputs
>, >,
private store: Store private service: PermissionsService,
private configState: ConfigStateService
) {} ) {}
getChecked(name: string) { getChecked(name: string) {
return (this.permissions.find((per) => per.name === name) || { isGranted: false }).isGranted; return (this.permissions.find(per => per.name === name) || { isGranted: false }).isGranted;
} }
isGrantedByOtherProviderName(grantedProviders: PermissionManagement.GrantedProvider[]): boolean { isGrantedByOtherProviderName(grantedProviders: ProviderInfoDto[]): boolean {
if (grantedProviders.length) { if (grantedProviders.length) {
return grantedProviders.findIndex((p) => p.providerName !== this.providerName) > -1; return grantedProviders.findIndex(p => p.providerName !== this.providerName) > -1;
} }
return false; return false;
} }
onClickCheckbox(clickedPermission: PermissionManagement.Permission, value) { onClickCheckbox(clickedPermission: PermissionGrantInfoDto, value) {
if ( if (
clickedPermission.isGranted && clickedPermission.isGranted &&
this.isGrantedByOtherProviderName(clickedPermission.grantedProviders) this.isGrantedByOtherProviderName(clickedPermission.grantedProviders)
@ -188,7 +176,7 @@ export class PermissionManagementComponent
return; return;
setTimeout(() => { setTimeout(() => {
this.permissions = this.permissions.map((per) => { this.permissions = this.permissions.map(per => {
if (clickedPermission.name === per.name) { if (clickedPermission.name === per.name) {
return { ...per, isGranted: !per.isGranted }; return { ...per, isGranted: !per.isGranted };
} else if (clickedPermission.name === per.parentName && clickedPermission.isGranted) { } else if (clickedPermission.name === per.parentName && clickedPermission.isGranted) {
@ -206,24 +194,22 @@ export class PermissionManagementComponent
} }
setTabCheckboxState() { setTabCheckboxState() {
this.selectedGroupPermissions$.pipe(take(1)).subscribe((permissions) => { const selectedPermissions = this.selectedGroupPermissions.filter(per => per.isGranted);
const selectedPermissions = permissions.filter((per) => per.isGranted); const element = document.querySelector('#select-all-in-this-tabs') as any;
const element = document.querySelector('#select-all-in-this-tabs') as any;
if (selectedPermissions.length === this.selectedGroupPermissions.length) {
if (selectedPermissions.length === permissions.length) { element.indeterminate = false;
element.indeterminate = false; this.selectThisTab = true;
this.selectThisTab = true; } else if (selectedPermissions.length === 0) {
} else if (selectedPermissions.length === 0) { element.indeterminate = false;
element.indeterminate = false; this.selectThisTab = false;
this.selectThisTab = false; } else {
} else { element.indeterminate = true;
element.indeterminate = true; }
}
});
} }
setGrantCheckboxState() { setGrantCheckboxState() {
const selectedAllPermissions = this.permissions.filter((per) => per.isGranted); const selectedAllPermissions = this.permissions.filter(per => per.isGranted);
const checkboxElement = document.querySelector('#select-all-in-all-tabs') as any; const checkboxElement = document.querySelector('#select-all-in-all-tabs') as any;
if (selectedAllPermissions.length === this.permissions.length) { if (selectedAllPermissions.length === this.permissions.length) {
@ -238,26 +224,24 @@ export class PermissionManagementComponent
} }
onClickSelectThisTab() { onClickSelectThisTab() {
this.selectedGroupPermissions$.pipe(take(1)).subscribe((permissions) => { this.selectedGroupPermissions.forEach(permission => {
permissions.forEach((permission) => { if (permission.isGranted && this.isGrantedByOtherProviderName(permission.grantedProviders))
if (permission.isGranted && this.isGrantedByOtherProviderName(permission.grantedProviders)) return;
return;
const index = this.permissions.findIndex(per => per.name === permission.name);
const index = this.permissions.findIndex((per) => per.name === permission.name);
this.permissions = [
this.permissions = [ ...this.permissions.slice(0, index),
...this.permissions.slice(0, index), { ...this.permissions[index], isGranted: !this.selectThisTab },
{ ...this.permissions[index], isGranted: !this.selectThisTab }, ...this.permissions.slice(index + 1),
...this.permissions.slice(index + 1), ];
];
});
}); });
this.setGrantCheckboxState(); this.setGrantCheckboxState();
} }
onClickSelectAll() { onClickSelectAll() {
this.permissions = this.permissions.map((permission) => ({ this.permissions = this.permissions.map(permission => ({
...permission, ...permission,
isGranted: isGranted:
this.isGrantedByOtherProviderName(permission.grantedProviders) || !this.selectAllTab, this.isGrantedByOtherProviderName(permission.grantedProviders) || !this.selectAllTab,
@ -266,43 +250,41 @@ export class PermissionManagementComponent
this.selectThisTab = !this.selectAllTab; this.selectThisTab = !this.selectAllTab;
} }
onChangeGroup(group: PermissionManagement.Group) { onChangeGroup(group: PermissionGroupDto) {
this.selectedGroup = group; this.selectedGroup = group;
this.setTabCheckboxState(); this.setTabCheckboxState();
} }
submit() { submit() {
this.modalBusy = true; const unchangedPermissions = getPermissions(this.data.groups);
const unchangedPermissions = getPermissions(
this.store.selectSnapshot(PermissionManagementState.getPermissionGroups)
);
const changedPermissions: PermissionManagement.MinimumPermission[] = this.permissions const changedPermissions: UpdatePermissionDto[] = this.permissions
.filter((per) => .filter(per =>
unchangedPermissions.find((unchanged) => unchanged.name === per.name).isGranted === unchangedPermissions.find(unchanged => unchanged.name === per.name).isGranted ===
per.isGranted per.isGranted
? false ? false
: true : true,
) )
.map(({ name, isGranted }) => ({ name, isGranted })); .map(({ name, isGranted }) => ({ name, isGranted }));
if (changedPermissions.length) { if (!changedPermissions.length) {
this.store
.dispatch(
new UpdatePermissions({
providerKey: this.providerKey,
providerName: this.providerName,
permissions: changedPermissions,
})
)
.pipe(finalize(() => (this.modalBusy = false)))
.subscribe(() => {
this.visible = false;
});
} else {
this.modalBusy = false;
this.visible = false; this.visible = false;
return;
} }
this.modalBusy = true;
this.service
.update(this.providerName, this.providerKey, { permissions: changedPermissions })
.pipe(
switchMap(() =>
this.shouldFetchAppConfig() ? this.configState.refreshAppState() : of(null),
),
finalize(() => (this.modalBusy = false)),
)
.subscribe(() => {
this.visible = false;
});
} }
openModal() { openModal() {
@ -310,20 +292,13 @@ export class PermissionManagementComponent
throw new Error('Provider Key and Provider Name are required.'); throw new Error('Provider Key and Provider Name are required.');
} }
return this.store return this.service.get(this.providerName, this.providerKey).pipe(
.dispatch( tap((permissionRes: GetPermissionListResultDto) => {
new GetPermissions({ this.data = permissionRes;
providerKey: this.providerKey, this.selectedGroup = permissionRes.groups[0];
providerName: this.providerName, this.permissions = getPermissions(permissionRes.groups);
}) }),
) );
.pipe(
pluck('PermissionManagementState', 'permissionRes'),
tap((permissionRes: PermissionManagement.Response) => {
this.selectedGroup = permissionRes.groups[0];
this.permissions = getPermissions(permissionRes.groups);
})
);
} }
initModal() { initModal() {
@ -331,6 +306,13 @@ export class PermissionManagementComponent
this.setGrantCheckboxState(); this.setGrantCheckboxState();
} }
getAssignedCount(groupName: string) {
return this.permissions.reduce(
(acc, val) => (val.name.split('.')[0] === groupName && val.isGranted ? acc + 1 : acc),
0,
);
}
onVisibleChange(visible: boolean) { onVisibleChange(visible: boolean) {
this.visible = visible; this.visible = visible;
@ -339,13 +321,20 @@ export class PermissionManagementComponent
this.replaceableData.outputs.visibleChange(visible); this.replaceableData.outputs.visibleChange(visible);
} }
} }
shouldFetchAppConfig() {
const currentUser = this.configState.getOne('currentUser') as CurrentUserDto;
if (this.providerName === 'R') return currentUser.roles.some(role => role === this.providerKey);
if (this.providerName === 'U') return currentUser.id === this.providerKey;
return false;
}
} }
function findMargin( function findMargin(permissions: PermissionGrantInfoDto[], permission: PermissionGrantInfoDto) {
permissions: PermissionManagement.Permission[], const parentPermission = permissions.find(per => per.name === permission.parentName);
permission: PermissionManagement.Permission
) {
const parentPermission = permissions.find((per) => per.name === permission.parentName);
if (parentPermission && parentPermission.parentName) { if (parentPermission && parentPermission.parentName) {
let margin = 20; let margin = 20;
@ -355,7 +344,7 @@ function findMargin(
return parentPermission ? 20 : 0; return parentPermission ? 20 : 0;
} }
function getPermissions(groups: PermissionManagement.Group[]): PermissionManagement.Permission[] { function getPermissions(groups: PermissionGroupDto[]): PermissionGrantInfoDto[] {
return groups.reduce((acc, val) => [...acc, ...val.permissions], []); return groups.reduce((acc, val) => [...acc, ...val.permissions], []);
} }
``` ```
@ -363,16 +352,12 @@ function getPermissions(groups: PermissionManagement.Group[]): PermissionManagem
Open the generated `permission-management.component.html` in `src/app/permission-management` folder and replace the content with the below: Open the generated `permission-management.component.html` in `src/app/permission-management` folder and replace the content with the below:
```html ```html
<abp-modal <abp-modal [visible]="isVisible" (visibleChange)="onVisibleChange($event)" [busy]="modalBusy">
[visible]="isVisible" <ng-container *ngIf="data.entityDisplayName">
(visibleChange)="onVisibleChange($event)"
(init)="initModal()"
[busy]="modalBusy"
>
<ng-container *ngIf="{ entityName: entityName$ | async } as data">
<ng-template #abpHeader> <ng-template #abpHeader>
<h4> <h4>
{%{{{ 'AbpPermissionManagement::Permissions' | abpLocalization }}}%} - {%{{{ data.entityName }}}%} {%{{{ 'AbpPermissionManagement::Permissions' | abpLocalization }}}%} -
{%{{{ data.entityDisplayName }}}%}
</h4> </h4>
</ng-template> </ng-template>
<ng-template #abpBody> <ng-template #abpBody>
@ -394,13 +379,18 @@ Open the generated `permission-management.component.html` in `src/app/permission
<div class="row"> <div class="row">
<div class="overflow-scroll col-md-4"> <div class="overflow-scroll col-md-4">
<ul class="nav nav-pills flex-column"> <ul class="nav nav-pills flex-column">
<li *ngFor="let group of groups$ | async; trackBy: trackByFn" class="nav-item"> <li *ngFor="let group of data.groups; trackBy: trackByFn" class="nav-item">
<a <a
*ngIf="{ assignedCount: getAssignedCount(group.name) } as count"
class="nav-link pointer" class="nav-link pointer"
[class.active]="selectedGroup?.name === group?.name" [class.active]="selectedGroup?.name === group?.name"
(click)="onChangeGroup(group)" (click)="onChangeGroup(group)"
>{%{{{ group?.displayName }}}%}</a
> >
<div [class.font-weight-bold]="count.assignedCount">
{%{{{ group?.displayName }}}%}
<span>({%{{{ count.assignedCount }}}%})</span>
</div>
</a>
</li> </li>
</ul> </ul>
</div> </div>
@ -423,12 +413,8 @@ Open the generated `permission-management.component.html` in `src/app/permission
</div> </div>
<hr class="mb-3" /> <hr class="mb-3" />
<div <div
*ngFor=" *ngFor="let permission of selectedGroupPermissions; let i = index; trackBy: trackByFn"
let permission of selectedGroupPermissions$ | async; [ngStyle]="permission.style"
let i = index;
trackBy: trackByFn
"
[style.margin-left]="permission.margin + 'px'"
class="custom-checkbox custom-control mb-2" class="custom-checkbox custom-control mb-2"
> >
<input <input

6
docs/zh-Hans/Text-Templating.md

@ -187,9 +187,9 @@ var result = await _templateRenderer.RenderAsync(
示例中我们并没有创建模型类,但是创建了一个匿名对象模型. 示例中我们并没有创建模型类,但是创建了一个匿名对象模型.
### 大驼峰 与 小驼峰 ### PascalCase 与 snake_case
PascalCase 属性名(如 `UserName`) 在模板中用做小驼峰(如 `userName`). PascalCase 属性名(如 `UserName`) 在模板中使用蛇形命名(如 `user_name`).
## 本地化 ## 本地化
@ -454,4 +454,4 @@ public class MyTemplateContentProvider
* 本文开发和引用的[应用程序示例源码](https://github.com/abpframework/abp-samples/tree/master/TextTemplateDemo). * 本文开发和引用的[应用程序示例源码](https://github.com/abpframework/abp-samples/tree/master/TextTemplateDemo).
* [本地化系统](Localization.md). * [本地化系统](Localization.md).
* [虚拟文件系统](Virtual-File-System.md). * [虚拟文件系统](Virtual-File-System.md).

21
framework/Volo.Abp.sln

@ -383,8 +383,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TextTemplating.Scr
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.MongoDB.Tests.SecondContext", "test\Volo.Abp.MongoDB.Tests.SecondContext\Volo.Abp.MongoDB.Tests.SecondContext.csproj", "{90B1866A-EF99-40B9-970E-B898E5AA523F}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.MongoDB.Tests.SecondContext", "test\Volo.Abp.MongoDB.Tests.SecondContext\Volo.Abp.MongoDB.Tests.SecondContext.csproj", "{90B1866A-EF99-40B9-970E-B898E5AA523F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.IdentityModel.Tests", "test\Volo.Abp.IdentityModel.Tests\Volo.Abp.IdentityModel.Tests.csproj", "{40C6740E-BFCA-4D37-8344-3D84E2044BB2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Threading.Tests", "test\Volo.Abp.Threading.Tests\Volo.Abp.Threading.Tests.csproj", "{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Threading.Tests", "test\Volo.Abp.Threading.Tests\Volo.Abp.Threading.Tests.csproj", "{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Auditing.Contracts", "src\Volo.Abp.Auditing.Contracts\Volo.Abp.Auditing.Contracts.csproj", "{508B6355-AD28-4E60-8549-266D21DBF2CF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Http.Client.Web", "src\Volo.Abp.Http.Client.Web\Volo.Abp.Http.Client.Web.csproj", "{F7407459-8AFA-45E4-83E9-9BB01412CC08}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -1143,10 +1149,22 @@ Global
{90B1866A-EF99-40B9-970E-B898E5AA523F}.Debug|Any CPU.Build.0 = Debug|Any CPU {90B1866A-EF99-40B9-970E-B898E5AA523F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90B1866A-EF99-40B9-970E-B898E5AA523F}.Release|Any CPU.ActiveCfg = Release|Any CPU {90B1866A-EF99-40B9-970E-B898E5AA523F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90B1866A-EF99-40B9-970E-B898E5AA523F}.Release|Any CPU.Build.0 = Release|Any CPU {90B1866A-EF99-40B9-970E-B898E5AA523F}.Release|Any CPU.Build.0 = Release|Any CPU
{40C6740E-BFCA-4D37-8344-3D84E2044BB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{40C6740E-BFCA-4D37-8344-3D84E2044BB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{40C6740E-BFCA-4D37-8344-3D84E2044BB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{40C6740E-BFCA-4D37-8344-3D84E2044BB2}.Release|Any CPU.Build.0 = Release|Any CPU
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Debug|Any CPU.Build.0 = Debug|Any CPU {7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Release|Any CPU.ActiveCfg = Release|Any CPU {7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Release|Any CPU.Build.0 = Release|Any CPU {7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Release|Any CPU.Build.0 = Release|Any CPU
{508B6355-AD28-4E60-8549-266D21DBF2CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{508B6355-AD28-4E60-8549-266D21DBF2CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{508B6355-AD28-4E60-8549-266D21DBF2CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{508B6355-AD28-4E60-8549-266D21DBF2CF}.Release|Any CPU.Build.0 = Release|Any CPU
{F7407459-8AFA-45E4-83E9-9BB01412CC08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F7407459-8AFA-45E4-83E9-9BB01412CC08}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7407459-8AFA-45E4-83E9-9BB01412CC08}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7407459-8AFA-45E4-83E9-9BB01412CC08}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -1340,7 +1358,10 @@ Global
{C996F458-98FB-483D-9306-4701290E2FC1} = {447C8A77-E5F0-4538-8687-7383196D04EA} {C996F458-98FB-483D-9306-4701290E2FC1} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C} = {447C8A77-E5F0-4538-8687-7383196D04EA} {75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{90B1866A-EF99-40B9-970E-B898E5AA523F} = {447C8A77-E5F0-4538-8687-7383196D04EA} {90B1866A-EF99-40B9-970E-B898E5AA523F} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{40C6740E-BFCA-4D37-8344-3D84E2044BB2} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B} = {447C8A77-E5F0-4538-8687-7383196D04EA} {7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{508B6355-AD28-4E60-8549-266D21DBF2CF} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{F7407459-8AFA-45E4-83E9-9BB01412CC08} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

2
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.Authentication.JwtBearer</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Authentication.JwtBearer</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Authentication.JwtBearer</PackageId> <PackageId>Volo.Abp.AspNetCore.Authentication.JwtBearer</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

2
framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.Authentication.OAuth</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Authentication.OAuth</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Authentication.OAuth</PackageId> <PackageId>Volo.Abp.AspNetCore.Authentication.OAuth</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

2
framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo.Abp.AspNetCore.Authentication.OpenIdConnect.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<RootNamespace /> <RootNamespace />
</PropertyGroup> </PropertyGroup>

2
framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Volo.Abp.AspNetCore.Components.Server.Theming.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<IsPackable>true</IsPackable> <IsPackable>true</IsPackable>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile> <NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>

2
framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<IsPackable>true</IsPackable> <IsPackable>true</IsPackable>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile> <NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>

2
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Volo.Abp.AspNetCore.Components.Web.Theming.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

2
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo.Abp.AspNetCore.Components.Web.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<RootNamespace /> <RootNamespace />
</PropertyGroup> </PropertyGroup>

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo.Abp.AspNetCore.Components.WebAssembly.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.Components.WebAssembly</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Components.WebAssembly</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Components.WebAssembly</PackageId> <PackageId>Volo.Abp.AspNetCore.Components.WebAssembly</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.Components</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Components</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Components</PackageId> <PackageId>Volo.Abp.AspNetCore.Components</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.MultiTenancy</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.MultiTenancy</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.MultiTenancy</PackageId> <PackageId>Volo.Abp.AspNetCore.MultiTenancy</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

1
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpMultiTenancyCookieHelper.cs

@ -19,6 +19,7 @@ namespace Volo.Abp.AspNetCore.MultiTenancy
{ {
Path = "/", Path = "/",
HttpOnly = false, HttpOnly = false,
IsEssential = true,
Expires = DateTimeOffset.Now.AddYears(10) Expires = DateTimeOffset.Now.AddYears(10)
} }
); );

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.Client</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Mvc.Client</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Mvc.Client</PackageId> <PackageId>Volo.Abp.AspNetCore.Mvc.Client</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

1
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationDto.cs

@ -1,7 +1,6 @@
using System; using System;
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending;
using Volo.Abp.AspNetCore.Mvc.MultiTenancy; using Volo.Abp.AspNetCore.Mvc.MultiTenancy;
using Volo.Abp.Timing;
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
{ {

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc> <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.Bootstrap</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.Bootstrap</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Mvc.UI.Bootstrap</PackageId> <PackageId>Volo.Abp.AspNetCore.Mvc.UI.Bootstrap</PackageId>

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<RootNamespace /> <RootNamespace />
</PropertyGroup> </PropertyGroup>

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc> <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.Bundling</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.Bundling</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Mvc.UI.Bundling</PackageId> <PackageId>Volo.Abp.AspNetCore.Mvc.UI.Bundling</PackageId>

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantAppService.cs

@ -15,7 +15,7 @@ namespace Pages.Abp.MultiTenancy
TenantStore = tenantStore; TenantStore = tenantStore;
} }
public async Task<FindTenantResultDto> FindTenantByNameAsync(string name) public virtual async Task<FindTenantResultDto> FindTenantByNameAsync(string name)
{ {
var tenant = await TenantStore.FindAsync(name); var tenant = await TenantStore.FindAsync(name);
@ -33,7 +33,7 @@ namespace Pages.Abp.MultiTenancy
}; };
} }
public async Task<FindTenantResultDto> FindTenantByIdAsync(Guid id) public virtual async Task<FindTenantResultDto> FindTenantByIdAsync(Guid id)
{ {
var tenant = await TenantStore.FindAsync(id); var tenant = await TenantStore.FindAsync(id);

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/AbpTenantController.cs

@ -21,14 +21,14 @@ namespace Pages.Abp.MultiTenancy
[HttpGet] [HttpGet]
[Route("tenants/by-name/{name}")] [Route("tenants/by-name/{name}")]
public async Task<FindTenantResultDto> FindTenantByNameAsync(string name) public virtual async Task<FindTenantResultDto> FindTenantByNameAsync(string name)
{ {
return await _abpTenantAppService.FindTenantByNameAsync(name); return await _abpTenantAppService.FindTenantByNameAsync(name);
} }
[HttpGet] [HttpGet]
[Route("tenants/by-id/{id}")] [Route("tenants/by-id/{id}")]
public async Task<FindTenantResultDto> FindTenantByIdAsync(Guid id) public virtual async Task<FindTenantResultDto> FindTenantByIdAsync(Guid id)
{ {
return await _abpTenantAppService.FindTenantByIdAsync(id); return await _abpTenantAppService.FindTenantByIdAsync(id);
} }

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml.cs

@ -28,7 +28,7 @@ namespace Pages.Abp.MultiTenancy
LocalizationResourceType = typeof(AbpUiMultiTenancyResource); LocalizationResourceType = typeof(AbpUiMultiTenancyResource);
} }
public async Task OnGetAsync() public virtual async Task OnGetAsync()
{ {
Input = new TenantInfoModel(); Input = new TenantInfoModel();
@ -39,7 +39,7 @@ namespace Pages.Abp.MultiTenancy
} }
} }
public async Task OnPostAsync() public virtual async Task OnPostAsync()
{ {
Guid? tenantId = null; Guid? tenantId = null;
if (!Input.Name.IsNullOrEmpty()) if (!Input.Name.IsNullOrEmpty())

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc> <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy</PackageId> <PackageId>Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy</PackageId>

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc> <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.Packages</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.Packages</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Mvc.UI.Packages</PackageId> <PackageId>Volo.Abp.AspNetCore.Mvc.UI.Packages</PackageId>

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/SweetAlert/SweetalertScriptContributor.cs → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/SweetAlert2/Sweetalert2ScriptContributor.cs

@ -3,14 +3,14 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Core; using Volo.Abp.AspNetCore.Mvc.UI.Packages.Core;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.SweetAlert namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.SweetAlert2
{ {
[DependsOn(typeof(CoreScriptContributor))] [DependsOn(typeof(CoreScriptContributor))]
public class SweetalertScriptContributor : BundleContributor public class Sweetalert2ScriptContributor : BundleContributor
{ {
public override void ConfigureBundle(BundleConfigurationContext context) public override void ConfigureBundle(BundleConfigurationContext context)
{ {
context.Files.AddIfNotContains("/libs/sweetalert/sweetalert.min.js"); context.Files.AddIfNotContains("/libs/sweetalert2/sweetalert2.all.min.js");
} }
} }
} }

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc> <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo</PackageId> <PackageId>Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo</PackageId>

8
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Bundling/SharedThemeGlobalScriptContributor.cs

@ -9,7 +9,7 @@ using Volo.Abp.AspNetCore.Mvc.UI.Packages.Lodash;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Luxon; using Volo.Abp.AspNetCore.Mvc.UI.Packages.Luxon;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.MalihuCustomScrollbar; using Volo.Abp.AspNetCore.Mvc.UI.Packages.MalihuCustomScrollbar;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Select2; using Volo.Abp.AspNetCore.Mvc.UI.Packages.Select2;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.SweetAlert; using Volo.Abp.AspNetCore.Mvc.UI.Packages.SweetAlert2;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Timeago; using Volo.Abp.AspNetCore.Mvc.UI.Packages.Timeago;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Toastr; using Volo.Abp.AspNetCore.Mvc.UI.Packages.Toastr;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
@ -24,7 +24,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Bundling
typeof(JQueryFormScriptContributor), typeof(JQueryFormScriptContributor),
typeof(Select2ScriptContributor), typeof(Select2ScriptContributor),
typeof(DatatablesNetBs4ScriptContributor), typeof(DatatablesNetBs4ScriptContributor),
typeof(SweetalertScriptContributor), typeof(Sweetalert2ScriptContributor),
typeof(ToastrScriptBundleContributor), typeof(ToastrScriptBundleContributor),
typeof(MalihuCustomScrollbarPluginScriptBundleContributor), typeof(MalihuCustomScrollbarPluginScriptBundleContributor),
typeof(LuxonScriptContributor), typeof(LuxonScriptContributor),
@ -44,9 +44,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Bundling
"/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js", "/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js",
"/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js", "/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/modal-manager.js",
"/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js", "/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js",
"/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert/abp-sweetalert.js", "/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js",
"/libs/abp/aspnetcore-mvc-ui-theme-shared/toastr/abp-toastr.js" "/libs/abp/aspnetcore-mvc-ui-theme-shared/toastr/abp-toastr.js"
}); });
} }
} }
} }

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc> <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared</PackageId> <PackageId>Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared</PackageId>

24
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert/abp-sweetalert.js → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js

@ -1,6 +1,6 @@
var abp = abp || {}; var abp = abp || {};
(function ($) { (function ($) {
if (!sweetAlert || !$) { if (!Swal || !$) {
return; return;
} }
@ -27,7 +27,8 @@
confirm: { confirm: {
icon: 'warning', icon: 'warning',
title: 'Are you sure?', title: 'Are you sure?',
buttons: ['Cancel', 'Yes'] showCancelButton: true,
reverseButtons: true
} }
} }
}; };
@ -51,7 +52,7 @@
); );
return $.Deferred(function ($dfd) { return $.Deferred(function ($dfd) {
sweetAlert(opts).then(function () { Swal.fire(opts).then(function () {
$dfd.resolve(); $dfd.resolve();
}); });
}); });
@ -73,7 +74,7 @@
return showMessage('error', message, title); return showMessage('error', message, title);
}; };
abp.message.confirm = function (message, titleOrCallback, callback, closeOnEsc) { abp.message.confirm = function (message, titleOrCallback, callback) {
var userOpts = { var userOpts = {
text: message text: message
@ -86,8 +87,6 @@
userOpts.title = titleOrCallback; userOpts.title = titleOrCallback;
}; };
userOpts.closeOnEsc = closeOnEsc;
var opts = $.extend( var opts = $.extend(
{}, {},
abp.libs.sweetAlert.config['default'], abp.libs.sweetAlert.config['default'],
@ -96,10 +95,10 @@
); );
return $.Deferred(function ($dfd) { return $.Deferred(function ($dfd) {
sweetAlert(opts).then(function (isConfirmed) { Swal.fire(opts).then(result => {
callback && callback(isConfirmed); callback && callback(result.value);
$dfd.resolve(isConfirmed); $dfd.resolve(result.value);
}); })
}); });
}; };
@ -107,7 +106,8 @@
var l = abp.localization.getResource('AbpUi'); var l = abp.localization.getResource('AbpUi');
abp.libs.sweetAlert.config.confirm.title = l('AreYouSure'); abp.libs.sweetAlert.config.confirm.title = l('AreYouSure');
abp.libs.sweetAlert.config.confirm.buttons = [l('Cancel'), l('Yes')]; abp.libs.sweetAlert.config.confirm.showCancelButton = true;
abp.libs.sweetAlert.config.confirm.reverseButtons = true;
}); });
})(jQuery); })(jQuery);

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc> <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.Widgets</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Mvc.UI.Widgets</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Mvc.UI.Widgets</PackageId> <PackageId>Volo.Abp.AspNetCore.Mvc.UI.Widgets</PackageId>

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc> <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<AssemblyName>Volo.Abp.AspNetCore.Mvc.UI</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Mvc.UI</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Mvc.UI</PackageId> <PackageId>Volo.Abp.AspNetCore.Mvc.UI</PackageId>
@ -15,7 +15,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="NUglify" Version="1.13.8" /> <PackageReference Include="NUglify" Version="1.16.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc> <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<AssemblyName>Volo.Abp.AspNetCore.Mvc</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Mvc</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Mvc</PackageId> <PackageId>Volo.Abp.AspNetCore.Mvc</PackageId>

25
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs

@ -86,6 +86,7 @@ namespace Volo.Abp.AspNetCore.Mvc
var controllerModel = moduleModel.GetOrAddController( var controllerModel = moduleModel.GetOrAddController(
_options.ControllerNameGenerator(controllerType, setting), _options.ControllerNameGenerator(controllerType, setting),
FindGroupName(controllerType) ?? apiDescription.GroupName,
controllerType, controllerType,
_modelOptions.IgnoredInterfaces _modelOptions.IgnoredInterfaces
); );
@ -113,6 +114,14 @@ namespace Volo.Abp.AspNetCore.Mvc
allowAnonymous = false; allowAnonymous = false;
} }
var implementFrom = controllerType.FullName;
var interfaceType = controllerType.GetInterfaces().FirstOrDefault(i => i.GetMethods().Any(x => x.ToString() == method.ToString()));
if (interfaceType != null)
{
implementFrom = TypeHelper.GetFullNameHandlingNullableAndGenerics(interfaceType);
}
var actionModel = controllerModel.AddAction( var actionModel = controllerModel.AddAction(
uniqueMethodName, uniqueMethodName,
ActionApiDescriptionModel.Create( ActionApiDescriptionModel.Create(
@ -121,7 +130,8 @@ namespace Volo.Abp.AspNetCore.Mvc
apiDescription.RelativePath, apiDescription.RelativePath,
apiDescription.HttpMethod, apiDescription.HttpMethod,
GetSupportedVersions(controllerType, method, setting), GetSupportedVersions(controllerType, method, setting),
allowAnonymous allowAnonymous,
implementFrom
) )
); );
@ -351,6 +361,19 @@ namespace Volo.Abp.AspNetCore.Mvc
return ModuleApiDescriptionModel.DefaultRemoteServiceName; return ModuleApiDescriptionModel.DefaultRemoteServiceName;
} }
private string FindGroupName(Type controllerType)
{
var controllerNameAttribute =
controllerType.GetCustomAttributes().OfType<ControllerNameAttribute>().FirstOrDefault();
if (controllerNameAttribute?.Name != null)
{
return controllerNameAttribute.Name;
}
return null;
}
[CanBeNull] [CanBeNull]
private ConventionalControllerSetting FindSetting(Type controllerType) private ConventionalControllerSetting FindSetting(Type controllerType)
{ {

13
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/AbpServiceConvention.cs

@ -45,7 +45,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
{ {
RemoveDuplicateControllers(application); RemoveDuplicateControllers(application);
foreach (var controller in application.Controllers) foreach (var controller in GetControllers(application))
{ {
var controllerType = controller.ControllerType.AsType(); var controllerType = controller.ControllerType.AsType();
@ -71,11 +71,16 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
} }
} }
protected virtual IList<ControllerModel> GetControllers(ApplicationModel application)
{
return application.Controllers;
}
protected virtual void RemoveDuplicateControllers(ApplicationModel application) protected virtual void RemoveDuplicateControllers(ApplicationModel application)
{ {
var controllerModelsToRemove = new List<ControllerModel>(); var controllerModelsToRemove = new List<ControllerModel>();
foreach (var controllerModel in application.Controllers) foreach (var controllerModel in GetControllers(application))
{ {
if (!controllerModel.ControllerType.IsDefined(typeof(ExposeServicesAttribute), false)) if (!controllerModel.ControllerType.IsDefined(typeof(ExposeServicesAttribute), false))
{ {
@ -90,7 +95,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
var exposeServicesAttr = ReflectionHelper.GetSingleAttributeOrDefault<ExposeServicesAttribute>(controllerModel.ControllerType); var exposeServicesAttr = ReflectionHelper.GetSingleAttributeOrDefault<ExposeServicesAttribute>(controllerModel.ControllerType);
if (exposeServicesAttr.IncludeSelf) if (exposeServicesAttr.IncludeSelf)
{ {
var exposedControllerModels = application.Controllers var exposedControllerModels = GetControllers(application)
.Where(cm => exposeServicesAttr.ServiceTypes.Contains(cm.ControllerType)) .Where(cm => exposeServicesAttr.ServiceTypes.Contains(cm.ControllerType))
.ToArray(); .ToArray();
@ -109,7 +114,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
continue; continue;
} }
var baseControllerModels = application.Controllers var baseControllerModels = GetControllers(application)
.Where(cm => baseControllerTypes.Contains(cm.ControllerType)) .Where(cm => baseControllerTypes.Contains(cm.ControllerType))
.ToArray(); .ToArray();

24
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs

@ -5,10 +5,12 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.ExceptionHandling; using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.Authorization;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.ExceptionHandling; using Volo.Abp.ExceptionHandling;
using Volo.Abp.Http; using Volo.Abp.Http;
@ -55,17 +57,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
{ {
//TODO: Trigger an AbpExceptionHandled event or something like that. //TODO: Trigger an AbpExceptionHandled event or something like that.
context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
context.HttpContext.Response.StatusCode = (int) context
.GetRequiredService<IHttpExceptionStatusCodeFinder>()
.GetStatusCode(context.HttpContext, context.Exception);
var exceptionHandlingOptions = context.GetRequiredService<IOptions<AbpExceptionHandlingOptions>>().Value; var exceptionHandlingOptions = context.GetRequiredService<IOptions<AbpExceptionHandlingOptions>>().Value;
var exceptionToErrorInfoConverter = context.GetRequiredService<IExceptionToErrorInfoConverter>(); var exceptionToErrorInfoConverter = context.GetRequiredService<IExceptionToErrorInfoConverter>();
var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, exceptionHandlingOptions.SendExceptionsDetailsToClients); var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, exceptionHandlingOptions.SendExceptionsDetailsToClients);
context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo));
var logLevel = context.Exception.GetLogLevel(); var logLevel = context.Exception.GetLogLevel();
var remoteServiceErrorInfoBuilder = new StringBuilder(); var remoteServiceErrorInfoBuilder = new StringBuilder();
@ -80,6 +75,21 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
await context.GetRequiredService<IExceptionNotifier>().NotifyAsync(new ExceptionNotificationContext(context.Exception)); await context.GetRequiredService<IExceptionNotifier>().NotifyAsync(new ExceptionNotificationContext(context.Exception));
if (context.Exception is AbpAuthorizationException)
{
await context.HttpContext.RequestServices.GetRequiredService<IAbpAuthorizationExceptionHandler>()
.HandleAsync(context.Exception.As<AbpAuthorizationException>(), context.HttpContext);
}
else
{
context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
context.HttpContext.Response.StatusCode = (int) context
.GetRequiredService<IHttpExceptionStatusCodeFinder>()
.GetStatusCode(context.HttpContext, context.Exception);
context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo));
}
context.Exception = null; //Handled! context.Exception = null; //Handled!
} }
} }

24
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs

@ -5,10 +5,12 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.ExceptionHandling; using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.Authorization;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.ExceptionHandling; using Volo.Abp.ExceptionHandling;
using Volo.Abp.Http; using Volo.Abp.Http;
@ -67,17 +69,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
{ {
//TODO: Trigger an AbpExceptionHandled event or something like that. //TODO: Trigger an AbpExceptionHandled event or something like that.
context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
context.HttpContext.Response.StatusCode = (int) context
.GetRequiredService<IHttpExceptionStatusCodeFinder>()
.GetStatusCode(context.HttpContext, context.Exception);
var exceptionHandlingOptions = context.GetRequiredService<IOptions<AbpExceptionHandlingOptions>>().Value; var exceptionHandlingOptions = context.GetRequiredService<IOptions<AbpExceptionHandlingOptions>>().Value;
var exceptionToErrorInfoConverter = context.GetRequiredService<IExceptionToErrorInfoConverter>(); var exceptionToErrorInfoConverter = context.GetRequiredService<IExceptionToErrorInfoConverter>();
var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, exceptionHandlingOptions.SendExceptionsDetailsToClients); var remoteServiceErrorInfo = exceptionToErrorInfoConverter.Convert(context.Exception, exceptionHandlingOptions.SendExceptionsDetailsToClients);
context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo));
var logLevel = context.Exception.GetLogLevel(); var logLevel = context.Exception.GetLogLevel();
var remoteServiceErrorInfoBuilder = new StringBuilder(); var remoteServiceErrorInfoBuilder = new StringBuilder();
@ -91,6 +86,21 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
await context.GetRequiredService<IExceptionNotifier>().NotifyAsync(new ExceptionNotificationContext(context.Exception)); await context.GetRequiredService<IExceptionNotifier>().NotifyAsync(new ExceptionNotificationContext(context.Exception));
if (context.Exception is AbpAuthorizationException)
{
await context.HttpContext.RequestServices.GetRequiredService<IAbpAuthorizationExceptionHandler>()
.HandleAsync(context.Exception.As<AbpAuthorizationException>(), context.HttpContext);
}
else
{
context.HttpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
context.HttpContext.Response.StatusCode = (int) context
.GetRequiredService<IHttpExceptionStatusCodeFinder>()
.GetStatusCode(context.HttpContext, context.Exception);
context.Result = new ObjectResult(new RemoteServiceErrorResponse(remoteServiceErrorInfo));
}
context.Exception = null; //Handled! context.Exception = null; //Handled!
} }
} }

7
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Response/AbpNoContentActionFilter.cs

@ -18,8 +18,9 @@ namespace Volo.Abp.AspNetCore.Mvc.Response
await next(); await next();
if (context.HttpContext.Response.StatusCode == (int)HttpStatusCode.OK if (!context.HttpContext.Response.HasStarted &&
&& context.Result == null) context.HttpContext.Response.StatusCode == (int)HttpStatusCode.OK &&
context.Result == null)
{ {
var returnType = context.ActionDescriptor.GetReturnType(); var returnType = context.ActionDescriptor.GetReturnType();
if (returnType == typeof(Task) || returnType == typeof(void)) if (returnType == typeof(Task) || returnType == typeof(void))
@ -29,4 +30,4 @@ namespace Volo.Abp.AspNetCore.Mvc.Response
} }
} }
} }
} }

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.Serilog</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.Serilog</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Serilog</PackageId> <PackageId>Volo.Abp.AspNetCore.Serilog</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.SignalR</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.SignalR</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.SignalR</PackageId> <PackageId>Volo.Abp.AspNetCore.SignalR</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.TestBase</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore.TestBase</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.TestBase</PackageId> <PackageId>Volo.Abp.AspNetCore.TestBase</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

6
framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestDynamicProxyHttpClientFactory.cs → framework/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestProxyHttpClientFactory.cs

@ -1,15 +1,17 @@
using System.Net.Http; using System.Net.Http;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Client.DynamicProxying; using Volo.Abp.Http.Client.DynamicProxying;
using Volo.Abp.Http.Client.Proxying;
namespace Volo.Abp.AspNetCore.TestBase.DynamicProxying namespace Volo.Abp.AspNetCore.TestBase.DynamicProxying
{ {
[Dependency(ReplaceServices = true)] [Dependency(ReplaceServices = true)]
public class AspNetCoreTestDynamicProxyHttpClientFactory : IDynamicProxyHttpClientFactory, ITransientDependency public class AspNetCoreTestProxyHttpClientFactory : IProxyHttpClientFactory, ITransientDependency
{ {
private readonly ITestServerAccessor _testServerAccessor; private readonly ITestServerAccessor _testServerAccessor;
public AspNetCoreTestDynamicProxyHttpClientFactory( public AspNetCoreTestProxyHttpClientFactory(
ITestServerAccessor testServerAccessor) ITestServerAccessor testServerAccessor)
{ {
_testServerAccessor = testServerAccessor; _testServerAccessor = testServerAccessor;

17
framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Http/AbpHttpRequestExtensions.cs

@ -1,23 +1,18 @@
using JetBrains.Annotations; using System;
using JetBrains.Annotations;
using Microsoft.Net.Http.Headers;
using Volo.Abp; using Volo.Abp;
namespace Microsoft.AspNetCore.Http namespace Microsoft.AspNetCore.Http
{ {
public static class AbpHttpRequestExtensions public static class AbpHttpRequestExtensions
{ {
private const string RequestedWithHeader = "X-Requested-With";
private const string XmlHttpRequest = "XMLHttpRequest";
public static bool IsAjax([NotNull]this HttpRequest request) public static bool IsAjax([NotNull]this HttpRequest request)
{ {
Check.NotNull(request, nameof(request)); Check.NotNull(request, nameof(request));
if (request.Headers == null) return string.Equals(request.Query[HeaderNames.XRequestedWith], "XMLHttpRequest", StringComparison.Ordinal) ||
{ string.Equals(request.Headers[HeaderNames.XRequestedWith], "XMLHttpRequest", StringComparison.Ordinal);
return false;
}
return request.Headers[RequestedWithHeader] == XmlHttpRequest;
} }
public static bool CanAccept([NotNull]this HttpRequest request, [NotNull] string contentType) public static bool CanAccept([NotNull]this HttpRequest request, [NotNull] string contentType)
@ -25,7 +20,7 @@ namespace Microsoft.AspNetCore.Http
Check.NotNull(request, nameof(request)); Check.NotNull(request, nameof(request));
Check.NotNull(contentType, nameof(contentType)); Check.NotNull(contentType, nameof(contentType));
return request.Headers["Accept"].ToString().Contains(contentType); return request.Headers[HeaderNames.Accept].ToString().Contains(contentType, StringComparison.OrdinalIgnoreCase);
} }
} }
} }

1
framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestCultureCookieHelper.cs

@ -15,6 +15,7 @@ namespace Microsoft.AspNetCore.RequestLocalization
CookieRequestCultureProvider.MakeCookieValue(requestCulture), CookieRequestCultureProvider.MakeCookieValue(requestCulture),
new CookieOptions new CookieOptions
{ {
IsEssential = true,
Expires = DateTime.Now.AddYears(2) Expires = DateTime.Now.AddYears(2)
} }
); );

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

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore</AssemblyName> <AssemblyName>Volo.Abp.AspNetCore</AssemblyName>
<PackageId>Volo.Abp.AspNetCore</PackageId> <PackageId>Volo.Abp.AspNetCore</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> <AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

7
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpAuthorizationExceptionHandlerOptions.cs

@ -0,0 +1,7 @@
namespace Volo.Abp.AspNetCore.ExceptionHandling
{
public class AbpAuthorizationExceptionHandlerOptions
{
public string AuthenticationScheme { get; set; }
}
}

45
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs

@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Authorization;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.ExceptionHandling; using Volo.Abp.ExceptionHandling;
using Volo.Abp.Http; using Volo.Abp.Http;
@ -58,30 +59,38 @@ namespace Volo.Abp.AspNetCore.ExceptionHandling
{ {
_logger.LogException(exception); _logger.LogException(exception);
var errorInfoConverter = httpContext.RequestServices.GetRequiredService<IExceptionToErrorInfoConverter>();
var statusCodeFinder = httpContext.RequestServices.GetRequiredService<IHttpExceptionStatusCodeFinder>();
var jsonSerializer = httpContext.RequestServices.GetRequiredService<IJsonSerializer>();
var options = httpContext.RequestServices.GetRequiredService<IOptions<AbpExceptionHandlingOptions>>().Value;
httpContext.Response.Clear();
httpContext.Response.StatusCode = (int)statusCodeFinder.GetStatusCode(httpContext, exception);
httpContext.Response.OnStarting(_clearCacheHeadersDelegate, httpContext.Response);
httpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
await httpContext.Response.WriteAsync(
jsonSerializer.Serialize(
new RemoteServiceErrorResponse(
errorInfoConverter.Convert(exception, options.SendExceptionsDetailsToClients)
)
)
);
await httpContext await httpContext
.RequestServices .RequestServices
.GetRequiredService<IExceptionNotifier>() .GetRequiredService<IExceptionNotifier>()
.NotifyAsync( .NotifyAsync(
new ExceptionNotificationContext(exception) new ExceptionNotificationContext(exception)
); );
if (exception is AbpAuthorizationException)
{
await httpContext.RequestServices.GetRequiredService<IAbpAuthorizationExceptionHandler>()
.HandleAsync(exception.As<AbpAuthorizationException>(), httpContext);
}
else
{
var errorInfoConverter = httpContext.RequestServices.GetRequiredService<IExceptionToErrorInfoConverter>();
var statusCodeFinder = httpContext.RequestServices.GetRequiredService<IHttpExceptionStatusCodeFinder>();
var jsonSerializer = httpContext.RequestServices.GetRequiredService<IJsonSerializer>();
var options = httpContext.RequestServices.GetRequiredService<IOptions<AbpExceptionHandlingOptions>>().Value;
httpContext.Response.Clear();
httpContext.Response.StatusCode = (int)statusCodeFinder.GetStatusCode(httpContext, exception);
httpContext.Response.OnStarting(_clearCacheHeadersDelegate, httpContext.Response);
httpContext.Response.Headers.Add(AbpHttpConsts.AbpErrorFormat, "true");
await httpContext.Response.WriteAsync(
jsonSerializer.Serialize(
new RemoteServiceErrorResponse(
errorInfoConverter.Convert(exception, options.SendExceptionsDetailsToClients)
)
)
);
}
} }
private Task ClearCacheHeaders(object state) private Task ClearCacheHeaders(object state)

67
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultAbpAuthorizationExceptionHandler.cs

@ -0,0 +1,67 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Authorization;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.ExceptionHandling
{
public class DefaultAbpAuthorizationExceptionHandler : IAbpAuthorizationExceptionHandler, ITransientDependency
{
public virtual async Task HandleAsync(AbpAuthorizationException exception, HttpContext httpContext)
{
var handlerOptions = httpContext.RequestServices.GetRequiredService<IOptions<AbpAuthorizationExceptionHandlerOptions>>().Value;
var isAuthenticated = httpContext.User.Identity?.IsAuthenticated ?? false;
var authenticationSchemeProvider = httpContext.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
AuthenticationScheme scheme = null;
if (!handlerOptions.AuthenticationScheme.IsNullOrWhiteSpace())
{
scheme = await authenticationSchemeProvider.GetSchemeAsync(handlerOptions.AuthenticationScheme);
if (scheme == null)
{
throw new AbpException($"No authentication scheme named {handlerOptions.AuthenticationScheme} was found.");
}
}
else
{
if (isAuthenticated)
{
scheme = await authenticationSchemeProvider.GetDefaultForbidSchemeAsync();
if (scheme == null)
{
throw new AbpException($"There was no DefaultForbidScheme found.");
}
}
else
{
scheme = await authenticationSchemeProvider.GetDefaultChallengeSchemeAsync();
if (scheme == null)
{
throw new AbpException($"There was no DefaultChallengeScheme found.");
}
}
}
var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
var handler = await handlers.GetHandlerAsync(httpContext, scheme.Name);
if (handler == null)
{
throw new AbpException($"No handler of {scheme.Name} was found.");
}
if (isAuthenticated)
{
await handler.ForbidAsync(null);
}
else
{
await handler.ChallengeAsync(null);
}
}
}
}

11
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IAbpAuthorizationExceptionHandler.cs

@ -0,0 +1,11 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Volo.Abp.Authorization;
namespace Volo.Abp.AspNetCore.ExceptionHandling
{
public interface IAbpAuthorizationExceptionHandler
{
Task HandleAsync(AbpAuthorizationException exception, HttpContext httpContext);
}
}

3
framework/src/Volo.Abp.Auditing.Contracts/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
framework/src/Volo.Abp.Auditing.Contracts/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

21
framework/src/Volo.Abp.Auditing.Contracts/Volo.Abp.Auditing.Contracts.csproj

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.Auditing.Contracts</AssemblyName>
<PackageId>Volo.Abp.Auditing.Contracts</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Core\Volo.Abp.Core.csproj" />
</ItemGroup>
</Project>

9
framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/AbpAuditingContractsModule.cs

@ -0,0 +1,9 @@
using Volo.Abp.Modularity;
namespace Volo.Abp.Auditing
{
public class AbpAuditingContractsModule : AbpModule
{
}
}

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditedAttribute.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/AuditedAttribute.cs

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/DisableAuditingAttribute.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/DisableAuditingAttribute.cs

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityChangeType.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/EntityChangeType.cs

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditedObject.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IAuditedObject.cs

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingEnabled.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IAuditingEnabled.cs

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/ICreationAuditedObject.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/ICreationAuditedObject.cs

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IDeletionAuditedObject.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IDeletionAuditedObject.cs

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IFullAuditedObject.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IFullAuditedObject.cs

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IHasCreationTime.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasCreationTime.cs

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IHasDeletionTime.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasDeletionTime.cs

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IHasModificationTime.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasModificationTime.cs

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMayHaveCreator.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IMayHaveCreator.cs

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IModificationAuditedObject.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IModificationAuditedObject.cs

0
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IMustHaveCreator.cs → framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IMustHaveCreator.cs

1
framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj

@ -15,6 +15,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Volo.Abp.Auditing.Contracts\Volo.Abp.Auditing.Contracts.csproj" />
<ProjectReference Include="..\Volo.Abp.Data\Volo.Abp.Data.csproj" /> <ProjectReference Include="..\Volo.Abp.Data\Volo.Abp.Data.csproj" />
<ProjectReference Include="..\Volo.Abp.Json\Volo.Abp.Json.csproj" /> <ProjectReference Include="..\Volo.Abp.Json\Volo.Abp.Json.csproj" />
<ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" /> <ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" />

3
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs

@ -15,7 +15,8 @@ namespace Volo.Abp.Auditing
typeof(AbpTimingModule), typeof(AbpTimingModule),
typeof(AbpSecurityModule), typeof(AbpSecurityModule),
typeof(AbpThreadingModule), typeof(AbpThreadingModule),
typeof(AbpMultiTenancyModule) typeof(AbpMultiTenancyModule),
typeof(AbpAuditingContractsModule)
)] )]
public class AbpAuditingModule : AbpModule public class AbpAuditingModule : AbpModule
{ {

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

Loading…
Cancel
Save