Browse Source

Merge branch 'dev' into IAbpDaprClientFactory

pull/18117/head
maliming 2 years ago
parent
commit
0adcaa5fbc
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 2
      .github/workflows/build-and-test.yml
  2. 208
      Directory.Packages.props
  3. 9
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json
  4. 4
      docs/en/Community-Articles/2023-10-23-NET-8-Feature-containers/POST.md
  5. 4
      docs/en/Community-Articles/2023-11-05-EF-Core-8-Complex-Types/POST.MD
  6. 21
      docs/en/Community-Articles/2023-11-06-Blazor-Fullstack-Web-Ui/Post.md
  7. BIN
      docs/en/Community-Articles/2023-11-06-Blazor-Fullstack-Web-Ui/cover-image.png
  8. 2
      docs/en/Community-Articles/2023-11-06-EF-Core_Hierarchy-Id/POST.md
  9. 95
      docs/en/Community-Articles/2023-11-16-Upgrading-Your-Existing-Projects-to-NET8/POST.md
  10. 5
      docs/en/Community-Articles/2023-11-97-AOT-Compilation/Post.md
  11. 80
      docs/en/Dynamic-Claims.md
  12. 343
      docs/en/Migration-Guides/Abp-8_0.md
  13. 1
      docs/en/Migration-Guides/Index.md
  14. BIN
      docs/en/Migration-Guides/images/integration-postfix-not-removed.png
  15. 8
      docs/en/docs-nav.json
  16. 14
      framework/Volo.Abp.sln
  17. 7
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Security/AbpComponentsClaimsCache.cs
  18. 44
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributor.cs
  19. 72
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributorCache.cs
  20. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs
  21. 61
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleFile.cs
  22. 6
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Authentication/ChallengeAccountController.cs
  23. 5
      framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs
  24. 25
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpDynamicClaimsMiddleware.cs
  25. 1
      framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj
  26. 3
      framework/src/Volo.Abp.EventBus.Rebus/Volo.Abp.EventBus.Rebus.csproj
  27. 3
      framework/src/Volo.Abp.Imaging.SkiaSharp/FodyWeavers.xml
  28. 30
      framework/src/Volo.Abp.Imaging.SkiaSharp/FodyWeavers.xsd
  29. 28
      framework/src/Volo.Abp.Imaging.SkiaSharp/Volo.Abp.Imaging.SkiaSharp.csproj
  30. 8
      framework/src/Volo.Abp.Imaging.SkiaSharp/Volo/Abp/Imaging/AbpImagingSkiaSharpModule.cs
  31. 98
      framework/src/Volo.Abp.Imaging.SkiaSharp/Volo/Abp/Imaging/SkiaSharpImageResizerContributor.cs
  32. 16
      framework/src/Volo.Abp.Imaging.SkiaSharp/Volo/Abp/Imaging/SkiaSharpResizerOptions.cs
  33. 14
      framework/src/Volo.Abp.Security/System/Security/Principal/AbpClaimsIdentityExtensions.cs
  34. 8
      framework/src/Volo.Abp.Security/Volo/Abp/Security/AbpSecurityModule.cs
  35. 10
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalContributorContext.cs
  36. 29
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactory.cs
  37. 40
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactoryOptions.cs
  38. 17
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpDynamicClaim.cs
  39. 25
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpDynamicClaimCacheItem.cs
  40. 44
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpDynamicClaimsPrincipalContributorBase.cs
  41. 2
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/IAbpClaimsPrincipalFactory.cs
  42. 8
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/IAbpDynamicClaimsPrincipalContributor.cs
  43. 19
      framework/test/Volo.Abp.Imaging.SkiaSharp.Tests/Volo.Abp.Imaging.SkiaSharp.Tests.csproj
  44. 14
      framework/test/Volo.Abp.Imaging.SkiaSharp.Tests/Volo/Abp/Imaging/AbpImagingMagickNetTestModule.cs
  45. 11
      framework/test/Volo.Abp.Imaging.SkiaSharp.Tests/Volo/Abp/Imaging/AbpImagingSkiaSharpTestModule.cs
  46. 75
      framework/test/Volo.Abp.Imaging.SkiaSharp.Tests/Volo/Abp/Imaging/SkiaSharpImageResizerTests.cs
  47. 103
      framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactory_Test.cs
  48. 189
      framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactory_Tests.cs
  49. 76
      framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/AbpDynamicClaimsPrincipalContributorBase_Tests.cs
  50. 4
      framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/CurrentPrincipalAccessor_Tests.cs
  51. 2
      global.json
  52. 2
      latest-versions.json
  53. 10
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/IDynamicClaimsAppService.cs
  54. 31
      modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/DynamicClaimsAppService.cs
  55. 24
      modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/Volo/Abp/Account/DynamicClaimsClientProxy.Generated.cs
  56. 7
      modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/Volo/Abp/Account/DynamicClaimsClientProxy.cs
  57. 41
      modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/account-generate-proxy.json
  58. 27
      modules/account/src/Volo.Abp.Account.HttpApi/Volo/Abp/Account/DynamicClaimsController.cs
  59. 14
      modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs
  60. 5
      modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/Account/OpenIddictSupportedLoginModel.cs
  61. 15
      modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs
  62. 22
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs
  63. 11
      modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs
  64. 15
      modules/account/src/Volo.Abp.Account.Web/wwwroot/client-proxies/account-proxy.js
  65. 2
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory.cs
  66. 39
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributor.cs
  67. 86
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributorCache.cs
  68. 13
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributorCacheOptions.cs
  69. 40
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/UserUpdatedEventHandler.cs
  70. 8
      modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory_Tests.cs
  71. 59
      modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributor_Tests.cs
  72. 100
      modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20231116094249_Initial.Designer.cs
  73. 88
      modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20231116094249_Initial.cs
  74. 98
      modules/openiddict/app/OpenIddict.Demo.Server/Migrations/ServerDbContextModelSnapshot.cs
  75. 1
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs
  76. 18
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDynamicClaimsOpenIddictClaimsPrincipalHandler.cs
  77. 2
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AbpOpenIdDictControllerBase.cs
  78. 14
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AuthorizeController.cs
  79. 1
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.AuthorizationCode.cs
  80. 1
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.DeviceCode.cs
  81. 4
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs
  82. 1
      modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.RefreshToken.cs
  83. 2
      npm/ng-packs/.gitignore
  84. 3
      npm/ng-packs/.prettierignore
  85. 2
      npm/ng-packs/apps/dev-app-e2e/project.json
  86. 11
      npm/ng-packs/apps/dev-app/project.json
  87. 152
      npm/ng-packs/migrations.json
  88. 38
      npm/ng-packs/nx.json
  89. 93
      npm/ng-packs/package.json
  90. 5
      npm/ng-packs/packages/account-core/project.json
  91. 5
      npm/ng-packs/packages/account/project.json
  92. 7
      npm/ng-packs/packages/components/extensible/src/lib/components/date-time-picker/extensible-date-time-picker.component.ts
  93. 2
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form-prop.component.html
  94. 133
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form-prop.component.ts
  95. 123
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form.component.ts
  96. 2
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.html
  97. 55
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts
  98. 5
      npm/ng-packs/packages/components/extensible/src/lib/components/grid-actions/grid-actions.component.ts
  99. 5
      npm/ng-packs/packages/components/extensible/src/lib/components/page-toolbar/page-toolbar.component.ts
  100. 1
      npm/ng-packs/packages/components/extensible/src/lib/directives/prop-data.directive.ts

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

@ -51,7 +51,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-dotnet@master
with:
dotnet-version: 8.0.100-rc.2.23502.2
dotnet-version: 8.0.100
- name: chown
run: |

208
Directory.Packages.props

@ -4,104 +4,105 @@
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="2.0.24" />
<PackageVersion Include="aliyun-net-sdk-sts" Version="3.1.1" />
<PackageVersion Include="aliyun-net-sdk-sts" Version="3.1.2" />
<PackageVersion Include="Aliyun.OSS.SDK.NetCore" Version="2.13.0" />
<PackageVersion Include="AsyncKeyedLock" Version="6.2.2" />
<PackageVersion Include="Autofac" Version="7.1.0" />
<PackageVersion Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
<PackageVersion Include="Autofac.Extras.DynamicProxy" Version="7.1.0" />
<PackageVersion Include="AutoMapper" Version="12.0.1" />
<PackageVersion Include="AWSSDK.S3" Version="3.7.205.9" />
<PackageVersion Include="AWSSDK.SecurityToken" Version="3.7.202.4" />
<PackageVersion Include="Azure.Messaging.ServiceBus" Version="7.8.1" />
<PackageVersion Include="Azure.Storage.Blobs" Version="12.18.0" />
<PackageVersion Include="Blazorise" Version="1.3.1" />
<PackageVersion Include="Blazorise.Components" Version="1.3.1" />
<PackageVersion Include="Blazorise.DataGrid" Version="1.3.1" />
<PackageVersion Include="Blazorise.Snackbar" Version="1.3.1" />
<PackageVersion Include="AWSSDK.S3" Version="3.7.300.2" />
<PackageVersion Include="AWSSDK.SecurityToken" Version="3.7.300.2" />
<PackageVersion Include="Azure.Messaging.ServiceBus" Version="7.17.0" />
<PackageVersion Include="Azure.Storage.Blobs" Version="12.19.1" />
<PackageVersion Include="Blazorise" Version="1.3.2" />
<PackageVersion Include="Blazorise.Components" Version="1.3.2" />
<PackageVersion Include="Blazorise.DataGrid" Version="1.3.2" />
<PackageVersion Include="Blazorise.Snackbar" Version="1.3.2" />
<PackageVersion Include="Castle.Core" Version="5.1.1" />
<PackageVersion Include="Castle.Core.AsyncInterceptor" Version="2.1.0" />
<PackageVersion Include="CommonMark.NET" Version="0.15.1" />
<PackageVersion Include="Confluent.Kafka" Version="2.2.0" />
<PackageVersion Include="Dapper" Version="2.1.4" />
<PackageVersion Include="Dapr.AspNetCore" Version="1.9.0" />
<PackageVersion Include="Dapr.Client" Version="1.11.0" />
<PackageVersion Include="Devart.Data.Oracle.EFCore" Version="10.1.134.7" />
<PackageVersion Include="Confluent.Kafka" Version="2.3.0" />
<PackageVersion Include="Dapper" Version="2.1.21" />
<PackageVersion Include="Dapr.AspNetCore" Version="1.12.0" />
<PackageVersion Include="Dapr.Client" Version="1.12.0" />
<PackageVersion Include="Devart.Data.Oracle.EFCore" Version="10.1.151.7" />
<PackageVersion Include="DistributedLock.Core" Version="1.0.5" />
<PackageVersion Include="DistributedLock.Redis" Version="1.0.2" />
<PackageVersion Include="EphemeralMongo.Core" Version="1.1.3" />
<PackageVersion Include="EphemeralMongo6.runtime.linux-x64" Version="1.1.3" />
<PackageVersion Include="EphemeralMongo6.runtime.osx-x64" Version="1.1.3" />
<PackageVersion Include="EphemeralMongo6.runtime.win-x64" Version="1.1.3" />
<PackageVersion Include="FluentValidation" Version="11.7.1" />
<PackageVersion Include="Hangfire.AspNetCore" Version="1.8.5" />
<PackageVersion Include="Hangfire.SqlServer" Version="1.8.5" />
<PackageVersion Include="HtmlSanitizer" Version="8.0.723" />
<PackageVersion Include="FluentValidation" Version="11.8.0" />
<PackageVersion Include="Hangfire.AspNetCore" Version="1.8.6" />
<PackageVersion Include="Hangfire.SqlServer" Version="1.8.6" />
<PackageVersion Include="HtmlSanitizer" Version="8.0.746" />
<PackageVersion Include="IdentityModel" Version="6.2.0" />
<PackageVersion Include="IdentityServer4" Version="4.1.2" />
<PackageVersion Include="IdentityServer4.AspNetIdentity" Version="4.1.2" />
<PackageVersion Include="JetBrains.Annotations" Version="2023.2.0" />
<PackageVersion Include="JetBrains.Annotations" Version="2023.3.0" />
<PackageVersion Include="LdapForNet" Version="2.7.15" />
<PackageVersion Include="LibGit2Sharp" Version="0.27.2" />
<PackageVersion Include="Magick.NET-Q16-AnyCPU" Version="13.3.0" />
<PackageVersion Include="MailKit" Version="4.2.0" />
<PackageVersion Include="LibGit2Sharp" Version="0.28.0" />
<PackageVersion Include="Magick.NET-Q16-AnyCPU" Version="13.4.0" />
<PackageVersion Include="MailKit" Version="4.3.0" />
<PackageVersion Include="Markdig.Signed" Version="0.33.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.Components" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Web" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Web" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.1.0" />
<PackageVersion Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.22" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.25" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="8.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.0" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Configuration.CommandLine" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Composite" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Localization" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.0-rc.2" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="8.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.CommandLine" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Composite" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Localization" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.0" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
<PackageVersion Include="Minio" Version="6.0.0" />
<PackageVersion Include="MongoDB.Driver" Version="2.21.0" />
<PackageVersion Include="Minio" Version="6.0.1" />
<PackageVersion Include="MongoDB.Driver" Version="2.22.0" />
<PackageVersion Include="NEST" Version="7.17.5" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Nito.AsyncEx.Context" Version="5.1.2" />
@ -111,57 +112,60 @@
<PackageVersion Include="NuGet.Versioning" Version="6.7.0" />
<PackageVersion Include="NUglify" Version="1.21.0" />
<PackageVersion Include="Nullable" Version="1.3.1" />
<PackageVersion Include="Octokit" Version="8.0.1" />
<PackageVersion Include="OpenIddict.Abstractions" Version="4.8.0" />
<PackageVersion Include="OpenIddict.Core" Version="4.8.0" />
<PackageVersion Include="OpenIddict.Server.AspNetCore" Version="4.8.0" />
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="4.8.0" />
<PackageVersion Include="OpenIddict.Validation.ServerIntegration" Version="4.8.0" />
<PackageVersion Include="Oracle.EntityFrameworkCore" Version="7.21.8" />
<PackageVersion Include="Polly" Version="8.0.0" />
<PackageVersion Include="Octokit" Version="9.0.0" />
<PackageVersion Include="OpenIddict.Abstractions" Version="4.10.0" />
<PackageVersion Include="OpenIddict.Core" Version="4.10.0" />
<PackageVersion Include="OpenIddict.Server.AspNetCore" Version="4.10.0" />
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="4.10.0" />
<PackageVersion Include="OpenIddict.Validation.ServerIntegration" Version="4.10.0" />
<PackageVersion Include="Oracle.EntityFrameworkCore" Version="7.21.12" />
<PackageVersion Include="Polly" Version="8.2.0" />
<PackageVersion Include="Polly.Extensions.Http" Version="3.0.0" />
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.0-beta.1" />
<PackageVersion Include="Quartz" Version="3.7.0" />
<PackageVersion Include="Quartz.Extensions.DependencyInjection" Version="3.7.0" />
<PackageVersion Include="Quartz.Plugins.TimeZoneConverter" Version="3.7.0" />
<PackageVersion Include="Quartz.Serialization.Json" Version="3.3.3" />
<PackageVersion Include="RabbitMQ.Client" Version="6.5.0" />
<PackageVersion Include="Quartz.Serialization.Json" Version="3.7.0" />
<PackageVersion Include="RabbitMQ.Client" Version="6.6.0" />
<PackageVersion Include="Rebus" Version="7.2.1" />
<PackageVersion Include="Rebus.ServiceProvider" Version="9.1.0" />
<PackageVersion Include="Scriban" Version="5.9.0" />
<PackageVersion Include="Serilog" Version="2.11.0" />
<PackageVersion Include="Serilog.AspNetCore" Version="7.0.0" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="7.0.0" />
<PackageVersion Include="Serilog.Extensions.Logging" Version="7.0.0" />
<PackageVersion Include="Serilog" Version="3.1.1" />
<PackageVersion Include="Serilog.AspNetCore" Version="8.0.0" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageVersion Include="Serilog.Extensions.Logging" Version="8.0.0" />
<PackageVersion Include="Serilog.Sinks.Async" Version="1.5.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="5.0.0" />
<PackageVersion Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Shouldly" Version="4.0.3" />
<PackageVersion Include="Shouldly" Version="4.2.1" />
<PackageVersion Include="SixLabors.ImageSharp" Version="3.0.2" />
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="2.0.0" />
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="2.0.1" />
<PackageVersion Include="SkiaSharp" Version="2.88.6" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.6" />
<PackageVersion Include="SkiaSharp.NativeAssets.macOS" Version="2.88.6" />
<PackageVersion Include="Slugify.Core" Version="4.0.1" />
<PackageVersion Include="Spectre.Console" Version="0.47.0" />
<PackageVersion Include="StackExchange.Redis" Version="2.6.122" />
<PackageVersion Include="StackExchange.Redis" Version="2.7.4" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageVersion Include="System.Collections.Immutable" Version="8.0.0-rc.2" />
<PackageVersion Include="System.Collections.Immutable" Version="8.0.0" />
<PackageVersion Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
<PackageVersion Include="System.Linq.Dynamic.Core" Version="1.3.5" />
<PackageVersion Include="System.Linq.Queryable" Version="4.3.0" />
<PackageVersion Include="System.Runtime.Loader" Version="4.3.0" />
<PackageVersion Include="System.Security.Permissions" Version="8.0.0-rc.2" />
<PackageVersion Include="System.Security.Permissions" Version="8.0.0" />
<PackageVersion Include="System.Security.Principal.Windows" Version="5.0.0" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="8.0.0-rc.2" />
<PackageVersion Include="System.Text.Encodings.Web" Version="8.0.0-rc.2" />
<PackageVersion Include="System.Text.Json" Version="8.0.0-rc.2" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="8.0.0" />
<PackageVersion Include="System.Text.Encodings.Web" Version="8.0.0" />
<PackageVersion Include="System.Text.Json" Version="8.0.0" />
<PackageVersion Include="TimeZoneConverter" Version="6.1.0" />
<PackageVersion Include="Unidecode.NET" Version="2.1.0" />
<PackageVersion Include="xunit" Version="2.5.1" />
<PackageVersion Include="xunit.extensibility.execution" Version="2.5.1" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.1" />
<PackageVersion Include="coverlet.collector" Version="3.1.2" />
<PackageVersion Include="ConfigureAwait.Fody" Version="3.3.2"/>
<PackageVersion Include="xunit" Version="2.6.1" />
<PackageVersion Include="xunit.extensibility.execution" Version="2.6.1" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.3" />
<PackageVersion Include="coverlet.collector" Version="6.0.0" />
<PackageVersion Include="ConfigureAwait.Fody" Version="3.3.2" />
<PackageVersion Include="Fody" Version="6.8.0" />
</ItemGroup>
</Project>
</Project>

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

@ -18,7 +18,7 @@
"Save": "Save",
"SameUrlAlreadyExist": "Same url already exists if you want to add this post, you should change the url!",
"UrlIsNotValid": "Url is not valid.",
"UrlNotFound" : "Url not found.",
"UrlNotFound": "Url not found.",
"UrlContentNotFound": "Url content not found.",
"Summary": "Summary",
"MostRead": "Most Read",
@ -171,7 +171,7 @@
"Discord_Page_Announce": "We are happy to announce ABP Community Discord Server!",
"Discord_Page_Description_1": "ABP Community has been growing since day one. We wanted to take it to the next step by creating an official ABP Discord server so the ABP Community can interact with each other using the wonders of instant messaging.",
"Discord_Page_Description_2": "ABP Community Discord Server is the place where you can showcase your creations using ABP Framework, share the tips that worked for you, catch up with the latest news and announcements about ABP Framework, just chat with community members to exchange ideas, and have fun!",
"Discord_Page_Description_3": "This ABP Community Discord Server is the official one with the ABP Core Team is present on the server to monitor.",
"Discord_Page_Description_3": "This ABP Community Discord Server is the official one with the ABP Core Team is present on the server to monitor.",
"Discord_Page_JoinToServer": "Join ABP Discord Server",
"Events_Page_MetaTitle": "ABP Community Events",
"Events_Page_MetaDescription": "The live shows, hosted by the ABP Team, are casual sessions full of community content, demos, Q&A, and discussions around what's happening in ABP.",
@ -252,6 +252,9 @@
"MostWatched": "Most Watched",
"Articles({0})": "Articles ({0})",
"Videos({0})": "Videos ({0})",
"LatestArticles": "Latest Articles"
"LatestArticles": "Latest Articles",
"RaffleHeader": "Hello ABP Community Member!",
"RafflesInfo": "<br>This is the raffle page dedicated to show our appreciation towards you for being an active Community Member. We do <a target=\"_blank\" class=\"fw-6 \" href=\"https://community.abp.io/events\">ABP Community Talks</a> <a target=\"_blank\" class=\"fw-6\" href=\"https://abp.io/conference/2023\">,ABP .NET Conference</a>, attend or sponsor to the .NET-related events in which we give away some gifts. <br><br>You can follow this page to see the upcoming raffles, attend them, or see previous raffles we draw including the winners. <br><br>Thank you for being an active member! See you in the upcoming raffles.",
"RafflesInfoTitle": "ABP Community <span class=\"gradient-community\">Raffles</span>"
}
}

4
docs/en/Community-Articles/2023-10-23-NET-8-Feature-containers/POST.md

@ -17,8 +17,8 @@ It's important to note that this change only affects the default port used when
If you want your application to continue using port 80, you can still specify it during the application launch or configure it in the application settings.
* Recommended: Explicitly set the `ASPNETCORE_HTTP_PORTS`, `ASPNETCORE_HTTPS_PORTS``, and `ASPNETCORE_URLS` environment variables to the desired port. Example: `docker run --rm -it -p 9999:80 -e ASPNETCORE_HTTP_PORTS=80 <my-app>``
* Update existing commands and configuration that rely on the expected default port of port 80 to reference port 8080 instead. Example: `docker run --rm -it -p 9999:8080 <my-app>``
* Recommended: Explicitly set the `ASPNETCORE_HTTP_PORTS`, `ASPNETCORE_HTTPS_PORTS`, and `ASPNETCORE_URLS` environment variables to the desired port. Example: `docker run --rm -it -p 9999:80 -e ASPNETCORE_HTTP_PORTS=80 <my-app>`
* Update existing commands and configuration that rely on the expected default port of port 80 to reference port 8080 instead. Example: `docker run --rm -it -p 9999:8080 <my-app>`
> The `dockerfile` of ABP templates has been updated to use port `80`.

4
docs/en/Community-Articles/2023-11-05-EF-Core-8-Complex-Types/POST.MD

@ -105,7 +105,7 @@ And update the database:
dotnet ef database update
````
If you check the fields of the `Customers` table in your dayabase, you will see the following fields:
If you check the fields of the `Customers` table in your database, you will see the following fields:
* `Id`
* `Name`
@ -180,7 +180,7 @@ For more details and examples, see the Microsoft's document in the *References*
You can find the sample project here:
https://github.com/hikalkan/samples/tree/master/EfCoreComplexTypeDemo
[https://github.com/hikalkan/samples/tree/master/EfCoreComplexTypeDemo](https://github.com/hikalkan/samples/tree/master/EfCoreComplexTypeDemo)
## References

21
docs/en/Community-Articles/2023-11-06-Blazor-Fullstack-Web-Ui/Post.md

@ -1,6 +1,9 @@
# Blazor's History and Full-stack Web UI
Blazor is a web framework that allows developers to build interactive web applications using .NET instead of JavaScript. The first version of Blazor was **released on May 14, 2020**. Since its initial release, Blazor has evolved with the new versions. Until now, six different versions have been declared. Sometimes, it can be not very clear to see the differences between these approaches. First, let's try to understand these.
![Cover Image](cover-image.png)
Blazor is a web framework that allows developers to build interactive web applications using .NET instead of JavaScript. The first version of Blazor was released on May 14, 2020. Since its initial release, Blazor has evolved with the new versions. Until now, six different versions have been declared. Sometimes, it can be not very clear to see the differences between these approaches. First, let's try to understand these.
* **Blazor-Server**: >> *Loads fast at first* >> In this version, heavy things are done in the server. Browsers are thin clients and download a small page for the first load. The page updates are done via SignalR connection. This was released with .NET Core 3.
* **Blazor WebAssembly (WASM):** >> *Loads slow at first* >> In this version, some binary files are being downloaded to the browser. This approach takes longer initialization time than the "Server" approach. The hard work is done on the browser.
@ -40,7 +43,7 @@ You can switch between two rendering modes and even mix them on the same page. W
## How it works?
## How it works?
### Rendering on Server
@ -50,25 +53,27 @@ You can add `WebComponentRenderMode.Server` to your Blazor components so that th
And sure you can add `WebComponentRenderMode.Server` to your page level, and the complete page will be rendered as a server component. All inputs on this page can work as an interactive server component like SPA mode.
And sure, you can add `WebComponentRenderMode.Server` to your page level, and the complete page will be rendered as a server component. All inputs on this page can work as an interactive server component like SPA mode.
![image-20231106172638604](image-20231106172638604.png)
### Rendering on client
### Rendering on Client
You can switch to WebAssembly mode by writing `WebComponentRenderMode.WebAssembly` attribute to your page. By doing so, the whole page should run interactively using WebAssembly. This time there's no server connection anymore because it loads the binaries (WebAssembly runtimes) at the page load.
![image-20231106173021958](image-20231106173021958.png)
## How it works?
## Enabling the Blazor Fullstack UI?
To enable Blazor Full-stack Web UI, you need to write `net8.0;net7.0-browser` into the `TargetFrameworks` area of your `csproj` file. These two keywords change your app like this; `net8.0` framework renders on the server, and `net7.0-browser` framework renders on the browser.
![image-20231106173411309](image-20231106173411309.png)
## Let the System decide on WebAssembly or Server approach
## Let the System Decide WebAssembly or Server Approach
You can let the system decide whether it uses `WebAssembly` or `Server`. This can be done with the `Auto` mode of the `WebComponentRenderMode`. In this case, it will not load binary files (WebAssembly files) for the initial page that has `WebComponentRenderMode.Server` attribute, but whenever the user navigates to a page that has `WebComponentRenderMode.WebAssembly`, it will download the runtimes. This will allow us to load the initial page very fast, and when we need interactivity, we can switch to `WebAssembly` and wait for the binaries to download. But this download will be done one time because it will be cached.
@ -80,10 +85,10 @@ You can let the system decide whether it uses `WebAssembly` or `Server`. This ca
I summarized the new generation Blazor in a very simple way. This architecture will be useful to everyone who uses Blazor.
---
*Resources:*
* You can check out Dan Roth's GitHub issue 👉 [github.com/dotnet/aspnetcore/issues/46636](https://github.com/dotnet/aspnetcore/issues/46636).
* You can check Dan Roth's GitHub issue 👉 [github.com/dotnet/aspnetcore/issues/46636](https://github.com/dotnet/aspnetcore/issues/46636).
* Steven Sanderson's YouTube video is very good for understanding these concepts 👉 [Blazor United Prototype Video](https://youtu.be/48G_CEGXZZM).

BIN
docs/en/Community-Articles/2023-11-06-Blazor-Fullstack-Web-Ui/cover-image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 KiB

2
docs/en/Community-Articles/2023-11-06-EF-Core_Hierarchy-Id/POST.md

@ -76,4 +76,4 @@ await context.SaveChangesAsync();
For more information about hierarchy id, see the following resource:
https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew#hierarchyid-in-net-and-ef-core
- [https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew#hierarchyid-in-net-and-ef-core](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew#hierarchyid-in-net-and-ef-core)

95
docs/en/Community-Articles/2023-11-16-Upgrading-Your-Existing-Projects-to-NET8/POST.md

@ -0,0 +1,95 @@
# Upgrade Your Existing Projects to .NET 8 & ABP 8.0
A new .NET version was released on November 14, 2023 and ABP 8.0 RC.1 shipped based on .NET 8.0 just after Microsoft's .NET 8.0 release. Therefore, it's a good time to see what we need to do to upgrade our existing projects to .NET 8.0.
Despite all the related dependency upgrades and changes made on ABP Framework and ABP Commercial sides, we still need to make some changes. Let's see the required actions that need to be taken in the following sections.
## Installing the .NET 8.0 SDK
To get started with ASP.NET Core in .NET 8.0, you need to install the .NET 8 SDK. You can install it at [https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0).
After installing the SDK & Runtime, you can upgrade your existing ASP.NET Core application to .NET 8.0.
## Updating the Target Framework
First, you need to update all your `*.csproj` files to support .NET 8. Find and replace all your `TargetFramework` definitions in the `*.csproj` files to support .NET 8.0:
```xml
<TargetFramework>net8.0</TargetFramework>
```
> This and all other changes mentioned in this article have already been done in the ABP Framework and ABP Commercial side, so you would not get any problems related to that.
## Updating Microsoft Package Versions
You are probably using some Microsoft packages in your solution, so you need to update them to the latest .NET 8.0 version. Therefore, update all `Microsoft.AspNetCore.*` and `Microsoft.Extensions.*` packages' references to `8.0.0`.
## Checking the Breaking Changes in .NET 8.0
As I have mentioned earlier in this article, on the ABP Framework & ABP Commercial sides all the related code changes have been made, so you would not get any error related to breaking changes introduced with .NET 8.0. However, you still need to check the [Breaking Changes in .NET 8.0 documentation](https://learn.microsoft.com/en-us/dotnet/core/compatibility/8.0), because the breaking changes listed in this documentation still might affect you. Therefore, read them accordingly and make the related changes in your application, if needed.
## Update Your Global Dotnet CLI Tools (optional)
You can update the global dotnet tools to the latest version by running the `dotnet tool update` command. For example, if you are using EF Core, you can update your `dotnet-ef` CLI tool with the following command:
```bash
dotnet tool update dotnet-ef --global
```
## Installing/Restoring the Workloads (required for Blazor WASM & MAUI apps)
The `dotnet workload restore` command installs the workloads needed for a project or a solution. This command analyzes a project or solution to determine which workloads are needed and if you have a .NET MAUI or Blazor-WASM project, you can update your workloads by running the following command in a terminal:
```bash
dotnet workload restore
```
## Docker Image Updates
If you are using Docker to automate the deployment of applications, you also need to update your images.
For example, you can update the ASP.NET Core image as follows:
```diff
- FROM mcr.microsoft.com/dotnet/aspnet:7.0-bullseye-slim AS base
+ FROM mcr.microsoft.com/dotnet/aspnet:8.0-bullseye-slim AS base
```
You can check the related images from Docker Hub and update them accordingly:
* [https://hub.docker.com/_/microsoft-dotnet-aspnet/](https://hub.docker.com/_/microsoft-dotnet-aspnet/)
* [https://hub.docker.com/_/microsoft-dotnet-sdk/](https://hub.docker.com/_/microsoft-dotnet-sdk/)
* [https://hub.docker.com/_/microsoft-dotnet-runtime/](https://hub.docker.com/_/microsoft-dotnet-runtime/)
## Upgrading Your Existing Projects to ABP 8.0
Updating your application to ABP 8.0 is pretty straight-forward. You first need to upgrade the ABP CLI to version `8.0.0-rc.1` using a command line terminal:
````bash
dotnet tool update Volo.Abp.Cli -g --version 8.0.0-rc.1
````
**or install** it if you haven't before:
````bash
dotnet tool install Volo.Abp.Cli -g --version 8.0.0-rc.1
````
Then, you can use the `abp update` command to update all the ABP related NuGet and NPM packages in your solution:
```bash
abp update --version 8.0.0-rc.1
```
After that, you need to check the migration guide documents, listed below:
* [ABP Framework 7.x to 8.0 Migration Guide](https://docs.abp.io/en/abp/8.0/Migration-Guides/Abp-8_0)
* [ABP Commercial 7.x to 8.0 Migration Guide](https://docs.abp.io/en/commercial/8.0/migration-guides/v8_0)
> Check these documents carefully and make the related changes in your solution to prevent errors.
## Final Words
That's it! These were all the related steps that need to be taken to upgrade your application to .NET 8 and ABP 8.0. Now, you can enjoy the .NET 8 & ABP 8.0 and benefit from the performance improvements and new features.
Happy Coding 🤗

5
docs/en/Community-Articles/2023-11-97-AOT-Compilation/Post.md

@ -39,7 +39,7 @@ I have created a simple console application to test the Native AOT Compilation.
| | Size | Speed |
| --- | --- | --- |
| --- | --- | --- |
| .NET 8 <br/>_(Self-Contained, Single File)_ | 65938 kb | 00.0051806 ~5ms |
| .NET 7 AOT (default) | 4452 kb | 00.0029823 ~2ms |
| .NET 8 AOT (default) | 1242 kb | 00.0028638 ~2ms |
@ -65,11 +65,8 @@ Always consider the specific needs and constraints of your project before decidi
Native AOT Compilation is a great feature that improves the performance of .NET applications. It's still in early-stages and not all libraries support it yet. But it's a great beginning for the future of .NET 🚀
## Links
- Native AOT deployment overview - .NET | Microsoft Learn. https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/.
-
- Optimize AOT deployments https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/optimizing
-
- What's new in .NET 8 | Microsoft Learn. https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8.

80
docs/en/Dynamic-Claims.md

@ -0,0 +1,80 @@
# Dynamic Claims
## What is Dynamic Claims and Why do we need it
We use claims-based authentication in ASP.NET Core, It will be store the claims in the cookie or token. But the claims are static, it will be not change after the user re-login. If the user changed its username or role, we still get the old claims.
The `Dynamic Claims` feature is used to dynamically generate claims for the user in each request. You can always get the latest user claims.
## How to use it
This feature is disabled by default. You can enable it by following code:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.IsDynamicClaimsEnabled = true;
});
}
````
If you are using the tiered solution you need to set the `RemoteRefreshUrl` to the Auth Server url in the UI project.
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.IsDynamicClaimsEnabled = true;
options.RemoteRefreshUrl = configuration["AuthServerUrl"] + options.RemoteRefreshUrl;
});
}
````
Then add the `DynamicClaims` middleware.
````csharp
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
// Add this line before UseAuthorization.
app.UseDynamicClaims();
app.UseAuthorization();
//...
}
````
## How it works
The `DynamicClaims` middleware will use `IAbpClaimsPrincipalFactory` to dynamically generate claims for the current user(`HttpContext.User`) in each request.
There are two implementations of `IAbpDynamicClaimsPrincipalContributor` for different scenarios.
### IdentityDynamicClaimsPrincipalContributor
This implementation is used for the `Monolithic` solution. It will get the dynamic claims from the `IUserClaimsPrincipalFactory` and add/replace the current user claims.
It uses cache to improve performance. the cache will be invalidated when the user entity changed.
### RemoteDynamicClaimsPrincipalContributor
This implementation is used for the `Tiered` solution. It will get the dynamic claims from the cache of the Auth Server. It will call the `RemoteRefreshUrl` of the Auth Server to refresh the cache when the cache is invalid.
## IAbpDynamicClaimsPrincipalContributor
If you want to add your own dynamic claims contributor, you can a class that implement the `IAbpDynamicClaimsPrincipalContributor` interface. The framework will call the `ContributeAsync` method when get the dynamic claims.
> It better to use cache to improve performance.
## AbpClaimsPrincipalFactoryOptions
* `IsDynamicClaimsEnabled`: Enable or disable the dynamic claims feature.
* `RemoteRefreshUrl`: The url of the Auth Server to refresh the cache. It will be used by the `RemoteDynamicClaimsPrincipalContributor`. The default value is `/api/account/dynamic-claims/refresh`.
* `DynamicClaims`: A list of dynamic claim types, `DynamicClaims contributor`` will only handle the claim type in this list.
* `ClaimsMap`: A dictionary to map the claim types. This is used when the claim types are different between the Auth Server and the client. Already set up for common claim types by default
## See Also
* [Authorization](Authorization.md)
* [Claims-based authorization in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/security/authorization/claims)
* [Mapping, customizing, and transforming claims in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/security/authentication/claims)

343
docs/en/Migration-Guides/Abp-8_0.md

@ -1,77 +1,282 @@
# ABP Version 8.0 Migration Guide
This document is a guide for upgrading ABP v7.4.x solutions to ABP v8.0.x.
This document is a guide for upgrading ABP v7.x solutions to ABP v8.0. There are some changes in this version that may affect your applications, please read it carefully and apply the necessary changes to your application.
> ABP Framework upgraded to .NET 8.0, so you need to move your solutions to .NET 8.0 if you want to use the ABP 8.0. You can check the [Migrate from ASP.NET Core 7.0 to 8.0](https://learn.microsoft.com/en-us/aspnet/core/migration/70-80) documentation.
## Injected the `IDistributedEventBus` Dependency into the `IdentityUserManager`
In this version, `IDistributedEventBus` service has been injected to the `IdentityUserManager` service, to publish a distributed event when the email or username is changed for a user, this was needed because sometimes there may be scenarios where the old email/username is needed for the synchronization purposes.
Therefore, you might need to update the `IdentityUserManager`'s constructor if you have overridden the class and are using it.
> See the issue for more information: https://github.com/abpframework/abp/pull/17990
## Updated Method Signatures in the Bundling System
In this version, ABP Framework introduced the CDN support for bundling. During the development, we have made some improvements on the bundling system and changed some method signatures.
See https://github.com/abpframework/abp/issues/17864 for more information.
## Replaced `IdentityUserLookupAppService` with the `IIdentityUserIntegrationService`
[Integration Services](../Integration-Services.md) are built for module-to-module (or microservice-to-microservice) communication rather than consumed from a UI or a client application as [Application Services](../Application-Services.md) are intended to do.
In that regard, we are discarding the `IIdentityUserLookupAppService` in the Identity Module and moving its functionality to the `IIdentityUserIntegrationService`. Therefore, if you have used that application service directly, use the integration service (`IIdentityUserIntegrationService`) instead. `IIdentityUserLookupAppService` will be removed in thes next versions, so you may need to create a similar service in your application.
> Notice that integration services have no authorization and are not exposed as HTTP API by default.
Also, if you have overridden the `IdentityUserLookupAppService` and `IdentityUserIntegrationService` classes in your application, you should update these classes' constructors as follows:
*IdentityUserLookupAppService.cs*
```csharp
public IdentityUserLookupAppService(IIdentityUserIntegrationService identityUserIntegrationService)
{
IdentityUserIntegrationService = identityUserIntegrationService;
}
```
*IdentityUserIntegrationService.cs*
```diff
public IdentityUserIntegrationService(
IUserRoleFinder userRoleFinder,
+ IdentityUserRepositoryExternalUserLookupServiceProvider userLookupServiceProvider)
{
UserRoleFinder = userRoleFinder;
+ UserLookupServiceProvider = userLookupServiceProvider;
}
```
## MongoDB Event Bus Enhancements
In this version, we have made some enhancements in the transactional inbox/outbox pattern implementation and defined two new methods: `ConfigureEventInbox` and `ConfigureEventOutbox` for MongoDB Event Box collections.
If you call one of these methods in your DbContext class, then this introduces a breaking-change because if you do it, MongoDB collection names will be changed. Therefore, it should be carefully done since existing (non-processed) event records are not automatically moved to new collection and they will be lost. Existing applications with event records should rename the collection manually while deploying their solutions.
See https://github.com/abpframework/abp/pull/17723 for more information. Also, check the documentation for the related configurations: [Distributed Event Bus](../Distributed-Event-Bus.md)
## Moved the CMS Kit Pages Feature's Routing to a `DynamicRouteValueTransformer`
In this version, we have made some improvements in the [CMS Kit's Pages Feature](../Modules/Cms-Kit/Pages.md), such as moving the routing logic to a `DynamicRouteValueTransformer` and etc...
These enhancements led to some breaking changes as listed below that should be taken care of:
* Page routing has been moved to **DynamicRouteValueTransformer**. If you use `{**slug}` pattern in your routing, it might conflict with new CMS Kit routing.
* `PageConsts.UrlPrefix` has been removed, instead, the default prefix is *pages* for now. Still `/pages/{slug}` route works for backward compatibility alongside with `/{slug}` route.
* **Endpoints changed:**
* `api/cms-kit-public/pages/{slug}` endpoint is changed to `api/cms-kit-public/pages/by-slug?slug={slug}`. Now multiple level of page URLs can be used and `/` characters will be transferred as URL Encoded in querysting to the HTTP API.
* `api/cms-kit-public/pages` changed to `api/cms-kit-public/pages/home`
>_CmsKit Client Proxies are updated. If you don't send a **custom request** to this endpoint, **you don't need to take an action**_
## Added Integration Postfix for Auto Controllers
With this version on, the `Integration` suffix from controller names while generating [auto controllers](../API/Auto-API-Controllers.md) are not going to be removed, to differ the integration services from application services in the OpenAPI specification:
![](./images/integration-postfix-not-removed.png)
> This should not affect most of the applications since you normally do not depend on the controller names in the client side.
See https://github.com/abpframework/abp/issues/17625 for more information (how to preserve the existing behaviour, etc...).
## Revised the reCaptcha Generator for CMS Kit's Comment Feature
In this version, we have made improvements on the [CMS Kit's Comment Feature](../Modules/Cms-Kit/Comments.md) and revised the reCaptcha generation process, and made a performance improvement.
This introduced some breaking changes that you should aware of:
* Lifetime of the `SimpleMathsCaptchaGenerator` changed from singleton to transient,
* Changed method signatures for `SimpleMathsCaptchaGenerator` class. (all of its methods are now async)
If you haven't override the comment view component, then you don't need to make any changes, however if you have overriden the component and used the `SimpleMathsCaptchaGenerator` class, then you should make the required changes as described.
## Disabled Logging for `HEAD` HTTP Methods
HTTP GET requests should not make any change in the database normally and audit log system of ABP Framework doesn't save audit log objects for GET requests by default. You can configure the `AbpAuditingOptions` and set the `IsEnabledForGetRequests` to **true** if you want to record _GET_ requests as described in [the documentation](../Audit-Logging.md).
Prior to this version, only the _GET_ requests were not saved as audit logs. From this version on, also the _HEAD_ requests will not be saved as audit logs, if the `IsEnabledForGetRequests` explicitly set as **true**.
You don't need to make any changes related to that, however it's important to know this change.
## Obsolete the `AbpAspNetCoreIntegratedTestBase` Class
In this version, `AbpAspNetCoreAsyncIntegratedTestBase` class has been set as `Obsolete` and it's recommended to use `AbpWebApplicationFactoryIntegratedTest` instead.
## Use NoTracking for readonly repositories for EF core.
In this version, ABP Framework provides read-only [repository](Repositories.md) interfaces (`IReadOnlyRepository<...>` or `IReadOnlyBasicRepository<...>`) to explicitly indicate that your purpose is to query data, but not change it. If so, you can inject these interfaces into your services.
Entity Framework Core read-only repository implementation uses [EF Core's No-Tracking feature](https://learn.microsoft.com/en-us/ef/core/querying/tracking#no-tracking-queries). That means the entities returned from the repository will not be tracked by the EF Core [change tracker](https://learn.microsoft.com/en-us/ef/core/change-tracking/), because it is expected that you won't update entities queried from a read-only repository.
> This behavior works only if the repository object is injected with one of the read-only repository interfaces (`IReadOnlyRepository<...>` or `IReadOnlyBasicRepository<...>`). It won't work if you have injected a standard repository (e.g. `IRepository<...>`) then casted it to a read-only repository interface.
> See the issue for more information: https://github.com/abpframework/abp/pull/17421
## Angular UI
# Guards
From Angular Documentation;
> Class-based **`Route`** guards are deprecated in favor of functional guards.
- Angular has been using functional guards since version 14. According to this situation we have moved our guards to functional guards.
We have modified our modules to adaptate functional guards.
```diff
- import {AuthGuard, PermissionGuard} from '@abp/ng.core';
+ import {authGuard, permissionGuard} from '@abp/ng.core';
- canActivate: mapToCanActivate([AuthGuard, PermissionGuard])
+ canActivate: [authGuard, permissionGuard]
```
You can still use class based guards but we recommend it to use functional guards like us :)
## Upgraded NuGet Dependencies
The following NuGet libraries have been upgraded:
You can see the following list of NuGet libraries that have been upgraded with .NET 8.0 upgrade, if you are using one of these packages explicitly, you may consider upgrading them in your solution:
| Package | Old Version | New Version |
| ------------------- | ----------- | ----------- |
| All Microsoft packages | 7.x | 8.x |
| Microsoft.CodeAnalysis | 4.2.0 | 4.5.0 |
| NUglify | 1.20.0 | 1.21.0 |
| Polly | 7.2.3 | 8.0.0 |
| aliyun-net-sdk-sts | 3.1.0 | 3.1.1 |
| Autofac | 7.0.0 | 7.1.0 |
| Autofac.Extras.DynamicProxy | 6.0.1 | 7.1.0 |
| AutoMapper | 12.0.0 | 12.0.1 |
| AsyncKeyedLock | 6.2.1 | 6.2.2 |
| AWSSDK.S3 | 3.7.9.2 | 3.7.205.9 |
| AWSSDK.SecurityToken | 3.7.1.151 | 3.7.202.4 |
| Azure.Storage.Blobs | 12.15.0 | 12.18.0 |
| ConfigureAwait.Fody | 3.3.1 | 3.3.2 |
| Confluent.Kafka | 1.8.2 | 2.2.0 |
| Dapper | 2.0.123 | 2.1.4 |
| Dapr.Client | 1.11.0 | 1.9.0 |
| DistributedLock.Core | 1.0.4 | 1.0.5 |
| DistributedLock.Redis | 1.0.1 | 1.0.2 |
| EphemeralMongo.Core | 1.1.0 | 1.1.3 |
| EphemeralMongo6.runtime.linux-x64 | 1.1.0 | 1.1.3 |
| EphemeralMongo6.runtime.osx-x64 | 1.1.0 | 1.1.3 |
| EphemeralMongo6.runtime.win-x64 | 1.1.0 | 1.1.3 |
| FluentValidation | 11.0.1 | 11.7.1 |
| Fody | 6.6.1 | 6.8.0 |
| Hangfire.AspNetCore | 1.8.2 | 1.8.5 |
| Hangfire.SqlServer | 1.8.2 | 1.8.5 |
| HtmlSanitizer | 5.0.331 | 8.0.723 |
| IdentityModel | 6.0.0 | 6.2.0 |
| IdentityServer4.AspNetIdentity | 4.1.1 | 4.1.2 |
| JetBrains.Annotations | 2022.1.0 | 2023.2.0 |
| LibGit2Sharp | 0.26.2 | 0.27.2 |
| Magick.NET-Q16-AnyCPU | 13.2.0 | 13.3.0 |
| MailKit | 3.2.0 | 4.2.0 |
| Markdig.Signed | 0.26.0 | 0.33.0 |
| Microsoft.AspNetCore.Mvc.Versioning | 5.0.0 | 5.1.0 |
| Microsoft.AspNetCore.Razor.Language | 6.0.8 | 6.0.22 |
| Microsoft.NET.Test.Sdk | 17.2.0 | 17.7.2 |
| Minio | 4.0.6 | 6.0.0 |
| MongoDB.Driver | 2.19.1 | 2.21.0 |
| NEST | 7.14.1 | 7.17.5 |
| Newtonsoft.Json | 13.0.1 | 13.0.3 |
| NSubstitute | 4.3.0 | 5.1.0 |
| NSubstitute.Analyzers.CSharp | 1.0.15 | 1.0.16 |
| NuGet.Versioning | 5.11.0 | 6.7.0 |
| Octokit | 0.50.0 | 8.0.1 |
| Quartz | 3.4.0 | 3.7.0 |
| Quartz.Extensions.DependencyInjection | 3.4.0 | 3.7.0 |
| Quartz.Plugins.TimeZoneConverter | 3.4.0 | 3.7.0 |
| RabbitMQ.Client | 6.3.0 | 6.5.0 |
| Rebus | 6.6.5 | 7.2.1 |
| Rebus.ServiceProvider | 7.0.0 | 9.1.0 |
| Scriban | 5.4.4 | 5.9.0 |
| Serilog.AspNetCore | 5.0.0 | 7.0.0 |
| Serilog.Extensions.Hosting | 3.1.0 | 7.0.0 |
| Serilog.Extensions.Logging | 3.1.0 | 7.0.0 |
| Serilog.Sinks.Async | 1.4.0 | 1.5.0 |
| SharpZipLib | 1.3.3 | 1.4.2 |
| Shouldly | 4.1.0 | 4.2.1 |
| SixLabors.ImageSharp | 1.0.4 | 3.0.2 |
| Slugify.Core | 3.0.0 | 4.0.1 |
| Spectre.Console | 0.46.1-preview.0.7 | 0.47.0 |
| Swashbuckle.AspNetCore | 6.2.1 | 6.5.0 |
| System.Linq.Dynamic.Core | 1.3.3 | 1.3.5 |
| TimeZoneConverter | 5.0.0 | 6.1.0 |
| xunit | 2.4.1 | 2.5.1 |
| xunit.extensibility.execution | 2.4.1 | 2.5.1 |
| xunit.runner.visualstudio | 2.4.5 | 2.5.1 |
| aliyun-net-sdk-sts | 3.1.0 | 3.1.2 |
| AsyncKeyedLock | 6.2.1 | 6.2.2 |
| Autofac | 7.0.0 | 7.1.0 |
| Autofac.Extras.DynamicProxy | 6.0.1 | 7.1.0 |
| AutoMapper | 12.0.0 | 12.0.1 |
| AWSSDK.S3 | 3.7.9.2 | 3.7.300.2 |
| AWSSDK.SecurityToken | 3.7.1.151 | 3.7.300.2 |
| Azure.Messaging.ServiceBus | 7.8.1 | 7.17.0 |
| Azure.Storage.Blobs | 12.15.0 | 12.19.1 |
| Blazorise | 1.3.1 | 1.3.2 |
| Blazorise.Bootstrap5 | 1.3.1 | 1.3.2 |
| Blazorise.Icons.FontAwesome | 1.3.1 | 1.3.2 |
| Blazorise.Components | 1.3.1 | 1.3.2 |
| Blazorise.DataGrid | 1.3.1 | 1.3.2 |
| Blazorise.Snackbar | 1.3.1 | 1.3.2 |
| Confluent.Kafka | 1.8.2 | 2.3.0 |
| Dapper | 2.0.123 | 2.1.21 |
| Dapr.AspNetCore | 1.9.0 | 1.12.0 |
| Dapr.Client | 1.9.0 | 1.12.0 |
| Devart.Data.Oracle.EFCore | 10.1.134.7 | 10.1.151.7 |
| DistributedLock.Core | 1.0.4 | 1.0.5 |
| DistributedLock.Redis | 1.0.1 | 1.0.2 |
| EphemeralMongo.Core | 1.1.0 | 1.1.3 |
| EphemeralMongo6.runtime.linux-x64 | 1.1.0 | 1.1.3 |
| EphemeralMongo6.runtime.osx-x64 | 1.1.0 | 1.1.3 |
| EphemeralMongo6.runtime.win-x64 | 1.1.0 | 1.1.3 |
| FluentValidation | 11.0.1 | 11.8.0 |
| Hangfire.AspNetCore | 1.8.2 | 1.8.6 |
| Hangfire.SqlServer | 1.8.2 | 1.8.6 |
| HtmlSanitizer | 5.0.331 | 8.0.746 |
| HtmlAgilityPack | 1.11.42 | 1.11.54 |
| IdentityModel | 6.0.0 | 6.2.0 |
| IdentityServer4.AspNetIdentity | 4.1.1 | 4.1.2 |
| JetBrains.Annotations | 2022.1.0 | 2023.3.0 |
| LibGit2Sharp | 0.26.2 | 0.28.0 |
| Magick.NET-Q16-AnyCPU | 13.2.0 | 13.4.0 |
| MailKit | 3.2.0 | 4.3.0 |
| Markdig.Signed | 0.26.0 | 0.33.0 |
| Microsoft.AspNetCore.Authentication.JwtBearer | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.Authentication.OpenIdConnect | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.Authorization | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.Components | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.Components.Authorization | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.Components.Web | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.Components.WebAssembly | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.Components.WebAssembly.Authentication | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.Components.WebAssembly.DevServer | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.Components.WebAssembly.Server | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.DataProtection.StackExchangeRedis | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.Mvc.NewtonsoftJson | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.Mvc.Versioning | 5.0.0 | 5.1.0 |
| Microsoft.AspNetCore.Razor.Language | 6.0.8 | 6.0.25 |
| Microsoft.AspNetCore.TestHost | 7.0.10 | 8.0.0 |
| Microsoft.AspNetCore.WebUtilities | 2.2.0 | 8.0.0 |
| Microsoft.Bcl.AsyncInterfaces | 7.0.0 | 8.0.0 |
| Microsoft.CodeAnalysis.CSharp | 4.2.0 | 4.5.0 |
| Microsoft.Data.Sqlite | 7.0.0 | 8.0.0 |
| Microsoft.EntityFrameworkCore | 7.0.10 | 8.0.0 |
| Microsoft.EntityFrameworkCore.Design | 7.0.0 | 8.0.0 |
| Microsoft.EntityFrameworkCore.InMemory | 7.0.10 | 8.0.0 |
| Microsoft.EntityFrameworkCore.Proxies | 7.0.10 | 8.0.0 |
| Microsoft.EntityFrameworkCore.Relational | 7.0.10 | 8.0.0 |
| Microsoft.EntityFrameworkCore.Sqlite | 7.0.10 | 8.0.0 |
| Microsoft.EntityFrameworkCore.SqlServer | 7.0.0 | 8.0.0 |
| Microsoft.EntityFrameworkCore.Tools | 7.0.1 | 8.0.0 |
| Microsoft.Extensions.Caching.Memory | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Caching.StackExchangeRedis | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Configuration.Binder | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Configuration.CommandLine | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Configuration.EnvironmentVariables | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Configuration.UserSecrets | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.DependencyInjection | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.DependencyInjection.Abstractions | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.FileProviders.Composite | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.FileProviders.Embedded | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.FileProviders.Physical | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.FileSystemGlobbing | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Hosting | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Hosting.Abstractions | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Http | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Http.Polly| 7.0.10 | 8.0.0 |
| Microsoft.Extensions.Identity.Core | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Localization | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Logging | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Logging.Console | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Options | 7.0.0 | 8.0.0 |
| Microsoft.Extensions.Options.ConfigurationExtensions | 7.0.0 | 8.0.0 |
| Microsoft.NET.Test.Sdk | 17.2.0 | 17.8.0 |
| Microsoft.VisualStudio.Web.CodeGeneration.Design | 7.0.0 | 8.0.0 |
| Minio | 4.0.6 | 6.0.1 |
| MongoDB.Driver | 2.19.1 | 2.22.0 |
| NEST | 7.14.1 | 7.17.5 |
| Newtonsoft.Json | 13.0.1 | 13.0.3 |
| NSubstitute | 4.3.0 | 5.1.0 |
| NuGet.Versioning | 5.11.0 | 6.7.0 |
| NUglify | 1.20.0 | 1.21.0 |
| Npgsql.EntityFrameworkCore.PostgreSQL | 7.0.0 | 8.0.0-rc.2 |
| NSubstitute.Analyzers.CSharp | 1.0.15 | 1.0.16 |
| Octokit | 0.50.0 | 9.0.0 |
| OpenIddict.Abstractions | 4.8.0 | 4.10.0 |
| OpenIddict.Core | 4.8.0 | 4.10.0 |
| OpenIddict.Server.AspNetCore | 4.8.0 | 4.10.0 |
| OpenIddict.Validation.AspNetCore | 4.8.0 | 4.10.0 |
| OpenIddict.Validation.ServerIntegration | 4.8.0 | 4.10.0 |
| Oracle.EntityFrameworkCore | 7.21.8 | 7.21.12 |
| Polly | 7.2.3 | 8.2.0 |
| Pomelo.EntityFrameworkCore.MySql | 7.0.0 | 8.0.0-beta.1 |
| Quartz | 3.4.0 | 3.7.0 |
| Quartz.Extensions.DependencyInjection | 3.4.0 | 3.7.0 |
| Quartz.Plugins.TimeZoneConverter | 3.4.0 | 3.7.0 |
| Quartz.Serialization.Json | 3.3.3 | 3.7.0 |
| RabbitMQ.Client | 6.3.0 | 6.6.0 |
| Rebus | 6.6.5 | 7.2.1 |
| Rebus.ServiceProvider | 7.0.0 | 9.1.0 |
| Scriban | 5.4.4 | 5.9.0 |
| Serilog | 2.11.0 | 3.1.1 |
| Serilog.AspNetCore | 5.0.0 | 8.0.0 |
| Serilog.Extensions.Hosting | 3.1.0 | 8.0.0 |
| Serilog.Extensions.Logging | 3.1.0 | 8.0.0 |
| Serilog.Sinks.Async | 1.4.0 | 1.5.0 |
| Serilog.Sinks.Console | 3.1.1 | 5.0.0 |
| Serilog.Sinks.File | 4.1.0 | 5.0.0 |
| SharpZipLib | 1.3.3 | 1.4.2 |
| Shouldly | 4.0.3 | 4.2.1 |
| SixLabors.ImageSharp.Drawing | 2.0.0 | 2.0.1 |
| Slugify.Core | 3.0.0 | 4.0.1 |
| StackExchange.Redis | 2.6.122 | 2.7.4 |
| Swashbuckle.AspNetCore | 6.2.1 | 6.5.0 |
| System.Collections.Immutable | 7.0.0 | 8.0.0 |
| System.Linq.Dynamic.Core | 1.3.3 | 1.3.5 |
| System.Security.Permissions | 7.0.0 | 8.0.0 |
| System.Text.Encoding.CodePages | 7.0.0 | 8.0.0 |
| System.Text.Encodings.Web | 7.0.0 | 8.0.0 |
| System.Text.Json | 7.0.0 | 8.0.0 |
| TimeZoneConverter | 5.0.0 | 6.1.0 |
| xunit | 2.4.1 | 2.6.1 |
| xunit.extensibility.execution | 2.4.1 | 2.6.1 |
| xunit.runner.visualstudio | 2.4.5 | 2.5.3 |

1
docs/en/Migration-Guides/Index.md

@ -2,6 +2,7 @@
The following documents explain how to migrate your existing ABP applications. We write migration documents only if you need to take an action while upgrading your solution. Otherwise, you can easily upgrade your solution using the [abp update command](../Upgrading.md).
- [7.x to 8.0](Abp-8_0.md)
- [7.3 to 7.4](Abp-7_4.md)
- [7.2 to 7.3](Abp-7_3.md)
- [7.1 to 7.2](Abp-7_2.md)

BIN
docs/en/Migration-Guides/images/integration-postfix-not-removed.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

8
docs/en/docs-nav.json

@ -178,7 +178,13 @@
},
{
"text": "Authorization",
"path": "Authorization.md"
"path": "Authorization.md",
"items": [
{
"text": "Dynamic Claims",
"path": "Dynamic-Claims.md"
}
]
},
{
"text": "Caching",

14
framework/Volo.Abp.sln

@ -459,6 +459,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Imaging.AspNetCore
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Maui.Client", "src\Volo.Abp.Maui.Client\Volo.Abp.Maui.Client.csproj", "{F19A6E0C-F719-4ED9-A024-14E4B8D40883}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Imaging.SkiaSharp", "src\Volo.Abp.Imaging.SkiaSharp\Volo.Abp.Imaging.SkiaSharp.csproj", "{198683D0-7DC6-40F2-B81B-8E446E70A9DE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Imaging.SkiaSharp.Tests", "test\Volo.Abp.Imaging.SkiaSharp.Tests\Volo.Abp.Imaging.SkiaSharp.Tests.csproj", "{DFAF8763-D1D6-4EB4-B459-20E31007FE2F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -1369,6 +1373,14 @@ Global
{F19A6E0C-F719-4ED9-A024-14E4B8D40883}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F19A6E0C-F719-4ED9-A024-14E4B8D40883}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F19A6E0C-F719-4ED9-A024-14E4B8D40883}.Release|Any CPU.Build.0 = Release|Any CPU
{198683D0-7DC6-40F2-B81B-8E446E70A9DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{198683D0-7DC6-40F2-B81B-8E446E70A9DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{198683D0-7DC6-40F2-B81B-8E446E70A9DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{198683D0-7DC6-40F2-B81B-8E446E70A9DE}.Release|Any CPU.Build.0 = Release|Any CPU
{DFAF8763-D1D6-4EB4-B459-20E31007FE2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DFAF8763-D1D6-4EB4-B459-20E31007FE2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DFAF8763-D1D6-4EB4-B459-20E31007FE2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DFAF8763-D1D6-4EB4-B459-20E31007FE2F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1600,6 +1612,8 @@ Global
{62B2B8C9-8F24-4D31-894F-C1F0728D32AB} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{983B0136-384B-4439-B374-31111FFAA286} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{F19A6E0C-F719-4ED9-A024-14E4B8D40883} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{198683D0-7DC6-40F2-B81B-8E446E70A9DE} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{DFAF8763-D1D6-4EB4-B459-20E31007FE2F} = {447C8A77-E5F0-4538-8687-7383196D04EA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

7
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Security/AbpComponentsClaimsCache.cs

@ -1,9 +1,9 @@
using System.Security.Claims;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Components.Web.Security;
@ -12,16 +12,18 @@ public class AbpComponentsClaimsCache : IScopedDependency
public ClaimsPrincipal Principal { get; private set; } = default!;
private readonly AuthenticationStateProvider? _authenticationStateProvider;
private readonly IAbpClaimsPrincipalFactory _abpClaimsPrincipalFactory;
public AbpComponentsClaimsCache(
IClientScopeServiceProviderAccessor serviceProviderAccessor)
{
_authenticationStateProvider = serviceProviderAccessor.ServiceProvider.GetService<AuthenticationStateProvider>();
_abpClaimsPrincipalFactory = serviceProviderAccessor.ServiceProvider.GetRequiredService<IAbpClaimsPrincipalFactory>();
if (_authenticationStateProvider != null)
{
_authenticationStateProvider.AuthenticationStateChanged += async (task) =>
{
Principal = (await task).User;
Principal = await _abpClaimsPrincipalFactory.CreateDynamicAsync((await task).User);
};
}
}
@ -32,6 +34,7 @@ public class AbpComponentsClaimsCache : IScopedDependency
{
var authenticationState = await _authenticationStateProvider.GetAuthenticationStateAsync();
Principal = authenticationState.User;
await _abpClaimsPrincipalFactory.CreateDynamicAsync(Principal);
}
}
}

44
framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributor.cs

@ -0,0 +1,44 @@
using System;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Mvc.Client;
public class RemoteDynamicClaimsPrincipalContributor : AbpDynamicClaimsPrincipalContributorBase
{
public async override Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var identity = context.ClaimsPrincipal.Identities.FirstOrDefault();
if (identity == null)
{
return;
}
var userId = identity.FindUserId();
if (userId == null)
{
return;
}
var dynamicClaimsCache = context.GetRequiredService<RemoteDynamicClaimsPrincipalContributorCache>();
AbpDynamicClaimCacheItem dynamicClaims;
try
{
dynamicClaims = await dynamicClaimsCache.GetAsync(userId.Value, identity.FindTenantId());
}
catch (Exception e)
{
// In case if failed refresh remote dynamic cache, We force to clear the claims principal.
context.ClaimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity());
var logger = context.GetRequiredService<ILogger<RemoteDynamicClaimsPrincipalContributor>>();
logger.LogWarning(e, $"Failed to refresh remote dynamic claims cache for user: {userId.Value}");
return;
}
await AddDynamicClaimsAsync(context, identity, dynamicClaims.Claims);
}
}

72
framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributorCache.cs

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Client.Authentication;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Mvc.Client;
public class RemoteDynamicClaimsPrincipalContributorCache : ITransientDependency
{
public const string HttpClientName = nameof(RemoteDynamicClaimsPrincipalContributorCache);
public ILogger<RemoteDynamicClaimsPrincipalContributorCache> Logger { get; set; }
protected IDistributedCache<AbpDynamicClaimCacheItem> Cache { get; }
protected IHttpClientFactory HttpClientFactory { get; }
protected IOptions<AbpClaimsPrincipalFactoryOptions> AbpClaimsPrincipalFactoryOptions { get; }
protected IRemoteServiceHttpClientAuthenticator HttpClientAuthenticator { get; }
public RemoteDynamicClaimsPrincipalContributorCache(
IDistributedCache<AbpDynamicClaimCacheItem> cache,
IHttpClientFactory httpClientFactory,
IOptions<AbpClaimsPrincipalFactoryOptions> abpClaimsPrincipalFactoryOptions,
IRemoteServiceHttpClientAuthenticator httpClientAuthenticator)
{
Cache = cache;
HttpClientFactory = httpClientFactory;
AbpClaimsPrincipalFactoryOptions = abpClaimsPrincipalFactoryOptions;
HttpClientAuthenticator = httpClientAuthenticator;
Logger = NullLogger<RemoteDynamicClaimsPrincipalContributorCache>.Instance;
}
public virtual async Task<AbpDynamicClaimCacheItem> GetAsync(Guid userId, Guid? tenantId = null)
{
Logger.LogDebug($"Get dynamic claims cache for user: {userId}");
var dynamicClaims = await Cache.GetAsync(AbpDynamicClaimCacheItem.CalculateCacheKey(userId, tenantId));
if (dynamicClaims != null && !dynamicClaims.Claims.IsNullOrEmpty())
{
return dynamicClaims;
}
Logger.LogDebug($"Refresh dynamic claims for user: {userId} from remote service.");
try
{
var client = HttpClientFactory.CreateClient(HttpClientName);
var requestMessage = new HttpRequestMessage(HttpMethod.Post, AbpClaimsPrincipalFactoryOptions.Value.RemoteRefreshUrl);
await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client, requestMessage, new RemoteServiceConfiguration("/"), string.Empty));
var response = await client.SendAsync(requestMessage);
response.EnsureSuccessStatusCode();
}
catch (Exception e)
{
Logger.LogWarning(e, $"Failed to refresh remote claims for user: {userId}");
throw;
}
dynamicClaims = await Cache.GetAsync(AbpDynamicClaimCacheItem.CalculateCacheKey(userId, tenantId));
if (dynamicClaims == null || dynamicClaims.Claims.IsNullOrEmpty())
{
throw new AbpException($"Failed to refresh remote claims for user: {userId}");
}
return dynamicClaims!;
}
}

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

@ -26,6 +26,7 @@ public class AbpDynamicFormTagHelperService : AbpTagHelperService<AbpDynamicForm
private readonly IHtmlGenerator _htmlGenerator;
private readonly IServiceProvider _serviceProvider;
private readonly IStringLocalizer<AbpUiResource> _localizer;
private List<ModelExpression> _models = new();
public AbpDynamicFormTagHelperService(
HtmlEncoder htmlEncoder,
@ -41,6 +42,7 @@ public class AbpDynamicFormTagHelperService : AbpTagHelperService<AbpDynamicForm
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
_models = GetModels(context, output);
var list = InitilizeFormGroupContentsContext(context, output);
NormalizeTagMode(context, output);
@ -157,9 +159,7 @@ public class AbpDynamicFormTagHelperService : AbpTagHelperService<AbpDynamicForm
protected virtual async Task ProcessFieldsAsync(TagHelperContext context, TagHelperOutput output)
{
var models = GetModels(context, output);
foreach (var model in models)
foreach (var model in _models)
{
if (IsSelectGroup(context, model))
{
@ -225,7 +225,7 @@ public class AbpDynamicFormTagHelperService : AbpTagHelperService<AbpDynamicForm
private bool TryToGetOtherDateModel(ModelExpression model, string pickerId, out ModelExplorer? otherModel)
{
otherModel = TagHelper.Model.ModelExplorer.Properties.SingleOrDefault(x => x != model.ModelExplorer && x.GetAttribute<DateRangePickerAttribute>()?.PickerId == pickerId);
otherModel = _models.Select(x => x.ModelExplorer).SingleOrDefault(x => x != model.ModelExplorer && x.GetAttribute<DateRangePickerAttribute>()?.PickerId == pickerId);
return otherModel != null;
}

61
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleFile.cs

@ -2,11 +2,11 @@ using System;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
public class BundleFile
public class BundleFile : IEquatable<BundleFile>, IComparable<BundleFile>
{
public string FileName { get; set; }
public string FileName { get; }
public bool IsExternalFile { get; set; }
public bool IsExternalFile { get; }
public BundleFile(string fileName)
{
@ -28,4 +28,59 @@ public class BundleFile
{
return new BundleFile(fileName);
}
public bool Equals(BundleFile? other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return FileName == other.FileName;
}
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != this.GetType())
{
return false;
}
return Equals((BundleFile)obj);
}
public override int GetHashCode()
{
return FileName.GetHashCode();
}
public int CompareTo(BundleFile? other)
{
if (ReferenceEquals(this, other))
{
return 0;
}
if (ReferenceEquals(null, other))
{
return 1;
}
return string.Compare(FileName, other.FileName, StringComparison.Ordinal);
}
}

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

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
@ -61,12 +61,12 @@ public abstract class ChallengeAccountController : AbpController
}
[HttpGet]
public virtual Task<IActionResult> AccessDenied(string returnUrl = "", string returnUrlHash = "")
public virtual Task<IActionResult> AccessDenied()
{
return Task.FromResult<IActionResult>(Challenge(
new AuthenticationProperties
{
RedirectUri = GetRedirectUrl(returnUrl, returnUrlHash)
RedirectUri = "/"
},
(ForbidSchemes.IsNullOrEmpty()
? new[]

5
framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs

@ -111,4 +111,9 @@ public static class AbpApplicationBuilderExtensions
{
return app.UseMiddleware<AbpSecurityHeadersMiddleware>();
}
public static IApplicationBuilder UseDynamicClaims(this IApplicationBuilder app)
{
return app.UseMiddleware<AbpDynamicClaimsMiddleware>();
}
}

25
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpDynamicClaimsMiddleware.cs

@ -0,0 +1,25 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Security.Claims;
public class AbpDynamicClaimsMiddleware : IMiddleware, ITransientDependency
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
if (context.User.Identity?.IsAuthenticated == true)
{
if (context.RequestServices.GetRequiredService<IOptions<AbpClaimsPrincipalFactoryOptions>>().Value.IsDynamicClaimsEnabled)
{
var abpClaimsPrincipalFactory = context.RequestServices.GetRequiredService<IAbpClaimsPrincipalFactory>();
context.User = await abpClaimsPrincipalFactory.CreateDynamicAsync(context.User);
}
}
await next(context);
}
}

1
framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj

@ -21,6 +21,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" VersionOverride="7.0.14" />
<PackageReference Include="Devart.Data.Oracle.EFCore" />
</ItemGroup>

3
framework/src/Volo.Abp.EventBus.Rebus/Volo.Abp.EventBus.Rebus.csproj

@ -21,6 +21,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Text.Json" VersionOverride="7.0.4" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
<PackageReference Include="Rebus" />
<PackageReference Include="Rebus.ServiceProvider" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />

3
framework/src/Volo.Abp.Imaging.SkiaSharp/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.Imaging.SkiaSharp/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>

28
framework/src/Volo.Abp.Imaging.SkiaSharp/Volo.Abp.Imaging.SkiaSharp.csproj

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<PackageId>Volo.Abp.Imaging.SkiaSharp</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.Imaging.Abstractions\Volo.Abp.Imaging.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SkiaSharp" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
<PackageReference Include="SkiaSharp.NativeAssets.macOS" Condition="$([MSBuild]::IsOSPlatform('OSX'))" />
</ItemGroup>
</Project>

8
framework/src/Volo.Abp.Imaging.SkiaSharp/Volo/Abp/Imaging/AbpImagingSkiaSharpModule.cs

@ -0,0 +1,8 @@
using Volo.Abp.Modularity;
namespace Volo.Abp.Imaging;
[DependsOn(typeof(AbpImagingAbstractionsModule))]
public class AbpImagingSkiaSharpModule : AbpModule
{
}

98
framework/src/Volo.Abp.Imaging.SkiaSharp/Volo/Abp/Imaging/SkiaSharpImageResizerContributor.cs

@ -0,0 +1,98 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using SkiaSharp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http;
namespace Volo.Abp.Imaging;
public class SkiaSharpImageResizerContributor : IImageResizerContributor, ITransientDependency
{
protected SkiaSharpResizerOptions Options { get; }
public SkiaSharpImageResizerContributor(IOptions<SkiaSharpResizerOptions> options)
{
Options = options.Value;
}
public virtual async Task<ImageResizeResult<byte[]>> TryResizeAsync(byte[] bytes, ImageResizeArgs resizeArgs, string? mimeType = null, CancellationToken cancellationToken = default)
{
if (!mimeType.IsNullOrWhiteSpace() && !CanResize(mimeType))
{
return new ImageResizeResult<byte[]>(bytes, ImageProcessState.Unsupported);
}
using (var memoryStream = new MemoryStream(bytes))
{
var result = await TryResizeAsync(memoryStream, resizeArgs, mimeType, cancellationToken);
if (result.State != ImageProcessState.Done)
{
return new ImageResizeResult<byte[]>(bytes, result.State);
}
var newBytes = await result.Result.GetAllBytesAsync(cancellationToken);
result.Result.Dispose();
return new ImageResizeResult<byte[]>(newBytes, result.State);
}
}
public virtual async Task<ImageResizeResult<Stream>> TryResizeAsync(Stream stream, ImageResizeArgs resizeArgs, string? mimeType = null, CancellationToken cancellationToken = default)
{
if (!mimeType.IsNullOrWhiteSpace() && !CanResize(mimeType))
{
return new ImageResizeResult<Stream>(stream, ImageProcessState.Unsupported);
}
var (memoryBitmapStream, memorySkCodecStream) = await CreateMemoryStream(stream);
using (var original = SKBitmap.Decode(memoryBitmapStream))
{
using (var resized = original.Resize(new SKImageInfo(resizeArgs.Width, resizeArgs.Height), Options.SKFilterQuality))
{
using (var image = SKImage.FromBitmap(resized))
{
using (var codec = SKCodec.Create(memorySkCodecStream))
{
var memoryStream = new MemoryStream();
image.Encode(codec.EncodedFormat, Options.Quality).SaveTo(memoryStream);
return new ImageResizeResult<Stream>(memoryStream, ImageProcessState.Done);
}
}
}
}
}
protected virtual async Task<(MemoryStream, MemoryStream)> CreateMemoryStream(Stream stream)
{
var streamPosition = stream.Position;
var memoryBitmapStream = new MemoryStream();
var memorySkCodecStream = new MemoryStream();
await stream.CopyToAsync(memoryBitmapStream);
stream.Position = streamPosition;
await stream.CopyToAsync(memorySkCodecStream);
stream.Position = streamPosition;
memoryBitmapStream.Position = 0;
memorySkCodecStream.Position = 0;
return (memoryBitmapStream, memorySkCodecStream);
}
protected virtual bool CanResize(string? mimeType)
{
return mimeType switch {
MimeTypes.Image.Jpeg => true,
MimeTypes.Image.Png => true,
MimeTypes.Image.Webp => true,
_ => false
};
}
}

16
framework/src/Volo.Abp.Imaging.SkiaSharp/Volo/Abp/Imaging/SkiaSharpResizerOptions.cs

@ -0,0 +1,16 @@
using SkiaSharp;
namespace Volo.Abp.Imaging;
public class SkiaSharpResizerOptions
{
public SKFilterQuality SKFilterQuality { get; set; }
public int Quality { get; set; }
public SkiaSharpResizerOptions()
{
SKFilterQuality = SKFilterQuality.None;
Quality = 75;
}
}

14
framework/src/Volo.Abp.Security/System/Security/Principal/AbpClaimsIdentityExtensions.cs

@ -238,6 +238,19 @@ public static class AbpClaimsIdentityExtensions
return claimsIdentity;
}
public static ClaimsIdentity RemoveAll(this ClaimsIdentity claimsIdentity, string claimType)
{
Check.NotNull(claimsIdentity, nameof(claimsIdentity));
foreach (var x in claimsIdentity.FindAll(claimType).ToList())
{
claimsIdentity.RemoveClaim(x);
}
return claimsIdentity;
}
public static ClaimsIdentity AddOrReplace(this ClaimsIdentity claimsIdentity, Claim claim)
{
Check.NotNull(claimsIdentity, nameof(claimsIdentity));
@ -263,5 +276,4 @@ public static class AbpClaimsIdentityExtensions
return principal;
}
}

8
framework/src/Volo.Abp.Security/Volo/Abp/Security/AbpSecurityModule.cs

@ -59,9 +59,11 @@ public class AbpSecurityModule : AbpModule
});
}
private static void AutoAddClaimsPrincipalContributors(IServiceCollection services)
{
var contributorTypes = new List<Type>();
var dynamicContributorTypes = new List<Type>();
services.OnRegistered(context =>
{
@ -69,11 +71,17 @@ public class AbpSecurityModule : AbpModule
{
contributorTypes.Add(context.ImplementationType);
}
if (typeof(IAbpDynamicClaimsPrincipalContributor).IsAssignableFrom(context.ImplementationType))
{
dynamicContributorTypes.Add(context.ImplementationType);
}
});
services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.Contributors.AddIfNotContains(contributorTypes);
options.DynamicContributors.AddIfNotContains(dynamicContributorTypes);
});
}
}

10
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalContributorContext.cs

@ -1,13 +1,14 @@
using System;
using System.Security.Claims;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
namespace Volo.Abp.Security.Claims;
public class AbpClaimsPrincipalContributorContext
{
[NotNull]
public ClaimsPrincipal ClaimsPrincipal { get; }
public ClaimsPrincipal ClaimsPrincipal { get; set; }
[NotNull]
public IServiceProvider ServiceProvider { get; }
@ -19,4 +20,11 @@ public class AbpClaimsPrincipalContributorContext
ClaimsPrincipal = claimsIdentity;
ServiceProvider = serviceProvider;
}
public virtual T GetRequiredService<T>()
where T : notnull
{
Check.NotNull(ServiceProvider, nameof(ServiceProvider));
return ServiceProvider.GetRequiredService<T>();
}
}

29
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactory.cs

@ -22,6 +22,16 @@ public class AbpClaimsPrincipalFactory : IAbpClaimsPrincipalFactory, ITransientD
}
public virtual async Task<ClaimsPrincipal> CreateAsync(ClaimsPrincipal? existsClaimsPrincipal = null)
{
return await InternalCreateAsync(Options, existsClaimsPrincipal, false);
}
public virtual async Task<ClaimsPrincipal> CreateDynamicAsync(ClaimsPrincipal? existsClaimsPrincipal = null)
{
return await InternalCreateAsync(Options, existsClaimsPrincipal, true);
}
public virtual async Task<ClaimsPrincipal> InternalCreateAsync(AbpClaimsPrincipalFactoryOptions options, ClaimsPrincipal? existsClaimsPrincipal = null, bool isDynamic = false)
{
using (var scope = ServiceScopeFactory.CreateScope())
{
@ -32,13 +42,24 @@ public class AbpClaimsPrincipalFactory : IAbpClaimsPrincipalFactory, ITransientD
var context = new AbpClaimsPrincipalContributorContext(claimsPrincipal, scope.ServiceProvider);
foreach (var contributorType in Options.Contributors)
if (!isDynamic)
{
foreach (var contributorType in options.Contributors)
{
var contributor = (IAbpClaimsPrincipalContributor)scope.ServiceProvider.GetRequiredService(contributorType);
await contributor.ContributeAsync(context);
}
}
else
{
var contributor = (IAbpClaimsPrincipalContributor)scope.ServiceProvider.GetRequiredService(contributorType);
await contributor.ContributeAsync(context);
foreach (var contributorType in options.DynamicContributors)
{
var contributor = (IAbpDynamicClaimsPrincipalContributor)scope.ServiceProvider.GetRequiredService(contributorType);
await contributor.ContributeAsync(context);
}
}
return claimsPrincipal;
return context.ClaimsPrincipal;
}
}
}

40
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactoryOptions.cs

@ -1,4 +1,6 @@
using Volo.Abp.Collections;
using System.Collections.Generic;
using System.Security.Claims;
using Volo.Abp.Collections;
namespace Volo.Abp.Security.Claims;
@ -6,8 +8,44 @@ public class AbpClaimsPrincipalFactoryOptions
{
public ITypeList<IAbpClaimsPrincipalContributor> Contributors { get; }
public ITypeList<IAbpDynamicClaimsPrincipalContributor> DynamicContributors { get; }
public List<string> DynamicClaims { get; }
public string RemoteRefreshUrl { get; set; }
public Dictionary<string, List<string>> ClaimsMap { get; set; }
public bool IsDynamicClaimsEnabled { get; set; }
public AbpClaimsPrincipalFactoryOptions()
{
Contributors = new TypeList<IAbpClaimsPrincipalContributor>();
DynamicContributors = new TypeList<IAbpDynamicClaimsPrincipalContributor>();
DynamicClaims = new List<string>
{
AbpClaimTypes.UserName,
AbpClaimTypes.Name,
AbpClaimTypes.SurName,
AbpClaimTypes.Role,
AbpClaimTypes.Email,
AbpClaimTypes.EmailVerified,
AbpClaimTypes.PhoneNumber,
AbpClaimTypes.PhoneNumberVerified
};
RemoteRefreshUrl = "/api/account/dynamic-claims/refresh";
ClaimsMap = new Dictionary<string, List<string>>()
{
{ AbpClaimTypes.UserName, new List<string> { "preferred_username", "unique_name", ClaimTypes.Name }},
{ AbpClaimTypes.Name, new List<string> { "given_name", ClaimTypes.GivenName }},
{ AbpClaimTypes.SurName, new List<string> { "family_name", ClaimTypes.Surname }},
{ AbpClaimTypes.Role, new List<string> { "role", "roles", ClaimTypes.Role }},
{ AbpClaimTypes.Email, new List<string> { "email", ClaimTypes.Email }},
};
IsDynamicClaimsEnabled = false;
}
}

17
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpDynamicClaim.cs

@ -0,0 +1,17 @@
using System;
namespace Volo.Abp.Security.Claims;
[Serializable]
public class AbpDynamicClaim
{
public string Type { get; set; }
public string? Value { get; set; }
public AbpDynamicClaim(string type, string? value)
{
Type = type;
Value = value;
}
}

25
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpDynamicClaimCacheItem.cs

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.Security.Claims;
[Serializable]
public class AbpDynamicClaimCacheItem
{
public List<AbpDynamicClaim> Claims { get; set; }
public AbpDynamicClaimCacheItem()
{
Claims = new List<AbpDynamicClaim>();
}
public AbpDynamicClaimCacheItem(List<AbpDynamicClaim> claims)
{
Claims = claims;
}
public static string CalculateCacheKey(Guid userId, Guid? tenantId)
{
return $"{tenantId}-{userId}";
}
}

44
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/AbpDynamicClaimsPrincipalContributorBase.cs

@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Security.Claims;
public abstract class AbpDynamicClaimsPrincipalContributorBase : IAbpDynamicClaimsPrincipalContributor, ITransientDependency
{
public abstract Task ContributeAsync(AbpClaimsPrincipalContributorContext context);
protected virtual async Task AddDynamicClaimsAsync(AbpClaimsPrincipalContributorContext context, ClaimsIdentity identity, List<AbpDynamicClaim> dynamicClaims)
{
var options = context.GetRequiredService<IOptions<AbpClaimsPrincipalFactoryOptions>>().Value;
foreach (var map in options.ClaimsMap)
{
await MapClaimAsync(identity, dynamicClaims, map.Key, map.Value.ToArray());
}
foreach (var claimGroup in dynamicClaims.GroupBy(x => x.Type))
{
identity.RemoveAll(claimGroup.First().Type);
identity.AddClaims(claimGroup.Where(c => c.Value != null).Select(c => new Claim(claimGroup.First().Type, c.Value!)));
}
}
protected virtual Task MapClaimAsync(ClaimsIdentity identity, List<AbpDynamicClaim> dynamicClaims, string targetClaimType, params string[] sourceClaimTypes)
{
var claims = dynamicClaims.Where(c => sourceClaimTypes.Contains(c.Type)).ToList();
if (claims.IsNullOrEmpty())
{
return Task.CompletedTask;
}
dynamicClaims.RemoveAll(claims);
identity.RemoveAll(targetClaimType);
identity.AddClaims(claims.Where(c => c.Value != null).Select(c => new Claim(targetClaimType, c.Value!)));
return Task.CompletedTask;;
}
}

2
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/IAbpClaimsPrincipalFactory.cs

@ -6,4 +6,6 @@ namespace Volo.Abp.Security.Claims;
public interface IAbpClaimsPrincipalFactory
{
Task<ClaimsPrincipal> CreateAsync(ClaimsPrincipal? existsClaimsPrincipal = null);
Task<ClaimsPrincipal> CreateDynamicAsync(ClaimsPrincipal? existsClaimsPrincipal = null);
}

8
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/IAbpDynamicClaimsPrincipalContributor.cs

@ -0,0 +1,8 @@
using System.Threading.Tasks;
namespace Volo.Abp.Security.Claims;
public interface IAbpDynamicClaimsPrincipalContributor
{
Task ContributeAsync(AbpClaimsPrincipalContributorContext context);
}

19
framework/test/Volo.Abp.Imaging.SkiaSharp.Tests/Volo.Abp.Imaging.SkiaSharp.Tests.csproj

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.test.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<ProjectReference Include="..\Volo.Abp.Imaging.Abstractions.Tests\Volo.Abp.Imaging.Abstractions.Tests.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Imaging.SkiaSharp\Volo.Abp.Imaging.SkiaSharp.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Volo\Abp\Imaging\Files\**" />
</ItemGroup>
</Project>

14
framework/test/Volo.Abp.Imaging.SkiaSharp.Tests/Volo/Abp/Imaging/AbpImagingMagickNetTestModule.cs

@ -0,0 +1,14 @@
using Volo.Abp.Autofac;
using Volo.Abp.Modularity;
namespace Volo.Abp.Imaging;
[DependsOn(
typeof(AbpAutofacModule),
typeof(AbpImagingSkiaSharpModule),
typeof(AbpTestBaseModule)
)]
public class AbpImagingSkiaSharpTestModule : AbpModule
{
}

11
framework/test/Volo.Abp.Imaging.SkiaSharp.Tests/Volo/Abp/Imaging/AbpImagingSkiaSharpTestModule.cs

@ -0,0 +1,11 @@
using Volo.Abp.Testing;
namespace Volo.Abp.Imaging;
public abstract class AbpImagingSkiaSharpTestBase : AbpIntegratedTest<AbpImagingSkiaSharpTestModule>
{
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
}

75
framework/test/Volo.Abp.Imaging.SkiaSharp.Tests/Volo/Abp/Imaging/SkiaSharpImageResizerTests.cs

@ -0,0 +1,75 @@
using System.IO;
using System.Threading.Tasks;
using Shouldly;
using Xunit;
namespace Volo.Abp.Imaging;
public class SkiaSharpImageResizerTests : AbpImagingSkiaSharpTestBase
{
public IImageResizer ImageResizer { get; }
public SkiaSharpImageResizerTests()
{
ImageResizer = GetRequiredService<IImageResizer>();
}
[Fact]
public async Task Should_Resize_Jpg()
{
await using var jpegImage = ImageFileHelper.GetJpgTestFileStream();
var resizedImage = await ImageResizer.ResizeAsync(jpegImage, new ImageResizeArgs(100, 100));
resizedImage.ShouldNotBeNull();
resizedImage.State.ShouldBe(ImageProcessState.Done);
resizedImage.Result.Length.ShouldBeLessThan(jpegImage.Length);
resizedImage.Result.Dispose();
}
[Fact]
public async Task Should_Resize_Png()
{
await using var pngImage = ImageFileHelper.GetPngTestFileStream();
var resizedImage = await ImageResizer.ResizeAsync(pngImage, new ImageResizeArgs(100, 100));
resizedImage.ShouldNotBeNull();
resizedImage.State.ShouldBe(ImageProcessState.Done);
resizedImage.Result.Length.ShouldBeLessThan(pngImage.Length);
resizedImage.Result.Dispose();
}
[Fact]
public async Task Should_Resize_Webp()
{
await using var webpImage = ImageFileHelper.GetWebpTestFileStream();
var resizedImage = await ImageResizer.ResizeAsync(webpImage, new ImageResizeArgs(100, 100));
resizedImage.ShouldNotBeNull();
resizedImage.State.ShouldBe(ImageProcessState.Done);
resizedImage.Result.Length.ShouldBeLessThan(webpImage.Length);
resizedImage.Result.Dispose();
}
[Fact]
public async Task Should_Resize_Stream_And_Byte_Array_The_Same()
{
await using var jpegImage = ImageFileHelper.GetJpgTestFileStream();
var resizedImage1 = await ImageResizer.ResizeAsync(jpegImage, new ImageResizeArgs(100, 100));
var resizedImage2 = await ImageResizer.ResizeAsync(await jpegImage.GetAllBytesAsync(), new ImageResizeArgs(100, 100));
resizedImage1.ShouldNotBeNull();
resizedImage1.State.ShouldBe(ImageProcessState.Done);
resizedImage1.Result.Length.ShouldBeLessThan(jpegImage.Length);
resizedImage2.ShouldNotBeNull();
resizedImage2.State.ShouldBe(ImageProcessState.Done);
resizedImage2.Result.LongLength.ShouldBeLessThan(jpegImage.Length);
resizedImage1.Result.Length.ShouldBe(resizedImage2.Result.LongLength);
resizedImage1.Result.Dispose();
}
}

103
framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactory_Test.cs

@ -1,103 +0,0 @@
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Security.Claims;
public class AbpClaimsPrincipalFactory_Test : AbpIntegratedTest<AbpSecurityTestModule>
{
private readonly IAbpClaimsPrincipalFactory _abpClaimsPrincipalFactory;
private static string TestAuthenticationType => "Identity.Application";
public AbpClaimsPrincipalFactory_Test()
{
_abpClaimsPrincipalFactory = GetRequiredService<IAbpClaimsPrincipalFactory>();
}
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
protected override void AfterAddApplication(IServiceCollection services)
{
services.AddTransient<TestAbpClaimsPrincipalContributor>();
services.AddTransient<Test2AbpClaimsPrincipalContributor>();
services.AddTransient<Test3AbpClaimsPrincipalContributor>();
}
[Fact]
public async Task CreateAsync()
{
var claimsPrincipal = await _abpClaimsPrincipalFactory.CreateAsync();
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Email && x.Value == "admin2@abp.io");
claimsPrincipal.Claims.ShouldNotContain(x => x.Type == ClaimTypes.Email && x.Value == "admin@abp.io");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Version && x.Value == "2.0");
}
[Fact]
public async Task Create_With_Exists_ClaimsPrincipal()
{
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(TestAuthenticationType, ClaimTypes.Name, ClaimTypes.Role));
claimsPrincipal.Identities.First().AddClaim(new Claim(ClaimTypes.Name, "123"));
claimsPrincipal.Identities.First().AddClaim(new Claim(ClaimTypes.Role, "admin"));
await _abpClaimsPrincipalFactory.CreateAsync(claimsPrincipal);
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Name && x.Value == "123");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Role && x.Value == "admin");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Email && x.Value == "admin2@abp.io");
claimsPrincipal.Claims.ShouldNotContain(x => x.Type == ClaimTypes.Email && x.Value == "admin@abp.io");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Version && x.Value == "2.0");
}
class TestAbpClaimsPrincipalContributor : IAbpClaimsPrincipalContributor
{
public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var claimsIdentity = context.ClaimsPrincipal.Identities.FirstOrDefault(x => x.AuthenticationType == TestAuthenticationType)
?? new ClaimsIdentity(TestAuthenticationType);
claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Email, "admin@abp.io"));
context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity);
return Task.CompletedTask;
}
}
class Test2AbpClaimsPrincipalContributor : IAbpClaimsPrincipalContributor
{
public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var claimsIdentity = context.ClaimsPrincipal.Identities.FirstOrDefault(x => x.AuthenticationType == TestAuthenticationType)
?? new ClaimsIdentity(TestAuthenticationType);
claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Email, "admin2@abp.io"));
context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity);
return Task.CompletedTask;
}
}
class Test3AbpClaimsPrincipalContributor : IAbpClaimsPrincipalContributor
{
public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var claimsIdentity = context.ClaimsPrincipal.Identities.FirstOrDefault(x => x.AuthenticationType == TestAuthenticationType)
?? new ClaimsIdentity(TestAuthenticationType);
claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Version, "2.0"));
context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity);
return Task.CompletedTask;
}
}
}

189
framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/AbpClaimsPrincipalFactory_Tests.cs

@ -0,0 +1,189 @@
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Security.Claims;
public class AbpClaimsPrincipalFactory_Tests : AbpIntegratedTest<AbpSecurityTestModule>
{
private readonly IAbpClaimsPrincipalFactory _abpClaimsPrincipalFactory;
private static string TestAuthenticationType => "Identity.Application";
public AbpClaimsPrincipalFactory_Tests()
{
_abpClaimsPrincipalFactory = GetRequiredService<IAbpClaimsPrincipalFactory>();
}
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
[Fact]
public async Task CreateAsync()
{
var claimsPrincipal = await _abpClaimsPrincipalFactory.CreateAsync();
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Email && x.Value == "admin2@abp.io");
claimsPrincipal.Claims.ShouldNotContain(x => x.Type == ClaimTypes.Email && x.Value == "admin@abp.io");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Version && x.Value == "2.0");
}
[Fact]
public async Task Create_With_Exists_ClaimsPrincipal()
{
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(TestAuthenticationType, ClaimTypes.Name, ClaimTypes.Role));
claimsPrincipal.Identities.First().AddClaim(new Claim(ClaimTypes.Name, "123"));
claimsPrincipal.Identities.First().AddClaim(new Claim(ClaimTypes.Role, "admin"));
await _abpClaimsPrincipalFactory.CreateAsync(claimsPrincipal);
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Name && x.Value == "123");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Role && x.Value == "admin");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Email && x.Value == "admin2@abp.io");
claimsPrincipal.Claims.ShouldNotContain(x => x.Type == ClaimTypes.Email && x.Value == "admin@abp.io");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Version && x.Value == "2.0");
}
[Fact]
public async Task DynamicCreateAsync()
{
var claimsPrincipal = await _abpClaimsPrincipalFactory.CreateDynamicAsync();
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Name && x.Value == "admin");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Role && x.Value == "admin");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Role && x.Value == "manager");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Email && x.Value == "admin2@abp.io");
claimsPrincipal.Claims.ShouldNotContain(x => x.Type == ClaimTypes.Email && x.Value == "admin@abp.io");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Version && x.Value == "2.0");
}
[Fact]
public async Task DynamicCreate_With_Exists_ClaimsPrincipal()
{
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(TestAuthenticationType, ClaimTypes.Name, ClaimTypes.Role));
claimsPrincipal.Identities.First().AddClaim(new Claim(ClaimTypes.Name, "123"));
claimsPrincipal.Identities.First().AddClaim(new Claim(ClaimTypes.Role, "123"));
await _abpClaimsPrincipalFactory.CreateDynamicAsync(claimsPrincipal);
claimsPrincipal.Claims.ShouldNotContain(x => x.Type == ClaimTypes.Name && x.Value == "123");
claimsPrincipal.Claims.ShouldNotContain(x => x.Type == ClaimTypes.Role && x.Value == "123");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Name && x.Value == "admin");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Role && x.Value == "admin");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Role && x.Value == "manager");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Email && x.Value == "admin2@abp.io");
claimsPrincipal.Claims.ShouldNotContain(x => x.Type == ClaimTypes.Email && x.Value == "admin@abp.io");
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Version && x.Value == "2.0");
}
class TestAbpClaimsPrincipalContributor : IAbpClaimsPrincipalContributor, ITransientDependency
{
public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var claimsIdentity = context.ClaimsPrincipal.Identities.FirstOrDefault(x => x.AuthenticationType == TestAuthenticationType)
?? new ClaimsIdentity(TestAuthenticationType);
claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Email, "admin@abp.io"));
context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity);
return Task.CompletedTask;
}
}
class Test2AbpClaimsPrincipalContributor : IAbpClaimsPrincipalContributor, ITransientDependency
{
public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var claimsIdentity = context.ClaimsPrincipal.Identities.FirstOrDefault(x => x.AuthenticationType == TestAuthenticationType)
?? new ClaimsIdentity(TestAuthenticationType);
claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Email, "admin2@abp.io"));
context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity);
return Task.CompletedTask;
}
}
class Test3AbpClaimsPrincipalContributor : IAbpClaimsPrincipalContributor, ITransientDependency
{
public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var claimsIdentity = context.ClaimsPrincipal.Identities.FirstOrDefault(x => x.AuthenticationType == TestAuthenticationType)
?? new ClaimsIdentity(TestAuthenticationType);
claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Version, "2.0"));
context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity);
return Task.CompletedTask;
}
}
class TestAbpDynamicClaimsPrincipalContributor : IAbpDynamicClaimsPrincipalContributor, ITransientDependency
{
public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var claimsIdentity = context.ClaimsPrincipal.Identities.FirstOrDefault(x => x.AuthenticationType == TestAuthenticationType)
?? new ClaimsIdentity(TestAuthenticationType);
claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Email, "admin@abp.io"));
context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity);
return Task.CompletedTask;
}
}
class Test2AbpDynamicClaimsPrincipalContributor : IAbpDynamicClaimsPrincipalContributor, ITransientDependency
{
public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var claimsIdentity = context.ClaimsPrincipal.Identities.FirstOrDefault(x => x.AuthenticationType == TestAuthenticationType)
?? new ClaimsIdentity(TestAuthenticationType);
claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Email, "admin2@abp.io"));
context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity);
return Task.CompletedTask;
}
}
class Test3AbpDynamicClaimsPrincipalContributor : IAbpDynamicClaimsPrincipalContributor, ITransientDependency
{
public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var claimsIdentity = context.ClaimsPrincipal.Identities.FirstOrDefault(x => x.AuthenticationType == TestAuthenticationType)
?? new ClaimsIdentity(TestAuthenticationType);
claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Version, "2.0"));
context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity);
return Task.CompletedTask;
}
}
class Test4AbpDynamicClaimsPrincipalContributor : IAbpDynamicClaimsPrincipalContributor, ITransientDependency
{
public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var claimsIdentity = context.ClaimsPrincipal.Identities.FirstOrDefault(x => x.AuthenticationType == TestAuthenticationType)
?? new ClaimsIdentity(TestAuthenticationType);
claimsIdentity.AddOrReplace(new Claim(ClaimTypes.Name, "admin"));
claimsIdentity.RemoveAll(ClaimTypes.Role);
claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, "admin"));
claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, "manager"));
context.ClaimsPrincipal.AddIdentityIfNotContains(claimsIdentity);
return Task.CompletedTask;
}
}
}

76
framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/AbpDynamicClaimsPrincipalContributorBase_Tests.cs

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Security.Claims;
class TestAbpDynamicClaimsPrincipalContributor : AbpDynamicClaimsPrincipalContributorBase
{
public async override Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var identity = context.ClaimsPrincipal.Identities.FirstOrDefault();
Check.NotNull(identity, nameof(identity));
await AddDynamicClaimsAsync(context, identity, AbpDynamicClaimsPrincipalContributorBase_Tests.DynamicClaims.Claims);
}
}
public class AbpDynamicClaimsPrincipalContributorBase_Tests : AbpIntegratedTest<AbpSecurityTestModule>
{
private readonly TestAbpDynamicClaimsPrincipalContributor _dynamicClaimsPrincipalContributorBase = new TestAbpDynamicClaimsPrincipalContributor();
public readonly static AbpDynamicClaimCacheItem DynamicClaims = new AbpDynamicClaimCacheItem();
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
[Fact]
public async Task AddDynamicClaimsAsync()
{
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity());
claimsPrincipal.Identities.First().AddClaim(new Claim(AbpClaimTypes.UserName, "test-source-userName"));
claimsPrincipal.Identities.First().AddClaim(new Claim(AbpClaimTypes.Name, "test-source-name"));
claimsPrincipal.Identities.First().AddClaim(new Claim(AbpClaimTypes.SurName, "test-source-surname"));
claimsPrincipal.Identities.First().AddClaim(new Claim(AbpClaimTypes.Role, "test-source-role1"));
claimsPrincipal.Identities.First().AddClaim(new Claim(AbpClaimTypes.Role, "test-source-role2"));
claimsPrincipal.Identities.First().AddClaim(new Claim(AbpClaimTypes.Email, "test-source-email"));
claimsPrincipal.Identities.First().AddClaim(new Claim(AbpClaimTypes.EmailVerified, "test-source-emailVerified"));
claimsPrincipal.Identities.First().AddClaim(new Claim(AbpClaimTypes.PhoneNumber, "test-source-phoneNumber"));
claimsPrincipal.Identities.First().AddClaim(new Claim(AbpClaimTypes.PhoneNumberVerified, "test-source-phoneNumberVerified"));
claimsPrincipal.Identities.First().AddClaim(new Claim("my-claim", "test-source-my-claim"));
DynamicClaims.Claims.AddRange(new []
{
new AbpDynamicClaim("preferred_username", "test-preferred_username"),
new AbpDynamicClaim(ClaimTypes.GivenName, "test-given_name"),
new AbpDynamicClaim("family_name", "test-family_name"),
new AbpDynamicClaim("role", "test-role1"),
new AbpDynamicClaim("roles", "test-role2"),
new AbpDynamicClaim(ClaimTypes.Role, "test-role3"),
new AbpDynamicClaim("email", "test-email"),
new AbpDynamicClaim(AbpClaimTypes.EmailVerified, "test-email-verified"),
new AbpDynamicClaim(AbpClaimTypes.PhoneNumberVerified, null),
});
await _dynamicClaimsPrincipalContributorBase.ContributeAsync(new AbpClaimsPrincipalContributorContext(claimsPrincipal, GetRequiredService<IServiceProvider>()));
claimsPrincipal.Identities.First().Claims.ShouldContain(c => c.Type == AbpClaimTypes.UserName && c.Value == "test-preferred_username");
claimsPrincipal.Identities.First().Claims.ShouldContain(c => c.Type == AbpClaimTypes.SurName && c.Value == "test-family_name");
claimsPrincipal.Identities.First().Claims.ShouldContain(c => c.Type == AbpClaimTypes.Name && c.Value == "test-given_name");
claimsPrincipal.Identities.First().Claims.ShouldContain(c => c.Type == AbpClaimTypes.Role && c.Value == "test-role1");
claimsPrincipal.Identities.First().Claims.ShouldContain(c => c.Type == AbpClaimTypes.Role && c.Value == "test-role2");
claimsPrincipal.Identities.First().Claims.ShouldContain(c => c.Type == AbpClaimTypes.Role && c.Value == "test-role3");
claimsPrincipal.Identities.First().Claims.ShouldContain(c => c.Type == AbpClaimTypes.Email && c.Value == "test-email");
claimsPrincipal.Identities.First().Claims.ShouldContain(c => c.Type == AbpClaimTypes.EmailVerified && c.Value == "test-email-verified");
claimsPrincipal.Identities.First().Claims.ShouldContain(c => c.Type == AbpClaimTypes.PhoneNumber && c.Value == "test-source-phoneNumber");
claimsPrincipal.Identities.First().Claims.ShouldNotContain(c => c.Type == AbpClaimTypes.PhoneNumberVerified);
claimsPrincipal.Identities.First().Claims.ShouldContain(c => c.Type == "my-claim" && c.Value == "test-source-my-claim");
}
}

4
framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/CurrentPrincipalAccessor_Test.cs → framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/CurrentPrincipalAccessor_Tests.cs

@ -6,11 +6,11 @@ using Xunit;
namespace Volo.Abp.Security.Claims;
public class CurrentPrincipalAccessor_Test : AbpIntegratedTest<AbpSecurityTestModule>
public class CurrentPrincipalAccessor_Tests : AbpIntegratedTest<AbpSecurityTestModule>
{
private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor;
public CurrentPrincipalAccessor_Test()
public CurrentPrincipalAccessor_Tests()
{
_currentPrincipalAccessor = GetRequiredService<ICurrentPrincipalAccessor>();
}

2
global.json

@ -1,6 +1,6 @@
{
"sdk": {
"version": "8.0.100-rc.2.23502.2",
"version": "8.0.100",
"rollForward": "latestFeature"
}
}

2
latest-versions.json

@ -1,6 +1,6 @@
[
{
"version": "7.4.1",
"version": "7.4.2",
"releaseDate": "",
"type": "stable",
"message": ""

10
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/IDynamicClaimsAppService.cs

@ -0,0 +1,10 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace Volo.Abp.Account;
public interface IDynamicClaimsAppService : IApplicationService
{
Task RefreshAsync();
}

31
modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/DynamicClaimsAppService.cs

@ -0,0 +1,31 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Identity;
using Volo.Abp.Security.Claims;
using Volo.Abp.Users;
namespace Volo.Abp.Account;
[Authorize]
public class DynamicClaimsAppService : IdentityAppServiceBase, IDynamicClaimsAppService
{
protected IdentityDynamicClaimsPrincipalContributorCache IdentityDynamicClaimsPrincipalContributorCache { get; }
protected IAbpClaimsPrincipalFactory AbpClaimsPrincipalFactory { get; }
protected ICurrentPrincipalAccessor PrincipalAccessor { get; }
public DynamicClaimsAppService(
IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache,
IAbpClaimsPrincipalFactory abpClaimsPrincipalFactory,
ICurrentPrincipalAccessor principalAccessor)
{
IdentityDynamicClaimsPrincipalContributorCache = identityDynamicClaimsPrincipalContributorCache;
AbpClaimsPrincipalFactory = abpClaimsPrincipalFactory;
PrincipalAccessor = principalAccessor;
}
public virtual async Task RefreshAsync()
{
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(CurrentUser.GetId(), CurrentUser.TenantId);
await AbpClaimsPrincipalFactory.CreateDynamicAsync(PrincipalAccessor.Principal);
}
}

24
modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/Volo/Abp/Account/DynamicClaimsClientProxy.Generated.cs

@ -0,0 +1,24 @@
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Account;
using Volo.Abp.Application.Dtos;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Client.ClientProxying;
using Volo.Abp.Http.Modeling;
// ReSharper disable once CheckNamespace
namespace Volo.Abp.Account;
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IDynamicClaimsAppService), typeof(DynamicClaimsClientProxy))]
public partial class DynamicClaimsClientProxy : ClientProxyBase<IDynamicClaimsAppService>, IDynamicClaimsAppService
{
public virtual async Task RefreshAsync()
{
await RequestAsync(nameof(RefreshAsync));
}
}

7
modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/Volo/Abp/Account/DynamicClaimsClientProxy.cs

@ -0,0 +1,7 @@
// This file is part of DynamicClaimsClientProxy, you can customize it here
// ReSharper disable once CheckNamespace
namespace Volo.Abp.Account;
public partial class DynamicClaimsClientProxy
{
}

41
modules/account/src/Volo.Abp.Account.HttpApi.Client/ClientProxies/account-generate-proxy.json

@ -338,6 +338,47 @@
}
}
},
"Volo.Abp.Account.DynamicClaimsController": {
"controllerName": "DynamicClaims",
"controllerGroupName": "DynamicClaims",
"isRemoteService": true,
"isIntegrationService": false,
"apiVersion": null,
"type": "Volo.Abp.Account.DynamicClaimsController",
"interfaces": [
{
"type": "Volo.Abp.Account.IDynamicClaimsAppService",
"name": "IDynamicClaimsAppService",
"methods": [
{
"name": "RefreshAsync",
"parametersOnMethod": [],
"returnValue": {
"type": "System.Void",
"typeSimple": "System.Void"
}
}
]
}
],
"actions": {
"RefreshAsync": {
"uniqueName": "RefreshAsync",
"name": "RefreshAsync",
"httpMethod": "POST",
"url": "api/account/dynamic-claims/refresh",
"supportedVersions": [],
"parametersOnMethod": [],
"parameters": [],
"returnValue": {
"type": "System.Void",
"typeSimple": "System.Void"
},
"allowAnonymous": null,
"implementFrom": "Volo.Abp.Account.IDynamicClaimsAppService"
}
}
},
"Volo.Abp.Account.ProfileController": {
"controllerName": "Profile",
"controllerGroupName": "Profile",

27
modules/account/src/Volo.Abp.Account.HttpApi/Volo/Abp/Account/DynamicClaimsController.cs

@ -0,0 +1,27 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
namespace Volo.Abp.Account;
[RemoteService(Name = AccountRemoteServiceConsts.RemoteServiceName)]
[Area(AccountRemoteServiceConsts.ModuleName)]
[ControllerName("DynamicClaims")]
[Route("/api/account/dynamic-claims")]
public class DynamicClaimsController : AbpControllerBase, IDynamicClaimsAppService
{
protected IDynamicClaimsAppService DynamicClaimsAppService { get; }
public DynamicClaimsController(IDynamicClaimsAppService dynamicClaimsAppService)
{
DynamicClaimsAppService = dynamicClaimsAppService;
}
[HttpPost]
[Route("refresh")]
public virtual Task RefreshAsync()
{
return DynamicClaimsAppService.RefreshAsync();
}
}

14
modules/account/src/Volo.Abp.Account.Web.IdentityServer/Pages/Account/IdentityServerSupportedLoginModel.cs

@ -10,7 +10,6 @@ using System;
using System.Diagnostics;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Volo.Abp.Account.Settings;
@ -32,14 +31,12 @@ public class IdentityServerSupportedLoginModel : LoginModel
public IdentityServerSupportedLoginModel(
IAuthenticationSchemeProvider schemeProvider,
IOptions<AbpAccountOptions> accountOptions,
IOptions<IdentityOptions> identityOptions,
IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache,
IIdentityServerInteractionService interaction,
IClientStore clientStore,
IEventService identityServerEvents,
IOptions<IdentityOptions> identityOptions)
: base(
schemeProvider,
accountOptions,
identityOptions)
IEventService identityServerEvents)
: base(schemeProvider, accountOptions, identityOptions, identityDynamicClaimsPrincipalContributorCache)
{
Interaction = interaction;
ClientStore = clientStore;
@ -177,6 +174,9 @@ public class IdentityServerSupportedLoginModel : LoginModel
Debug.Assert(user != null, nameof(user) + " != null");
await IdentityServerEvents.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id.ToString(), user.UserName)); //TODO: Use user's name once implemented
// Clear the dynamic claims cache.
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId);
return RedirectSafely(ReturnUrl, ReturnUrlHash);
}

5
modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/Account/OpenIddictSupportedLoginModel.cs

@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Mvc;
using OpenIddict.Server;
using OpenIddict.Server.AspNetCore;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.OpenIddict;
@ -17,12 +18,14 @@ namespace Volo.Abp.Account.Web.Pages.Account;
public class OpenIddictSupportedLoginModel : LoginModel
{
protected AbpOpenIddictRequestHelper OpenIddictRequestHelper { get; }
public OpenIddictSupportedLoginModel(
IAuthenticationSchemeProvider schemeProvider,
IOptions<AbpAccountOptions> accountOptions,
IOptions<IdentityOptions> identityOptions,
IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache,
AbpOpenIddictRequestHelper openIddictRequestHelper)
: base(schemeProvider, accountOptions, identityOptions)
: base(schemeProvider, accountOptions, identityOptions, identityDynamicClaimsPrincipalContributorCache)
{
OpenIddictRequestHelper = openIddictRequestHelper;
}

15
modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountController.cs

@ -29,13 +29,15 @@ public class AccountController : AbpControllerBase
protected ISettingProvider SettingProvider { get; }
protected IdentitySecurityLogManager IdentitySecurityLogManager { get; }
protected IOptions<IdentityOptions> IdentityOptions { get; }
protected IdentityDynamicClaimsPrincipalContributorCache IdentityDynamicClaimsPrincipalContributorCache { get; }
public AccountController(
SignInManager<IdentityUser> signInManager,
IdentityUserManager userManager,
ISettingProvider settingProvider,
IdentitySecurityLogManager identitySecurityLogManager,
IOptions<IdentityOptions> identityOptions)
IOptions<IdentityOptions> identityOptions,
IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache)
{
LocalizationResource = typeof(AccountResource);
@ -44,6 +46,7 @@ public class AccountController : AbpControllerBase
SettingProvider = settingProvider;
IdentitySecurityLogManager = identitySecurityLogManager;
IdentityOptions = identityOptions;
IdentityDynamicClaimsPrincipalContributorCache = identityDynamicClaimsPrincipalContributorCache;
}
[HttpPost]
@ -69,6 +72,16 @@ public class AccountController : AbpControllerBase
UserName = login.UserNameOrEmailAddress
});
if (signInResult.Succeeded)
{
var user = await UserManager.FindByNameAsync(login.UserNameOrEmailAddress);
if (user != null)
{
// Clear the dynamic claims cache.
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId);
}
}
return GetAbpLoginResult(signInResult);
}

22
modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs

@ -52,17 +52,19 @@ public class LoginModel : AccountPageModel
protected IAuthenticationSchemeProvider SchemeProvider { get; }
protected AbpAccountOptions AccountOptions { get; }
protected IOptions<IdentityOptions> IdentityOptions { get; }
protected IdentityDynamicClaimsPrincipalContributorCache IdentityDynamicClaimsPrincipalContributorCache { get; }
public bool ShowCancelButton { get; set; }
public LoginModel(
IAuthenticationSchemeProvider schemeProvider,
IOptions<AbpAccountOptions> accountOptions,
IOptions<IdentityOptions> identityOptions)
IOptions<IdentityOptions> identityOptions,
IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache)
{
SchemeProvider = schemeProvider;
IdentityOptions = identityOptions;
AccountOptions = accountOptions.Value;
IdentityDynamicClaimsPrincipalContributorCache = identityDynamicClaimsPrincipalContributorCache;
}
public virtual async Task<IActionResult> OnGetAsync()
@ -138,6 +140,9 @@ public class LoginModel : AccountPageModel
Debug.Assert(user != null, nameof(user) + " != null");
// Clear the dynamic claims cache.
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId);
return RedirectSafely(ReturnUrl, ReturnUrlHash);
}
@ -222,8 +227,16 @@ public class LoginModel : AccountPageModel
throw new UserFriendlyException("Cannot proceed because user is not allowed!");
}
IdentityUser user;
if (result.Succeeded)
{
user = await UserManager.FindByLoginAsync(loginInfo.LoginProvider, loginInfo.ProviderKey);
if (user != null)
{
// Clear the dynamic claims cache.
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId);
}
return RedirectSafely(returnUrl, returnUrlHash);
}
@ -239,7 +252,7 @@ public class LoginModel : AccountPageModel
});
}
var user = await UserManager.FindByEmailAsync(email);
user = await UserManager.FindByEmailAsync(email);
if (user == null)
{
return RedirectToPage("./Register", new {
@ -263,6 +276,9 @@ public class LoginModel : AccountPageModel
UserName = user.Name
});
// Clear the dynamic claims cache.
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId);
return RedirectSafely(returnUrl, returnUrlHash);
}

11
modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs

@ -46,13 +46,16 @@ public class RegisterModel : AccountPageModel
protected IAuthenticationSchemeProvider SchemeProvider { get; }
protected AbpAccountOptions AccountOptions { get; }
protected IdentityDynamicClaimsPrincipalContributorCache IdentityDynamicClaimsPrincipalContributorCache { get; }
public RegisterModel(
IAccountAppService accountAppService,
IAuthenticationSchemeProvider schemeProvider,
IOptions<AbpAccountOptions> accountOptions)
IOptions<AbpAccountOptions> accountOptions,
IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache)
{
SchemeProvider = schemeProvider;
IdentityDynamicClaimsPrincipalContributorCache = identityDynamicClaimsPrincipalContributorCache;
AccountAppService = accountAppService;
AccountOptions = accountOptions.Value;
}
@ -159,6 +162,9 @@ public class RegisterModel : AccountPageModel
var user = await UserManager.GetByIdAsync(userDto.Id);
await SignInManager.SignInAsync(user, isPersistent: true);
// Clear the dynamic claims cache.
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId);
}
protected virtual async Task RegisterExternalUserAsync(ExternalLoginInfo externalLoginInfo, string userName, string emailAddress)
@ -185,6 +191,9 @@ public class RegisterModel : AccountPageModel
}
await SignInManager.SignInAsync(user, isPersistent: true, ExternalLoginAuthSchema);
// Clear the dynamic claims cache.
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId);
}
protected virtual async Task<bool> CheckSelfRegistrationAsync()

15
modules/account/src/Volo.Abp.Account.Web/wwwroot/client-proxies/account-proxy.js

@ -79,6 +79,21 @@
})();
// controller volo.abp.account.dynamicClaims
(function(){
abp.utils.createNamespace(window, 'volo.abp.account.dynamicClaims');
volo.abp.account.dynamicClaims.get = function(ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/account/dynamic-claims',
type: 'GET'
}, ajaxParams));
};
})();
// controller volo.abp.account.profile
(function(){

2
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory.cs

@ -33,7 +33,7 @@ public class AbpUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<Identity
}
[UnitOfWork]
public override async Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
public async override Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
{
var principal = await base.CreateAsync(user);
var identity = principal.Identities.First();

39
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributor.cs

@ -0,0 +1,39 @@
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.Identity;
public class IdentityDynamicClaimsPrincipalContributor : AbpDynamicClaimsPrincipalContributorBase
{
public async override Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var identity = context.ClaimsPrincipal.Identities.FirstOrDefault();
var userId = identity?.FindUserId();
if (userId == null)
{
return;
}
var dynamicClaimsCache = context.GetRequiredService<IdentityDynamicClaimsPrincipalContributorCache>();
AbpDynamicClaimCacheItem dynamicClaims;
try
{
dynamicClaims = await dynamicClaimsCache.GetAsync(userId.Value, identity.FindTenantId());
}
catch (EntityNotFoundException e)
{
// In case if user not found, We force to clear the claims principal.
context.ClaimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity());
var logger = context.GetRequiredService<ILogger<IdentityDynamicClaimsPrincipalContributor>>();
logger.LogWarning(e, $"User not found: {userId.Value}");
return;
}
await AddDynamicClaimsAsync(context, identity, dynamicClaims.Claims);
}
}

86
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributorCache.cs

@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.Identity;
public class IdentityDynamicClaimsPrincipalContributorCache : ITransientDependency
{
public ILogger<IdentityDynamicClaimsPrincipalContributorCache> Logger { get; set; }
protected IDistributedCache<AbpDynamicClaimCacheItem> Cache { get; }
protected ICurrentTenant CurrentTenant { get; }
protected IdentityUserManager UserManager { get; }
protected IUserClaimsPrincipalFactory<IdentityUser> UserClaimsPrincipalFactory { get; }
protected IOptions<AbpClaimsPrincipalFactoryOptions> AbpClaimsPrincipalFactoryOptions { get; }
protected IOptions<IdentityDynamicClaimsPrincipalContributorCacheOptions> CacheOptions { get; }
public IdentityDynamicClaimsPrincipalContributorCache(
IDistributedCache<AbpDynamicClaimCacheItem> cache,
ICurrentTenant currentTenant,
IdentityUserManager userManager,
IUserClaimsPrincipalFactory<IdentityUser> userClaimsPrincipalFactory,
IOptions<AbpClaimsPrincipalFactoryOptions> abpClaimsPrincipalFactoryOptions,
IOptions<IdentityDynamicClaimsPrincipalContributorCacheOptions> cacheOptions)
{
Cache = cache;
CurrentTenant = currentTenant;
UserManager = userManager;
UserClaimsPrincipalFactory = userClaimsPrincipalFactory;
AbpClaimsPrincipalFactoryOptions = abpClaimsPrincipalFactoryOptions;
CacheOptions = cacheOptions;
Logger = NullLogger<IdentityDynamicClaimsPrincipalContributorCache>.Instance;
}
public virtual async Task<AbpDynamicClaimCacheItem> GetAsync(Guid userId, Guid? tenantId = null)
{
Logger.LogDebug($"Get dynamic claims cache for user: {userId}");
return await Cache.GetOrAddAsync(AbpDynamicClaimCacheItem.CalculateCacheKey(userId, tenantId), async () =>
{
using (CurrentTenant.Change(tenantId))
{
Logger.LogDebug($"Filling dynamic claims cache for user: {userId}");
var user = await UserManager.GetByIdAsync(userId);
var principal = await UserClaimsPrincipalFactory.CreateAsync(user);
var dynamicClaims = new AbpDynamicClaimCacheItem();
foreach (var claimType in AbpClaimsPrincipalFactoryOptions.Value.DynamicClaims)
{
var claims = principal.Claims.Where(x => x.Type == claimType).ToList();
if (claims.Any())
{
dynamicClaims.Claims.AddRange(claims.Select(claim => new AbpDynamicClaim(claimType, claim.Value)));
}
else
{
dynamicClaims.Claims.Add(new AbpDynamicClaim(claimType, null));
}
}
return dynamicClaims;
}
}, () => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = CacheOptions.Value.CacheAbsoluteExpiration
});
}
public virtual async Task ClearAsync(Guid userId, Guid? tenantId = null)
{
Logger.LogDebug($"Clearing dynamic claims cache for user: {userId}");
await Cache.RemoveAsync(AbpDynamicClaimCacheItem.CalculateCacheKey(userId, tenantId));
}
}

13
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributorCacheOptions.cs

@ -0,0 +1,13 @@
using System;
namespace Volo.Abp.Identity;
public class IdentityDynamicClaimsPrincipalContributorCacheOptions
{
public TimeSpan CacheAbsoluteExpiration { get; set; }
public IdentityDynamicClaimsPrincipalContributorCacheOptions()
{
CacheAbsoluteExpiration = TimeSpan.FromHours(1);
}
}

40
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/UserUpdatedEventHandler.cs

@ -0,0 +1,40 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;
using Volo.Abp.Uow;
namespace Volo.Abp.Identity;
public class UserEntityUpdatedEventHandler :
ILocalEventHandler<EntityUpdatedEventData<IdentityUser>>,
ILocalEventHandler<EntityDeletedEventData<IdentityUser>>,
ITransientDependency
{
private readonly IdentityDynamicClaimsPrincipalContributorCache _cache;
public UserEntityUpdatedEventHandler(IdentityDynamicClaimsPrincipalContributorCache cache)
{
_cache = cache;
}
[UnitOfWork]
public virtual async Task HandleEventAsync(EntityUpdatedEventData<IdentityUser> eventData)
{
await ClearAsync(eventData.Entity.Id, eventData.Entity.TenantId);
}
[UnitOfWork]
public virtual async Task HandleEventAsync(EntityDeletedEventData<IdentityUser> eventData)
{
await ClearAsync(eventData.Entity.Id, eventData.Entity.TenantId);
}
protected virtual async Task ClearAsync(Guid userId, Guid? tenantId)
{
await _cache.ClearAsync(userId, tenantId);
}
}

8
modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpUserClaimsPrincipalFactory_Tests.cs

@ -2,6 +2,7 @@
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
@ -22,6 +23,11 @@ public class AbpUserClaimsPrincipalFactory_Tests : AbpIdentityDomainTestBase
_testData = GetRequiredService<IdentityTestData>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
services.AddTransient<TestAbpClaimsPrincipalContributor>();
}
[Fact]
public async Task Add_And_Replace_Claims_Test()
{
@ -42,7 +48,7 @@ public class AbpUserClaimsPrincipalFactory_Tests : AbpIdentityDomainTestBase
});
}
class TestAbpClaimsPrincipalContributor : IAbpClaimsPrincipalContributor, ITransientDependency
class TestAbpClaimsPrincipalContributor : IAbpClaimsPrincipalContributor
{
//https://github.com/dotnet/aspnetcore/blob/v5.0.0/src/Identity/Extensions.Core/src/UserClaimsPrincipalFactory.cs#L79
private static string IdentityAuthenticationType => "Identity.Application";

59
modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/IdentityDynamicClaimsPrincipalContributor_Tests.cs

@ -0,0 +1,59 @@
using System.Security.Claims;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Security.Claims;
using Xunit;
namespace Volo.Abp.Identity;
public class IdentityDynamicClaimsPrincipalContributor_Tests : AbpIdentityDomainTestBase
{
private readonly IdentityUserManager _identityUserManager;
private readonly IAbpClaimsPrincipalFactory _abpClaimsPrincipalFactory;
private readonly AbpUserClaimsPrincipalFactory _abpUserClaimsPrincipalFactory;
private readonly IdentityTestData _testData;
public IdentityDynamicClaimsPrincipalContributor_Tests()
{
_identityUserManager = GetRequiredService<IdentityUserManager>();
_abpClaimsPrincipalFactory = GetRequiredService<IAbpClaimsPrincipalFactory>();
_abpUserClaimsPrincipalFactory = GetRequiredService<AbpUserClaimsPrincipalFactory>();
_testData = GetRequiredService<IdentityTestData>();
}
[Fact]
public async Task Should_Get_Correct_Claims_After_User_Updating()
{
IdentityUser user = null;
ClaimsPrincipal claimsPrincipal = null;
string securityStamp = null;
await UsingUowAsync(async () =>
{
user = await _identityUserManager.GetByIdAsync(_testData.UserJohnId);
user.ShouldNotBeNull();
securityStamp = user.SecurityStamp;
claimsPrincipal = await _abpUserClaimsPrincipalFactory.CreateAsync(user);
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.NameIdentifier && x.Value == user.Id.ToString());
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Name && x.Value == user.UserName);
claimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Email && x.Value == user.Email);
claimsPrincipal.Claims.ShouldContain(x => x.Type == "AspNet.Identity.SecurityStamp" && x.Value == securityStamp);
var dynamicClaimsPrincipal = await _abpClaimsPrincipalFactory.CreateDynamicAsync(claimsPrincipal);
dynamicClaimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.NameIdentifier && x.Value == user.Id.ToString());
dynamicClaimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Name && x.Value == user.UserName);
dynamicClaimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Email && x.Value == user.Email);
dynamicClaimsPrincipal.Claims.ShouldContain(x => x.Type == "AspNet.Identity.SecurityStamp" && x.Value == securityStamp);//SecurityStamp is not dynamic claim
await _identityUserManager.SetUserNameAsync(user, "newUserName");
await _identityUserManager.SetEmailAsync(user, "newUserEmail@abp.io");
await _identityUserManager.UpdateSecurityStampAsync(user);
});
var dynamicClaimsPrincipal = await _abpClaimsPrincipalFactory.CreateDynamicAsync(claimsPrincipal);
dynamicClaimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.NameIdentifier && x.Value == user.Id.ToString());
dynamicClaimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Name && x.Value =="newUserName");
dynamicClaimsPrincipal.Claims.ShouldContain(x => x.Type == ClaimTypes.Email && x.Value == "newUserEmail@abp.io");
dynamicClaimsPrincipal.Claims.ShouldContain(x => x.Type == "AspNet.Identity.SecurityStamp" && x.Value == securityStamp);//SecurityStamp is not dynamic claim
}
}

100
modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230404033745_Initial.Designer.cs → modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20231116094249_Initial.Designer.cs

@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace OpenIddict.Demo.Server.Migrations
{
[DbContext(typeof(ServerDbContext))]
[Migration("20230404033745_Initial")]
[Migration("20231116094249_Initial")]
partial class Initial
{
/// <inheritdoc />
@ -22,7 +22,7 @@ namespace OpenIddict.Demo.Server.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer)
.HasAnnotation("ProductVersion", "7.0.1")
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
@ -157,6 +157,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -166,6 +167,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("nvarchar(256)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -231,6 +233,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -239,6 +242,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("int");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -331,6 +335,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -343,6 +348,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("datetime2");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -392,6 +398,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -428,6 +435,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("int");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -571,6 +579,33 @@ namespace OpenIddict.Demo.Server.Migrations
b.ToTable("AbpUserClaims", (string)null);
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("EndTime")
.HasColumnType("datetime2");
b.Property<Guid>("SourceUserId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("StartTime")
.HasColumnType("datetime2");
b.Property<Guid>("TargetUserId")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.ToTable("AbpUserDelegations", (string)null);
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b =>
{
b.Property<Guid>("UserId")
@ -685,6 +720,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -715,6 +751,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("int");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -793,6 +830,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -824,6 +862,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("nvarchar(max)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -881,6 +920,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -905,6 +945,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -955,6 +996,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -988,6 +1030,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("nvarchar(max)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -1036,6 +1079,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -1063,6 +1107,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("datetime2");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -1264,6 +1309,55 @@ namespace OpenIddict.Demo.Server.Migrations
b.ToTable("AbpSettings", (string)null);
});
modelBuilder.Entity("Volo.Abp.SettingManagement.SettingDefinitionRecord", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("DefaultValue")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("Description")
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("ExtraProperties")
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsEncrypted")
.HasColumnType("bit");
b.Property<bool>("IsInherited")
.HasColumnType("bit");
b.Property<bool>("IsVisibleToClients")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("Providers")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("AbpSettingDefinitions", (string)null);
});
modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b =>
{
b.Property<Guid>("Id")
@ -1272,6 +1366,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -1296,6 +1391,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("int");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");

88
modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20230404033745_Initial.cs → modules/openiddict/app/OpenIddict.Demo.Server/Migrations/20231116094249_Initial.cs

@ -23,8 +23,8 @@ namespace OpenIddict.Demo.Server.Migrations
RegexDescription = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
Description = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
ValueType = table.Column<int>(type: "int", nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true)
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false)
},
constraints: table =>
{
@ -107,8 +107,8 @@ namespace OpenIddict.Demo.Server.Migrations
Code = table.Column<string>(type: "nvarchar(95)", maxLength: 95, nullable: false),
DisplayName = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
EntityVersion = table.Column<int>(type: "int", nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
@ -188,8 +188,8 @@ namespace OpenIddict.Demo.Server.Migrations
IsStatic = table.Column<bool>(type: "bit", nullable: false),
IsPublic = table.Column<bool>(type: "bit", nullable: false),
EntityVersion = table.Column<int>(type: "int", nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true)
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false)
},
constraints: table =>
{
@ -213,14 +213,34 @@ namespace OpenIddict.Demo.Server.Migrations
ClientIpAddress = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
BrowserInfo = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true)
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpSecurityLogs", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpSettingDefinitions",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
DisplayName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Description = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
DefaultValue = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
IsVisibleToClients = table.Column<bool>(type: "bit", nullable: false),
Providers = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
IsInherited = table.Column<bool>(type: "bit", nullable: false),
IsEncrypted = table.Column<bool>(type: "bit", nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpSettingDefinitions", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpSettings",
columns: table => new
@ -243,8 +263,8 @@ namespace OpenIddict.Demo.Server.Migrations
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
EntityVersion = table.Column<int>(type: "int", nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
@ -258,6 +278,22 @@ namespace OpenIddict.Demo.Server.Migrations
table.PrimaryKey("PK_AbpTenants", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpUserDelegations",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
SourceUserId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TargetUserId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
StartTime = table.Column<DateTime>(type: "datetime2", nullable: false),
EndTime = table.Column<DateTime>(type: "datetime2", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpUserDelegations", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AbpUsers",
columns: table => new
@ -284,8 +320,8 @@ namespace OpenIddict.Demo.Server.Migrations
ShouldChangePasswordOnNextLogin = table.Column<bool>(type: "bit", nullable: false),
EntityVersion = table.Column<int>(type: "int", nullable: false),
LastPasswordChangeTime = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
@ -317,8 +353,8 @@ namespace OpenIddict.Demo.Server.Migrations
Type = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
ClientUri = table.Column<string>(type: "nvarchar(max)", nullable: true),
LogoUri = table.Column<string>(type: "nvarchar(max)", nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
@ -344,8 +380,8 @@ namespace OpenIddict.Demo.Server.Migrations
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
Properties = table.Column<string>(type: "nvarchar(max)", nullable: true),
Resources = table.Column<string>(type: "nvarchar(max)", nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
@ -553,8 +589,8 @@ namespace OpenIddict.Demo.Server.Migrations
Status = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
Subject = table.Column<string>(type: "nvarchar(400)", maxLength: 400, nullable: true),
Type = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
@ -589,8 +625,8 @@ namespace OpenIddict.Demo.Server.Migrations
Status = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
Subject = table.Column<string>(type: "nvarchar(400)", maxLength: 400, nullable: true),
Type = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
@ -714,6 +750,12 @@ namespace OpenIddict.Demo.Server.Migrations
table: "AbpSecurityLogs",
columns: new[] { "TenantId", "UserId" });
migrationBuilder.CreateIndex(
name: "IX_AbpSettingDefinitions_Name",
table: "AbpSettingDefinitions",
column: "Name",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_AbpSettings_Name_ProviderName_ProviderKey",
table: "AbpSettings",
@ -833,6 +875,9 @@ namespace OpenIddict.Demo.Server.Migrations
migrationBuilder.DropTable(
name: "AbpSecurityLogs");
migrationBuilder.DropTable(
name: "AbpSettingDefinitions");
migrationBuilder.DropTable(
name: "AbpSettings");
@ -842,6 +887,9 @@ namespace OpenIddict.Demo.Server.Migrations
migrationBuilder.DropTable(
name: "AbpUserClaims");
migrationBuilder.DropTable(
name: "AbpUserDelegations");
migrationBuilder.DropTable(
name: "AbpUserLogins");

98
modules/openiddict/app/OpenIddict.Demo.Server/Migrations/ServerDbContextModelSnapshot.cs

@ -19,7 +19,7 @@ namespace OpenIddict.Demo.Server.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer)
.HasAnnotation("ProductVersion", "7.0.1")
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
@ -154,6 +154,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -163,6 +164,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("nvarchar(256)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -228,6 +230,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -236,6 +239,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("int");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -328,6 +332,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -340,6 +345,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("datetime2");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -389,6 +395,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -425,6 +432,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("int");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -568,6 +576,33 @@ namespace OpenIddict.Demo.Server.Migrations
b.ToTable("AbpUserClaims", (string)null);
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserDelegation", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("EndTime")
.HasColumnType("datetime2");
b.Property<Guid>("SourceUserId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("StartTime")
.HasColumnType("datetime2");
b.Property<Guid>("TargetUserId")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.ToTable("AbpUserDelegations", (string)null);
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b =>
{
b.Property<Guid>("UserId")
@ -682,6 +717,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -712,6 +748,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("int");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -790,6 +827,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -821,6 +859,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("nvarchar(max)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -878,6 +917,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -902,6 +942,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -952,6 +993,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -985,6 +1027,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("nvarchar(max)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -1033,6 +1076,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -1060,6 +1104,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("datetime2");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -1261,6 +1306,55 @@ namespace OpenIddict.Demo.Server.Migrations
b.ToTable("AbpSettings", (string)null);
});
modelBuilder.Entity("Volo.Abp.SettingManagement.SettingDefinitionRecord", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("DefaultValue")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("Description")
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("ExtraProperties")
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsEncrypted")
.HasColumnType("bit");
b.Property<bool>("IsInherited")
.HasColumnType("bit");
b.Property<bool>("IsVisibleToClients")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("Providers")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("AbpSettingDefinitions", (string)null);
});
modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b =>
{
b.Property<Guid>("Id")
@ -1269,6 +1363,7 @@ namespace OpenIddict.Demo.Server.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -1293,6 +1388,7 @@ namespace OpenIddict.Demo.Server.Migrations
.HasColumnType("int");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");

1
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictAspNetCoreModule.cs

@ -24,6 +24,7 @@ public class AbpOpenIddictAspNetCoreModule : AbpModule
Configure<AbpOpenIddictClaimsPrincipalOptions>(options =>
{
options.ClaimsPrincipalHandlers.Add<AbpDynamicClaimsOpenIddictClaimsPrincipalHandler>();
options.ClaimsPrincipalHandlers.Add<AbpDefaultOpenIddictClaimsPrincipalHandler>();
});

18
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Claims/AbpDynamicClaimsOpenIddictClaimsPrincipalHandler.cs

@ -0,0 +1,18 @@
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.OpenIddict;
public class AbpDynamicClaimsOpenIddictClaimsPrincipalHandler: IAbpOpenIddictClaimsPrincipalHandler, ITransientDependency
{
public virtual async Task HandleAsync(AbpOpenIddictClaimsPrincipalHandlerContext context)
{
var abpClaimsPrincipalFactory = context
.ScopeServiceProvider
.GetRequiredService<IAbpClaimsPrincipalFactory>();
await abpClaimsPrincipalFactory.CreateDynamicAsync(context.Principal);
}
}

2
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AbpOpenIdDictControllerBase.cs

@ -13,6 +13,7 @@ using OpenIddict.Abstractions;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Identity;
using Volo.Abp.OpenIddict.Localization;
using Volo.Abp.Security.Claims;
using IdentityUser = Volo.Abp.Identity.IdentityUser;
namespace Volo.Abp.OpenIddict.Controllers;
@ -26,6 +27,7 @@ public abstract class AbpOpenIdDictControllerBase : AbpController
protected IOpenIddictScopeManager ScopeManager => LazyServiceProvider.LazyGetRequiredService<IOpenIddictScopeManager>();
protected IOpenIddictTokenManager TokenManager => LazyServiceProvider.LazyGetRequiredService<IOpenIddictTokenManager>();
protected AbpOpenIddictClaimsPrincipalManager OpenIddictClaimsPrincipalManager => LazyServiceProvider.LazyGetRequiredService<AbpOpenIddictClaimsPrincipalManager>();
protected IAbpClaimsPrincipalFactory AbpClaimsPrincipalFactory => LazyServiceProvider.LazyGetRequiredService<IAbpClaimsPrincipalFactory>();
protected AbpOpenIdDictControllerBase()
{

14
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AuthorizeController.cs

@ -78,8 +78,18 @@ public class AuthorizeController : AbpOpenIdDictControllerBase
}
// Retrieve the profile of the logged in user.
var user = await UserManager.GetUserAsync(result.Principal) ??
throw new InvalidOperationException(L["TheUserDetailsCannotBbeRetrieved"]);
var dynamicPrincipal = await AbpClaimsPrincipalFactory.CreateDynamicAsync(result.Principal);
var user = await UserManager.GetUserAsync(dynamicPrincipal);
if (user == null)
{
return Challenge(
authenticationSchemes: IdentityConstants.ApplicationScheme,
properties: new AuthenticationProperties
{
RedirectUri = Request.PathBase + Request.Path + QueryString.Create(
Request.HasFormContentType ? Request.Form.ToList() : Request.Query.ToList())
});
}
// Retrieve the application details from the database.
var application = await ApplicationManager.FindByClientIdAsync(request.ClientId) ??

1
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.AuthorizationCode.cs

@ -14,6 +14,7 @@ public partial class TokenController
{
// Retrieve the claims principal stored in the authorization code/device code/refresh token.
var principal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal;
principal = await AbpClaimsPrincipalFactory.CreateDynamicAsync(principal);
using (CurrentTenant.Change(principal.FindTenantId()))
{
// Retrieve the user profile corresponding to the authorization code/refresh token.

1
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.DeviceCode.cs

@ -14,6 +14,7 @@ public partial class TokenController
{
// Retrieve the claims principal stored in the authorization code/device code/refresh token.
var principal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal;
principal = await AbpClaimsPrincipalFactory.CreateDynamicAsync(principal);
using (CurrentTenant.Change(principal.FindTenantId()))
{
// Retrieve the user profile corresponding to the authorization code/refresh token.

4
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs

@ -31,6 +31,7 @@ public partial class TokenController
protected IdentitySecurityLogManager IdentitySecurityLogManager => LazyServiceProvider.LazyGetRequiredService<IdentitySecurityLogManager>();
protected ISettingProvider SettingProvider => LazyServiceProvider.LazyGetRequiredService<ISettingProvider>();
protected IdentityDynamicClaimsPrincipalContributorCache IdentityDynamicClaimsPrincipalContributorCache => LazyServiceProvider.LazyGetRequiredService<IdentityDynamicClaimsPrincipalContributorCache>();
[UnitOfWork]
protected virtual async Task<IActionResult> HandlePasswordAsync(OpenIddictRequest request)
@ -334,6 +335,9 @@ public partial class TokenController
protected virtual async Task<IActionResult> SetSuccessResultAsync(OpenIddictRequest request, IdentityUser user)
{
// Clear the dynamic claims cache.
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId);
// Create a new ClaimsPrincipal containing the claims that
// will be used to create an id_token, a token or a code.
var principal = await SignInManager.CreateUserPrincipalAsync(user);

1
modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.RefreshToken.cs

@ -14,6 +14,7 @@ public partial class TokenController
{
// Retrieve the claims principal stored in the authorization code/device code/refresh token.
var principal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal;
principal = await AbpClaimsPrincipalFactory.CreateDynamicAsync(principal);
using (CurrentTenant.Change(principal.FindTenantId()))
{
// Retrieve the user profile corresponding to the authorization code/refresh token.

2
npm/ng-packs/.gitignore

@ -56,3 +56,5 @@ Thumbs.db
*.internal.*
.angular
.nx/

3
npm/ng-packs/.prettierignore

@ -7,4 +7,5 @@
/node_modules
/scripts
/tools
/source-code-requirements
/source-code-requirements
/.nx/cache

2
npm/ng-packs/apps/dev-app-e2e/project.json

@ -18,7 +18,7 @@
}
},
"lint": {
"executor": "@nx/linter:eslint",
"executor": "@nx/eslint:lint",
"options": {
"lintFilePatterns": ["apps/dev-app-e2e/**/*.{js,ts}"]
},

11
npm/ng-packs/apps/dev-app/project.json

@ -151,10 +151,10 @@
"executor": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "dev-app:build:production"
"buildTarget": "dev-app:build:production"
},
"development": {
"browserTarget": "dev-app:build:development"
"buildTarget": "dev-app:build:development"
}
},
"defaultConfiguration": "development"
@ -162,11 +162,11 @@
"extract-i18n": {
"executor": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "dev-app:build"
"buildTarget": "dev-app:build"
}
},
"lint": {
"executor": "@nx/linter:eslint",
"executor": "@nx/eslint:lint",
"options": {
"lintFilePatterns": ["apps/dev-app/src/**/*.ts", "apps/dev-app/src/**/*.html"]
}
@ -175,8 +175,7 @@
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/apps/dev-app"],
"options": {
"jestConfig": "apps/dev-app/jest.config.ts",
"passWithNoTests": true
"jestConfig": "apps/dev-app/jest.config.ts"
}
}
}

152
npm/ng-packs/migrations.json

@ -2,115 +2,131 @@
"migrations": [
{
"cli": "nx",
"version": "16.6.0-beta.6",
"description": "Prefix outputs with {workspaceRoot}/{projectRoot} if needed",
"implementation": "./src/migrations/update-15-0-0/prefix-outputs",
"version": "17.0.0-beta.1",
"description": "Updates the default cache directory to .nx/cache",
"implementation": "./src/migrations/update-17-0-0/move-cache-directory",
"package": "nx",
"name": "16.6.0-prefix-outputs"
"name": "17.0.0-move-cache-directory"
},
{
"cli": "nx",
"version": "16.8.0-beta.3",
"description": "Escape $ in env variables",
"implementation": "./src/migrations/update-16-8-0/escape-dollar-sign-env-variables",
"version": "17.0.0-beta.3",
"description": "Use minimal config for tasksRunnerOptions",
"implementation": "./src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options",
"package": "nx",
"name": "16.8.0-escape-dollar-sign-env"
"name": "17.0.0-use-minimal-config-for-tasks-runner-options"
},
{
"version": "16.8.0",
"description": "update-16-8-0-add-ignored-files",
"implementation": "./src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files",
"package": "@nx/linter",
"name": "update-16-8-0-add-ignored-files"
"version": "17.0.0-rc.1",
"description": "Migration for v17.0.0-rc.1",
"implementation": "./src/migrations/update-17-0-0/rm-default-collection-npm-scope",
"package": "nx",
"name": "rm-default-collection-npm-scope"
},
{
"cli": "nx",
"version": "16.9.0-beta.1",
"description": "Replace imports of Module Federation utils frm @nx/devkit to @nx/webpack",
"implementation": "./src/migrations/update-16-9-0/migrate-mf-util-usage",
"package": "@nx/devkit",
"name": "update-16-9-0-migrate-mf-usage-to-webpack"
"version": "17.0.2",
"description": "Remove deprecated build options",
"implementation": "./src/migrations/update-17-0-0/remove-deprecated-build-options",
"package": "@nx/js",
"name": "update-17-0-0-remove-deprecated-build-options"
},
{
"version": "17.0.0-beta.7",
"description": "update-17-0-0-rename-to-eslint",
"implementation": "./src/migrations/update-17-0-0-rename-to-eslint/update-17-0-0-rename-to-eslint",
"package": "@nx/eslint",
"name": "update-17-0-0-rename-to-eslint"
},
{
"version": "17.1.0-beta.1",
"description": "Updates for @typescript-utils/utils v6.9.1+",
"implementation": "./src/migrations/update-17-1-0/update-typescript-eslint",
"package": "@nx/eslint",
"name": "update-typescript-eslint"
},
{
"version": "17.1.0-beta.2",
"description": "Move jest executor options to nx.json targetDefaults",
"implementation": "./src/migrations/update-17-1-0/move-options-to-target-defaults",
"package": "@nx/jest",
"name": "move-options-to-target-defaults"
},
{
"cli": "nx",
"version": "16.4.0-beta.6",
"version": "17.1.0-beta.5",
"requires": {
"@angular-eslint/eslint-plugin-template": ">=16.0.0"
"@angular/core": ">=17.0.0"
},
"description": "Remove the 'accessibility-' prefix from '@angular-eslint/eslint-plugin-template' rules.",
"factory": "./src/migrations/update-16-4-0/rename-angular-eslint-accesibility-rules",
"description": "Update the @angular/cli package version to ~17.0.0.",
"factory": "./src/migrations/update-17-1-0/update-angular-cli",
"package": "@nx/angular",
"name": "rename-angular-eslint-accesibility-rules"
"name": "update-angular-cli-version-17-0-0"
},
{
"cli": "nx",
"version": "16.4.0-beta.11",
"version": "17.1.0-beta.5",
"requires": {
"@angular/core": ">=16.1.0"
"@angular/core": ">=17.0.0"
},
"description": "Update the @angular/cli package version to ~16.1.0.",
"factory": "./src/migrations/update-16-4-0/update-angular-cli",
"description": "Rename 'browserTarget' to 'buildTarget'.",
"factory": "./src/migrations/update-17-1-0/browser-target-to-build-target",
"package": "@nx/angular",
"name": "update-angular-cli-version-16-1-0"
"name": "rename-browser-target-to-build-target"
},
{
"cli": "nx",
"version": "16.6.0-beta.0",
"description": "Explicitly set 'updateBuildableProjectDepsInPackageJson' to 'true' in targets that rely on that value as the default.",
"factory": "./src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps",
"version": "17.1.0-beta.5",
"requires": {
"@angular/core": ">=17.0.0"
},
"description": "Replace usages of '@nguniversal/builders' with '@angular-devkit/build-angular'.",
"factory": "./src/migrations/update-17-1-0/replace-nguniversal-builders",
"package": "@nx/angular",
"name": "explicitly-set-projects-to-update-buildable-deps"
"name": "replace-nguniversal-builders"
},
{
"cli": "nx",
"version": "16.7.0-beta.6",
"version": "17.1.0-beta.5",
"requires": {
"@angular/core": ">=16.2.0"
"@angular/core": ">=17.0.0"
},
"description": "Update the @angular/cli package version to ~16.2.0.",
"factory": "./src/migrations/update-16-7-0/update-angular-cli",
"description": "Replace usages of '@nguniversal/' packages with '@angular/ssr'.",
"factory": "./src/migrations/update-17-1-0/replace-nguniversal-engines",
"package": "@nx/angular",
"name": "update-angular-cli-version-16-2-0"
"name": "replace-nguniversal-engines"
},
{
"cli": "nx",
"version": "16.4.0-beta.10",
"description": "Remove tsconfig.e2e.json and add settings to project tsconfig.json. tsConfigs executor option is now deprecated. The project level tsconfig.json file should be used instead.",
"implementation": "./src/migrations/update-16-4-0/tsconfig-sourcemaps",
"package": "@nx/cypress",
"name": "update-16-3-0-remove-old-tsconfigs"
},
{
"cli": "nx",
"version": "16.8.0-beta.4",
"description": "Update to Cypress v13. Most noteable change is video recording is off by default. This migration will only update if the workspace is already on Cypress v12. https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-130",
"implementation": "./src/migrations/update-16-8-0/cypress-13",
"package": "@nx/cypress",
"name": "update-16-8-0-cypress-13"
"version": "17.1.0-beta.5",
"requires": {
"@angular/core": ">=17.0.0"
},
"description": "Replace the deep imports from 'zone.js/dist/zone' and 'zone.js/dist/zone-testing' with 'zone.js' and 'zone.js/testing'.",
"factory": "./src/migrations/update-17-1-0/update-zone-js-deep-import",
"package": "@nx/angular",
"name": "update-zone-js-deep-import"
},
{
"cli": "nx",
"version": "16.5.0-beta.2",
"description": "Add test-setup.ts to ignored files in production input",
"implementation": "./src/migrations/update-16-5-0/add-test-setup-to-inputs-ignore",
"package": "@nx/jest",
"name": "add-test-setup-to-inputs-ignore"
"version": "17.0.0",
"description": "Angular v17 introduces a new control flow syntax that uses the @ and } characters. This migration replaces the existing usages with their corresponding HTML entities.",
"factory": "./migrations/block-template-entities/bundle",
"package": "@angular/core",
"name": "block-template-entities"
},
{
"cli": "nx",
"version": "16.6.0-beta.0",
"description": "Explicitly set 'updateBuildableProjectDepsInPackageJson' to 'true' in targets that rely on that value as the default.",
"factory": "./src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps",
"package": "@nx/js",
"name": "explicitly-set-projects-to-update-buildable-deps"
"version": "17.0.0",
"description": "CompilerOption.useJit and CompilerOption.missingTranslation are unused under Ivy. This migration removes their usage",
"factory": "./migrations/compiler-options/bundle",
"package": "@angular/core",
"name": "migration-v17-compiler-options"
},
{
"cli": "nx",
"version": "16.8.2-beta.0",
"description": "Remove invalid options (strict, noInterop) for ES6 type modules.",
"factory": "./src/migrations/update-16-8-2/update-swcrc",
"package": "@nx/js",
"name": "16-8-2-update-swcrc"
"version": "17.0.0",
"description": "Updates `TransferState`, `makeStateKey`, `StateKey` imports from `@angular/platform-browser` to `@angular/core`.",
"factory": "./migrations/transfer-state/bundle",
"package": "@angular/core",
"name": "migration-transfer-state"
}
]
}

38
npm/ng-packs/nx.json

@ -1,17 +1,7 @@
{
"npmScope": "abp",
"affected": {
"defaultBase": "dev"
},
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": ["build", "lint", "test", "e2e"],
"parallel": 3
}
}
},
"workspaceLayout": {
"libsDir": "packages",
"appsDir": ""
@ -51,16 +41,29 @@
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
"inputs": ["production", "^production"]
"inputs": ["production", "^production"],
"cache": true
},
"e2e": {
"inputs": ["default", "^production"]
},
"test": {
"inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"]
"inputs": ["default", "^production"],
"cache": true
},
"lint": {
"inputs": ["default", "{workspaceRoot}/.eslintrc.json"]
"inputs": ["default", "{workspaceRoot}/.eslintrc.json"],
"cache": true
},
"@nx/jest:jest": {
"inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"],
"cache": true,
"options": {
"passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
}
},
"namedInputs": {
@ -73,5 +76,6 @@
"!{projectRoot}/jest.config.[jt]s",
"!{projectRoot}/.eslintrc.json"
]
}
},
"parallel": 3
}

93
npm/ng-packs/package.json

@ -44,48 +44,47 @@
},
"private": true,
"devDependencies": {
"@abp/ng.theme.lepton-x": "~2.4.1",
"@abp/utils": "~7.4.1",
"@angular-devkit/build-angular": "~16.2.0",
"@angular-devkit/core": "~16.2.0",
"@angular-devkit/schematics": "~16.2.0",
"@angular-devkit/schematics-cli": "~16.2.0",
"@angular-eslint/eslint-plugin": "~16.2.0",
"@angular-eslint/eslint-plugin-template": "~16.2.0",
"@angular-eslint/template-parser": "~16.2.0",
"@angular/animations": "~16.2.0",
"@angular/cli": "~16.2.0",
"@angular/common": "~16.2.0",
"@angular/compiler": "~16.2.0",
"@angular/compiler-cli": "~16.2.0",
"@angular/core": "~16.2.0",
"@angular/forms": "~16.2.0",
"@angular/language-service": "~16.2.0",
"@angular/localize": "~16.2.0",
"@angular/platform-browser": "~16.2.0",
"@angular/platform-browser-dynamic": "~16.2.0",
"@angular/router": "~16.2.0",
"@fortawesome/fontawesome-free": "^5.0.0",
"@abp/ng.theme.lepton-x": "~2.4.0",
"@abp/utils": "~7.4.0",
"@angular-devkit/build-angular": "~17.0.0",
"@angular-devkit/core": "~17.0.0",
"@angular-devkit/schematics": "~17.0.0",
"@angular-devkit/schematics-cli": "~17.0.0",
"@angular-eslint/eslint-plugin": "~17.0.0",
"@angular-eslint/eslint-plugin-template": "~17.0.0",
"@angular-eslint/template-parser": "~17.0.0",
"@angular/animations": "~17.0.0",
"@angular/cli": "~17.0.0",
"@angular/common": "~17.0.0",
"@angular/compiler": "~17.0.0",
"@angular/compiler-cli": "~17.0.0",
"@angular/core": "~17.0.0",
"@angular/forms": "~17.0.0",
"@angular/language-service": "~17.0.0",
"@angular/localize": "~17.0.0",
"@angular/platform-browser": "~17.0.0",
"@angular/platform-browser-dynamic": "~17.0.0",
"@angular/router": "~17.0.0",
"@fortawesome/fontawesome-free": "^6.0.0",
"@ng-bootstrap/ng-bootstrap": "^15.0.0",
"@ngneat/spectator": "^10.0.0",
"@ngneat/spectator": "^15.0.0",
"@ngx-validate/core": "^0.2.0",
"@nx/angular": "16.9.0",
"@nx/cypress": "16.9.0",
"@nx/eslint-plugin": "16.9.0",
"@nx/jest": "16.9.0",
"@nx/js": "16.9.0",
"@nx/linter": "16.9.0",
"@nx/workspace": "16.9.0",
"@nx/angular": "~17.1.0",
"@nx/cypress": "~17.1.0",
"@nx/eslint-plugin": "~17.1.0",
"@nx/jest": "~17.1.0",
"@nx/js": "~17.1.0",
"@nx/workspace": "~17.1.0",
"@popperjs/core": "~2.11.0",
"@schematics/angular": "~16.2.0",
"@swc-node/register": "~1.4.0",
"@schematics/angular": "17.0.0",
"@swc-node/register": "1.6.8",
"@swc/cli": "~0.1.0",
"@swc/core": "1.3.94",
"@swimlane/ngx-datatable": "^20.0.0",
"@types/jest": "29.4.4",
"@types/node": "20.2.5",
"@typescript-eslint/eslint-plugin": "5.62.0",
"@typescript-eslint/parser": "5.62.0",
"@typescript-eslint/eslint-plugin": "6.9.1",
"@typescript-eslint/parser": "6.9.1",
"angular-oauth2-oidc": "^15.0.0",
"bootstrap": "^5.0.0",
"bootstrap-icons": "^1.0.0",
@ -93,23 +92,22 @@
"cypress": "^7.0.0",
"dotenv": "10.0.0",
"eslint": "8.46.0",
"eslint-config-prettier": "8.1.0",
"eslint-plugin-cypress": "2.15.1",
"got": "^11.0.0",
"eslint-config-prettier": "9.0.0",
"eslint-plugin-cypress": "^2.10.3",
"jest": "^29.0.0",
"got": "^11.0.0",
"jest": "^29.0.0",
"jest-canvas-mock": "^2.0.0",
"jest-environment-jsdom": "^29.0.0",
"jest-preset-angular": "13.1.0",
"jest-preset-angular": "13.1.3",
"jsonc-eslint-parser": "^2.0.0",
"jsonc-parser": "^2.0.0",
"just-clone": "^6.0.0",
"just-compare": "^2.0.0",
"lerna": "^4.0.0",
"lint-staged": "^13.0.0",
"ng-packagr": "~16.2.0",
"ng-zorro-antd": "^16.0.0",
"nx": "16.9.0",
"ng-packagr": "17.0.0",
"ng-zorro-antd": "^15.0.0",
"nx": "~17.1.0",
"perfect-scrollbar": "^1.0.0",
"postcss": "^8.0.0",
"postcss-import": "14.1.0",
@ -124,11 +122,12 @@
"ts-toolbelt": "6.15.4",
"tslib": "^2.0.0",
"tslint": "~6.1.0",
"typescript": "5.1.6",
"zone.js": "~0.13.0",
"@nx/devkit": "16.9.0",
"@nx/plugin": "16.9.0",
"@swc/helpers": "0.5.3"
"typescript": "~5.2.0",
"zone.js": "0.14.2",
"@nx/devkit": "~17.1.0",
"@nx/plugin": "~17.1.0",
"@swc/helpers": "0.5.3",
"@nx/eslint": "~17.1.0"
},
"lint-staged": {
"**/*.{js,jsx,ts,tsx,html,css,scss}": [

5
npm/ng-packs/packages/account-core/project.json

@ -25,12 +25,11 @@
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/packages/account-core"],
"options": {
"jestConfig": "packages/account-core/jest.config.ts",
"passWithNoTests": true
"jestConfig": "packages/account-core/jest.config.ts"
}
},
"lint": {
"executor": "@nx/linter:eslint",
"executor": "@nx/eslint:lint",
"options": {
"lintFilePatterns": [
"packages/account-core/src/**/*.ts",

5
npm/ng-packs/packages/account/project.json

@ -25,12 +25,11 @@
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/packages/account"],
"options": {
"jestConfig": "packages/account/jest.config.ts",
"passWithNoTests": true
"jestConfig": "packages/account/jest.config.ts"
}
},
"lint": {
"executor": "@nx/linter:eslint",
"executor": "@nx/eslint:lint",
"options": {
"lintFilePatterns": ["packages/account/src/**/*.ts", "packages/account/src/**/*.html"]
},

7
npm/ng-packs/packages/components/extensible/src/lib/components/date-time-picker/extensible-date-time-picker.component.ts

@ -7,19 +7,24 @@ import {
SkipSelf,
ViewChild,
} from '@angular/core';
import { ControlContainer } from '@angular/forms';
import { ControlContainer, ReactiveFormsModule } from '@angular/forms';
import {
NgbDateAdapter,
NgbDatepickerModule,
NgbInputDatepicker,
NgbTimeAdapter,
NgbTimepicker,
NgbTimepickerModule,
} from '@ng-bootstrap/ng-bootstrap';
import { FormProp } from '../../models/form-props';
import { selfFactory } from '../../utils/factory.util';
import { DateTimeAdapter } from '@abp/ng.theme.shared';
import { CommonModule } from '@angular/common';
@Component({
exportAs: 'abpExtensibleDateTimePicker',
standalone: true,
imports: [CommonModule, NgbDatepickerModule, ReactiveFormsModule, NgbTimepickerModule],
selector: 'abp-extensible-date-time-picker',
template: `
<input

2
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form-prop.component.html

@ -124,7 +124,7 @@
<ng-template ngSwitchCase="dateTime">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<abp-extensible-date-time-picker [prop]="prop" [meridian]="meridian" />
<abp-extensible-date-time-picker [prop]="prop" [meridian]="meridian$ | async" />
</ng-template>
<ng-template ngSwitchCase="textarea">

133
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form-prop.component.ts

@ -1,11 +1,12 @@
import { EXTENSIONS_FORM_PROP, EXTENSIONS_FORM_PROP_DATA } from './../../tokens/extensions.token';
import { ABP, AbpValidators, ConfigStateService, TrackByService } from '@abp/ng.core';
import { ABP, CoreModule, TrackByService } from '@abp/ng.core';
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
inject,
Injector,
Input,
OnChanges,
@ -17,26 +18,53 @@ import {
import {
ControlContainer,
FormGroupDirective,
UntypedFormGroup,
ReactiveFormsModule,
ValidatorFn,
Validators,
} from '@angular/forms';
import { NgbDateAdapter, NgbTimeAdapter } from '@ng-bootstrap/ng-bootstrap';
import {
NgbDateAdapter,
NgbDatepickerModule,
NgbTimeAdapter,
NgbTimepickerModule,
NgbTypeaheadModule,
} from '@ng-bootstrap/ng-bootstrap';
import { Observable, of } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
import { DateAdapter, TimeAdapter } from '@abp/ng.theme.shared';
import {
DateAdapter,
DisabledDirective,
PasswordComponent,
TimeAdapter,
} from '@abp/ng.theme.shared';
import { EXTRA_PROPERTIES_KEY } from '../../constants/extra-properties';
import { ePropType } from '../../enums/props.enum';
import { FormProp } from '../../models/form-props';
import { PropData } from '../../models/props';
import { selfFactory } from '../../utils/factory.util';
import { addTypeaheadTextSuffix } from '../../utils/typeahead.util';
import { eThemeSharedComponents } from "../../enums/components";
import { eThemeSharedComponents } from '../../enums/components';
import { ExtensibleDateTimePickerComponent } from '../date-time-picker/extensible-date-time-picker.component';
import { NgxValidateCoreModule } from '@ngx-validate/core';
import { ExtensibleFormPropService } from '../../services/extensible-form-prop.service';
import {CreateInjectorPipe} from "../../pipes/create-injector.pipe";
@Component({
selector: 'abp-extensible-form-prop',
templateUrl: './extensible-form-prop.component.html',
standalone: true,
imports: [
CoreModule,
ExtensibleDateTimePickerComponent,
NgbDatepickerModule,
NgbTimepickerModule,
ReactiveFormsModule,
DisabledDirective,
NgxValidateCoreModule,
NgbTypeaheadModule,
PasswordComponent,
CreateInjectorPipe
],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [ExtensibleFormPropService],
viewProviders: [
{
provide: ControlContainer,
@ -48,32 +76,27 @@ import { eThemeSharedComponents } from "../../enums/components";
],
})
export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
@Input() data!: PropData;
protected service = inject(ExtensibleFormPropService);
public readonly cdRef = inject(ChangeDetectorRef);
public readonly track = inject(TrackByService);
#groupDirective = inject(FormGroupDirective);
private injector = inject(Injector);
private readonly form = this.#groupDirective.form;
@Input() data!: PropData;
@Input() prop!: FormProp;
@Input() first?: boolean;
@ViewChild('field') private fieldRef!: ElementRef<HTMLElement>;
public injectorForCustomComponent?: Injector;
injectorForCustomComponent?: Injector;
asterisk = '';
containerClassName = 'mb-2';
options$: Observable<ABP.Option<any>[]> = of([]);
validators: ValidatorFn[] = [];
readonly!: boolean;
typeaheadModel: any;
passwordKey = eThemeSharedComponents.PasswordComponent;
private readonly form: UntypedFormGroup;
disabledFn = (data: PropData) => false;
get disabled() {
@ -100,27 +123,13 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
typeaheadFormatter = (option: ABP.Option<any>) => option.key;
get meridian() {
return (
this.configState.getDeep('localization.currentCulture.dateTimeFormat.shortTimePattern') || ''
).includes('tt');
}
meridian$ = this.service.meridian$;
get isInvalid() {
const control = this.form.get(this.prop.name);
return control?.touched && control.invalid;
}
constructor(
public readonly cdRef: ChangeDetectorRef,
public readonly track: TrackByService,
protected configState: ConfigStateService,
groupDirective: FormGroupDirective,
private injector: Injector,
) {
this.form = groupDirective.form;
}
private getTypeaheadControls() {
const { name } = this.prop;
const extraPropName = `${EXTRA_PROPERTIES_KEY}.${name}`;
@ -132,7 +141,7 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
}
private setAsterisk() {
this.asterisk = this.validators.some(isRequired) ? '*' : '';
this.asterisk = this.service.calcAsterisks(this.validators);
}
ngAfterViewInit() {
@ -143,51 +152,11 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
}
getComponent(prop: FormProp): string {
if (prop.template) {
return 'template';
}
switch (prop.type) {
case ePropType.Boolean:
return 'checkbox';
case ePropType.Date:
return 'date';
case ePropType.DateTime:
return 'dateTime';
case ePropType.Hidden:
return 'hidden';
case ePropType.MultiSelect:
return 'multiselect';
case ePropType.Text:
return 'textarea';
case ePropType.Time:
return 'time';
case ePropType.Typeahead:
return 'typeahead';
case ePropType.PasswordInputGroup:
return 'passwordinputgroup';
default:
return prop.options ? 'select' : 'input';
}
return this.service.getComponent(prop);
}
getType(prop: FormProp): string {
switch (prop.type) {
case ePropType.Date:
case ePropType.String:
return 'text';
case ePropType.Boolean:
return 'checkbox';
case ePropType.Number:
return 'number';
case ePropType.Email:
return 'email';
case ePropType.Password:
return 'password';
case ePropType.PasswordInputGroup:
return 'passwordinputgroup';
default:
return 'hidden';
}
return this.service.getType(prop);
}
ngOnChanges({ prop, data }: SimpleChanges) {
@ -229,11 +198,3 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
this.typeaheadModel = { key: keyControl.value, value: valueControl.value };
}
}
function isRequired(validator: ValidatorFn) {
return (
validator === Validators.required ||
validator === AbpValidators.required ||
validator.name === 'required'
);
}

123
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form.component.ts

@ -1,73 +1,76 @@
import { TrackByService } from '@abp/ng.core';
import {TrackByService} from '@abp/ng.core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
Inject,
Input,
Optional,
QueryList,
SkipSelf,
ViewChildren,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component, inject,
Input,
Optional,
QueryList,
SkipSelf,
ViewChildren,
} from '@angular/core';
import { ControlContainer, UntypedFormGroup } from '@angular/forms';
import { EXTRA_PROPERTIES_KEY } from '../../constants/extra-properties';
import { FormPropList, GroupedFormPropList } from '../../models/form-props';
import { ExtensionsService } from '../../services/extensions.service';
import { EXTENSIONS_IDENTIFIER } from '../../tokens/extensions.token';
import { selfFactory } from '../../utils/factory.util';
import { ExtensibleFormPropComponent } from './extensible-form-prop.component';
import {ControlContainer, ReactiveFormsModule, UntypedFormGroup} from '@angular/forms';
import {EXTRA_PROPERTIES_KEY} from '../../constants/extra-properties';
import {FormPropList, GroupedFormPropList} from '../../models/form-props';
import {ExtensionsService} from '../../services/extensions.service';
import {EXTENSIONS_IDENTIFIER} from '../../tokens/extensions.token';
import {selfFactory} from '../../utils/factory.util';
import {ExtensibleFormPropComponent} from './extensible-form-prop.component';
import {CommonModule} from "@angular/common";
import {PropDataDirective} from "../../directives/prop-data.directive";
@Component({
exportAs: 'abpExtensibleForm',
selector: 'abp-extensible-form',
templateUrl: './extensible-form.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
viewProviders: [
{
provide: ControlContainer,
useFactory: selfFactory,
deps: [[new Optional(), new SkipSelf(), ControlContainer]],
},
],
exportAs: 'abpExtensibleForm',
selector: 'abp-extensible-form',
templateUrl: './extensible-form.component.html',
standalone:true,
imports:[CommonModule, PropDataDirective,ReactiveFormsModule,ExtensibleFormPropComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
viewProviders: [
{
provide: ControlContainer,
useFactory: selfFactory,
deps: [[new Optional(), new SkipSelf(), ControlContainer]],
},
],
})
export class ExtensibleFormComponent<R = any> {
@ViewChildren(ExtensibleFormPropComponent)
formProps!: QueryList<ExtensibleFormPropComponent>;
@Input()
set selectedRecord(record: R) {
const type = !record || JSON.stringify(record) === '{}' ? 'create' : 'edit';
const propList = this.extensions[`${type}FormProps`].get(this.identifier).props;
this.groupedPropList = this.createGroupedList(propList);
this.record = record;
}
@ViewChildren(ExtensibleFormPropComponent)
formProps!: QueryList<ExtensibleFormPropComponent>;
extraPropertiesKey = EXTRA_PROPERTIES_KEY;
groupedPropList!: GroupedFormPropList;
record!: R;
@Input()
set selectedRecord(record: R) {
const type = !record || JSON.stringify(record) === '{}' ? 'create' : 'edit';
const propList = this.extensions[`${type}FormProps`].get(this.identifier).props;
this.groupedPropList = this.createGroupedList(propList);
this.record = record;
}
createGroupedList(propList: FormPropList<R>) {
const groupedFormPropList = new GroupedFormPropList();
propList.forEach(item => {
groupedFormPropList.addItem(item.value);
});
return groupedFormPropList;
}
extraPropertiesKey = EXTRA_PROPERTIES_KEY;
groupedPropList!: GroupedFormPropList;
record!: R;
get form(): UntypedFormGroup {
return (this.container ? this.container.control : { controls: {} }) as UntypedFormGroup;
}
public readonly cdRef = inject(ChangeDetectorRef)
public readonly track = inject(TrackByService)
private container = inject(ControlContainer)
private extensions = inject(ExtensionsService);
private identifier = inject(EXTENSIONS_IDENTIFIER)
get extraProperties(): UntypedFormGroup {
return (this.form.controls.extraProperties || { controls: {} }) as UntypedFormGroup;
}
createGroupedList(propList: FormPropList<R>) {
const groupedFormPropList = new GroupedFormPropList();
propList.forEach(item => {
groupedFormPropList.addItem(item.value);
});
return groupedFormPropList;
}
get form(): UntypedFormGroup {
return (this.container ? this.container.control : {controls: {}}) as UntypedFormGroup;
}
get extraProperties(): UntypedFormGroup {
return (this.form.controls.extraProperties || {controls: {}}) as UntypedFormGroup;
}
constructor(
public readonly cdRef: ChangeDetectorRef,
public readonly track: TrackByService,
private container: ControlContainer,
private extensions: ExtensionsService,
@Inject(EXTENSIONS_IDENTIFIER) private identifier: string,
) {}
}

2
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.html

@ -44,7 +44,7 @@
</ng-template>
<ng-template let-row="row" let-i="index" ngx-datatable-cell-template>
<ng-container *abpPermission="prop.permission; runChangeDetection: false">
<ng-container *ngIf="row['_' + prop.name]?.visible">
<ng-container *abpVisible="row['_' + prop.name]?.visible">
<div
*ngIf="!row['_' + prop.name].component; else component"
[innerHTML]="row['_' + prop.name]?.value | async"

55
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts

@ -1,6 +1,7 @@
import {
ABP,
ConfigStateService,
CoreModule,
getShortDateFormat,
getShortDateShortTimeFormat,
getShortTimeFormat,
@ -12,7 +13,7 @@ import {
ChangeDetectionStrategy,
Component,
EventEmitter,
Inject,
inject,
Injector,
Input,
LOCALE_ID,
@ -31,16 +32,33 @@ import { PropData } from '../../models/props';
import { ExtensionsService } from '../../services/extensions.service';
import {
ENTITY_PROP_TYPE_CLASSES,
EntityPropTypeClass,
EXTENSIONS_IDENTIFIER,
PROP_DATA_STREAM,
} from '../../tokens/extensions.token';
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
import { GridActionsComponent } from '../grid-actions/grid-actions.component';
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap';
import {
AbpVisibleDirective,
NgxDatatableDefaultDirective,
NgxDatatableListDirective,
} from '@abp/ng.theme.shared';
const DEFAULT_ACTIONS_COLUMN_WIDTH = 150;
@Component({
@Component({
exportAs: 'abpExtensibleTable',
selector: 'abp-extensible-table',
standalone: true,
imports: [
CoreModule,
AbpVisibleDirective,
NgxDatatableModule,
GridActionsComponent,
NgbTooltip,
NgxDatatableDefaultDirective,
NgxDatatableListDirective,
],
templateUrl: './extensible-table.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
@ -50,6 +68,7 @@ export class ExtensibleTableComponent<R = any> implements OnChanges {
set actionsText(value: string) {
this._actionsText = value;
}
get actionsText(): string {
return this._actionsText ?? (this.actionList.length > 1 ? 'AbpUi::Actions' : '');
}
@ -57,19 +76,17 @@ export class ExtensibleTableComponent<R = any> implements OnChanges {
@Input() data!: R[];
@Input() list!: ListService;
@Input() recordsTotal!: number;
@Input() set actionsColumnWidth(width: number) {
this.setColumnWidths(width ? Number(width) : undefined);
}
@Input() actionsTemplate?: TemplateRef<any>;
@Output() tableActivate = new EventEmitter();
getInjected: typeof this.injector.get
hasAtLeastOnePermittedAction: boolean;
entityPropTypeClasses: EntityPropTypeClass;
readonly columnWidths!: number[];
readonly propList: EntityPropList<R>;
@ -78,20 +95,20 @@ export class ExtensibleTableComponent<R = any> implements OnChanges {
readonly trackByFn: TrackByFunction<EntityProp<R>> = (_, item) => item.name;
constructor(
@Inject(LOCALE_ID) private locale: string,
private config: ConfigStateService,
private injector: Injector,
) {
this.entityPropTypeClasses = injector.get(ENTITY_PROP_TYPE_CLASSES);
this.getInjected = injector.get.bind(injector);
const extensions = injector.get(ExtensionsService);
const name = injector.get(EXTENSIONS_IDENTIFIER);
locale = inject(LOCALE_ID);
private config = inject(ConfigStateService);
entityPropTypeClasses = inject(ENTITY_PROP_TYPE_CLASSES);
#injector = inject(Injector);
getInjected = this.#injector.get.bind(this.#injector);
constructor() {
const extensions = this.#injector.get(ExtensionsService);
const name = this.#injector.get(EXTENSIONS_IDENTIFIER);
this.propList = extensions.entityProps.get(name).props;
this.actionList = extensions['entityActions'].get(name)
.actions as unknown as EntityActionList<R>;
const permissionService = injector.get(PermissionService);
const permissionService = this.#injector.get(PermissionService);
this.hasAtLeastOnePermittedAction =
permissionService.filterItemsByPolicy(
this.actionList.toArray().map(action => ({ requiredPolicy: action.permission })),
@ -149,7 +166,7 @@ export class ExtensibleTableComponent<R = any> implements OnChanges {
if (!data?.currentValue) return;
if (data.currentValue.length < 1) {
this.list.totalCount = this.recordsTotal
this.list.totalCount = this.recordsTotal;
}
this.data = data.currentValue.map((record: any, index: number) => {
@ -170,7 +187,7 @@ export class ExtensibleTableComponent<R = any> implements OnChanges {
useValue: value,
},
],
parent: this.injector,
parent: this.#injector,
});
record[propKey].component = prop.value.component;
}

5
npm/ng-packs/packages/components/extensible/src/lib/components/grid-actions/grid-actions.component.ts

@ -8,9 +8,14 @@ import {
import { EntityAction, EntityActionList } from '../../models/entity-actions';
import { EXTENSIONS_ACTION_TYPE } from '../../tokens/extensions.token';
import { AbstractActionsComponent } from '../abstract-actions/abstract-actions.component';
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { CoreModule } from '@abp/ng.core';
import {EllipsisDirective} from "@abp/ng.theme.shared";
@Component({
exportAs: 'abpGridActions',
standalone: true,
imports: [ CoreModule, NgbDropdownModule, EllipsisDirective],
selector: 'abp-grid-actions',
templateUrl: './grid-actions.component.html',
providers: [

5
npm/ng-packs/packages/components/extensible/src/lib/components/page-toolbar/page-toolbar.component.ts

@ -8,10 +8,14 @@ import {
} from '../../models/toolbar-actions';
import { EXTENSIONS_ACTION_TYPE } from '../../tokens/extensions.token';
import { AbstractActionsComponent } from '../abstract-actions/abstract-actions.component';
import { CreateInjectorPipe } from '../../pipes/create-injector.pipe';
import { CoreModule } from '@abp/ng.core';
@Component({
exportAs: 'abpPageToolbar',
selector: 'abp-page-toolbar',
standalone: true,
imports: [ CoreModule, CreateInjectorPipe],
templateUrl: './page-toolbar.component.html',
providers: [
{
@ -31,6 +35,7 @@ export class PageToolbarComponent<R = any>
readonly trackByFn: TrackByFunction<ToolbarComponent<R>> = (_, item) =>
item.action || item.component;
constructor(public readonly injector: Injector) {
super(injector);
}

1
npm/ng-packs/packages/components/extensible/src/lib/directives/prop-data.directive.ts

@ -13,6 +13,7 @@ import { PropData, PropList } from '../models/props';
@Directive({
exportAs: 'abpPropData',
selector: '[abpPropData]',
standalone: true,
})
export class PropDataDirective<L extends PropList<any>>
extends PropData<InferredData<L>>

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

Loading…
Cancel
Save