Browse Source

Merge branch 'dev' into denizdemirkan/L

pull/18178/head
denizdemirkan 3 years ago
parent
commit
ef63be955f
  1. 24
      .github/workflows/auto-pr.yml
  2. 8
      Directory.Packages.props
  3. 3
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
  4. 7
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  5. 35
      abp_io/README.md
  6. 6
      common.props
  7. 223
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/POST.md
  8. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/account-module-register.png
  9. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/community-talk-2023-8.png
  10. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/cover-image.png
  11. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/identity-users.gif
  12. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/password-complexity-indicators.png
  13. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/suite-master-child-datagrid.png
  14. BIN
      docs/en/Blog-Posts/2023-11-15 v8_0_Preview/users-page.png
  15. 1
      docs/en/Community-Articles/2023-11-06-Blazor-Fullstack-Web-Ui/Post.md
  16. 0
      docs/en/Community-Articles/2023-11-17-AOT-Compilation/Post.md
  17. 30
      docs/en/Dapr/Index.md
  18. 18
      docs/en/Dependency-Injection.md
  19. 10
      docs/en/Distributed-Event-Bus-RabbitMQ-Integration.md
  20. 64
      docs/en/Dynamic-Claims.md
  21. 16
      docs/en/Migration-Guides/Abp-8_0.md
  22. 2
      docs/en/Modules/OpenIddict.md
  23. 15
      docs/en/Road-Map.md
  24. 39
      docs/en/Themes/LeptonXLite/Blazor.md
  25. 0
      docs/en/UI/Angular/Caps-Lock-Directive.md
  26. 8
      docs/en/docs-nav.json
  27. 30
      docs/zh-Hans/Dapr/Index.md
  28. 18
      docs/zh-Hans/Dependency-Injection.md
  29. 10
      docs/zh-Hans/Distributed-Event-Bus-RabbitMQ-Integration.md
  30. 25
      docs/zh-Hans/Local-Event-Bus.md
  31. 418
      framework/Volo.Abp.abpmdl
  32. 2
      framework/Volo.Abp.abpsln
  33. 0
      framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo.Abp.ApiVersioning.Abstractions.abppkg
  34. 36
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/Extensions/DependencyInjection/AbpJwtBearerExtensions.cs
  35. 0
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.abppkg
  36. 2
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj
  37. 19
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/AbpAspNetCoreAuthenticationJwtBearerModule.cs
  38. 10
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributor.cs
  39. 75
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorCache.cs
  40. 16
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorOptions.cs
  41. 0
      framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.abppkg
  42. 13
      framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Microsoft/Extensions/DependencyInjection/AbpOpenIdConnectExtensions.cs
  43. 0
      framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo.Abp.AspNetCore.Authentication.OpenIdConnect.abppkg
  44. 0
      framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Volo.Abp.AspNetCore.Components.Server.Theming.abppkg
  45. 0
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.abppkg
  46. 9
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
  47. 20
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs
  48. 0
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Volo.Abp.AspNetCore.Components.Web.Theming.abppkg
  49. 0
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo.Abp.AspNetCore.Components.Web.abppkg
  50. 4
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpBlazorMessageLocalizerHelper.cs
  51. 7
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Security/AbpComponentsClaimsCache.cs
  52. 0
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.abppkg
  53. 0
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo.Abp.AspNetCore.Components.WebAssembly.abppkg
  54. 8
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Extensibility/WebAssemblyLookupApiRequestService.cs
  55. 0
      framework/src/Volo.Abp.AspNetCore.Components/Volo.Abp.AspNetCore.Components.abppkg
  56. 0
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo.Abp.AspNetCore.MultiTenancy.abppkg
  57. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo.Abp.AspNetCore.Mvc.Client.Common.abppkg
  58. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCommonModule.cs
  59. 40
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributor.cs
  60. 31
      framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteDynamicClaimsPrincipalContributorCache.cs
  61. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.abppkg
  62. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.abppkg
  63. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.abppkg
  64. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo.Abp.AspNetCore.Mvc.Dapr.abppkg
  65. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson.abppkg
  66. 22
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs
  67. 22
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs
  68. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.abppkg
  69. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions.abppkg
  70. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo.Abp.AspNetCore.Mvc.UI.Bundling.abppkg
  71. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.abppkg
  72. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo.Abp.AspNetCore.Mvc.UI.Packages.abppkg
  73. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.abppkg
  74. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.abppkg
  75. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.abppkg
  76. 0
      framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.abppkg
  77. 0
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.abppkg
  78. 0
      framework/src/Volo.Abp.AspNetCore.Serilog/Volo.Abp.AspNetCore.Serilog.abppkg
  79. 0
      framework/src/Volo.Abp.AspNetCore.SignalR/Volo.Abp.AspNetCore.SignalR.abppkg
  80. 0
      framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.abppkg
  81. 0
      framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.abppkg
  82. 0
      framework/src/Volo.Abp.Auditing.Contracts/Volo.Abp.Auditing.Contracts.abppkg
  83. 0
      framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.abppkg
  84. 0
      framework/src/Volo.Abp.Authorization.Abstractions/Volo.Abp.Authorization.Abstractions.abppkg
  85. 0
      framework/src/Volo.Abp.Authorization/Volo.Abp.Authorization.abppkg
  86. 0
      framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.abppkg
  87. 0
      framework/src/Volo.Abp.Autofac.WebAssembly/Volo.Abp.Autofac.WebAssembly.abppkg
  88. 25
      framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs
  89. 5
      framework/src/Volo.Abp.Autofac/Autofac/Extensions/DependencyInjection/AutofacRegistration.cs
  90. 0
      framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.abppkg
  91. 0
      framework/src/Volo.Abp.AzureServiceBus/Volo.Abp.AzureServiceBus.abppkg
  92. 0
      framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo.Abp.BackgroundJobs.Abstractions.abppkg
  93. 0
      framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo.Abp.BackgroundJobs.HangFire.abppkg
  94. 0
      framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo.Abp.BackgroundJobs.Quartz.abppkg
  95. 0
      framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo.Abp.BackgroundJobs.RabbitMQ.abppkg
  96. 0
      framework/src/Volo.Abp.BackgroundJobs/Volo.Abp.BackgroundJobs.abppkg
  97. 0
      framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo.Abp.BackgroundWorkers.Hangfire.abppkg
  98. 0
      framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo.Abp.BackgroundWorkers.Quartz.abppkg
  99. 0
      framework/src/Volo.Abp.BackgroundWorkers/Volo.Abp.BackgroundWorkers.abppkg
  100. 0
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo.Abp.BlobStoring.Aliyun.abppkg

24
.github/workflows/auto-pr.yml

@ -1,13 +1,13 @@
name: Merge branch dev with rel-7.4
name: Merge branch dev with rel-8.0
on:
push:
branches:
- rel-7.4
- rel-8.0
permissions:
contents: read
jobs:
merge-dev-with-rel-7-4:
merge-dev-with-rel-8-0:
permissions:
contents: write # for peter-evans/create-pull-request to create branch
pull-requests: write # for peter-evans/create-pull-request to create a PR
@ -18,13 +18,19 @@ jobs:
ref: dev
- name: Reset promotion branch
run: |
git fetch origin rel-7.4:rel-7.4
git reset --hard rel-7.4
git fetch origin rel-8.0:rel-8.0
git reset --hard rel-8.0
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
branch: auto-merge/rel-7-4/${{github.run_number}}
title: Merge branch dev with rel-7.4
body: This PR generated automatically to merge dev with rel-7.4. Please review the changed files before merging to prevent any errors that may occur.
reviewers: ${{github.actor}}
branch: auto-merge/rel-8-0/${{github.run_number}}
title: Merge branch dev with rel-8.0
body: This PR generated automatically to merge dev with rel-8.0. Please review the changed files before merging to prevent any errors that may occur.
reviewers: maliming
token: ${{ github.token }}
- name: Merge Pull Request
env:
GH_TOKEN: ${{ secrets.BOT_SECRET }}
run: |
gh pr review auto-merge/rel-8-0/${{github.run_number}} --approve
gh pr merge auto-merge/rel-8-0/${{github.run_number}} --merge --auto --delete-branch

8
Directory.Packages.props

@ -107,7 +107,7 @@
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Nito.AsyncEx.Context" Version="5.1.2" />
<PackageVersion Include="Nito.AsyncEx.Coordination" Version="5.1.2" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0-rc.2" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
<PackageVersion Include="NSubstitute" Version="5.1.0" />
<PackageVersion Include="NuGet.Versioning" Version="6.7.0" />
<PackageVersion Include="NUglify" Version="1.21.0" />
@ -121,14 +121,14 @@
<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="Pomelo.EntityFrameworkCore.MySql" Version="8.0.0-beta.2" />
<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.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="Rebus" Version="8.0.1" />
<PackageVersion Include="Rebus.ServiceProvider" Version="10.0.0" />
<PackageVersion Include="Scriban" Version="5.9.0" />
<PackageVersion Include="Serilog" Version="3.1.1" />
<PackageVersion Include="Serilog.AspNetCore" Version="8.0.0" />

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

@ -229,6 +229,7 @@
"ManageAccount": "Manage Account",
"CommunityProfile": "Community Profile",
"BlogProfile": "Blog Profile",
"Tickets": "Tickets"
"Tickets": "Tickets",
"Videos": "Videos"
}
}

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

@ -437,6 +437,11 @@
"Testimonials": "Testimonials",
"CoolestCompaniesUseABPFramework": "Coolest Companies Use <span class=\"fw-bold\">ABP Framework</span>",
"Index_Page_Testimonial_1": "ABP Framework is not just a tool but a catalyst that has accelerated my growth as a developer. It has made it possible for me to build new features faster than ever before, reminiscent of the experiences of other users. The unified coding pattern has streamlined my projects, giving me more time to focus on creating rather than troubleshooting.\nI would say the ABP Framework has been the cornerstone of my early professional journey. It has facilitated my transition from an aspiring developer to a confident professional ready to make a mark in the software world. I am looking forward to the exciting projects that await me, knowing that ABP will be there to guide me. It is more than just a product; it's a partner in success.",
"Index_Page_Testimonial_2": "ABP Framework is not only a framework, it is also a guidance for project development/management, because it provides DDD, GenericRepository, DI, Microservice, Modularity trainings. Even if you are not going to use framework itself, you can develop yourself with docs.abp.io which is well and professionally prepared. (OpenIddict, Redis, Quartz etc.)\nBecause many thing pre-built, it shortens project development time significantly. (Such as login page, exception handling, data filtering-seeding, audit logging, localization, auto api controller etc.)\nAs an example from our app, i have used Local Event Bus for stock control. So, I am able to manage order movements by writing stock handler.\nIt is wonderful not to lose time for CreationTime, CreatorId. They are filled automatically."
"Index_Page_Testimonial_2": "ABP Framework is not only a framework, it is also a guidance for project development/management, because it provides DDD, GenericRepository, DI, Microservice, Modularity trainings. Even if you are not going to use framework itself, you can develop yourself with docs.abp.io which is well and professionally prepared. (OpenIddict, Redis, Quartz etc.)\nBecause many thing pre-built, it shortens project development time significantly. (Such as login page, exception handling, data filtering-seeding, audit logging, localization, auto api controller etc.)\nAs an example from our app, i have used Local Event Bus for stock control. So, I am able to manage order movements by writing stock handler.\nIt is wonderful not to lose time for CreationTime, CreatorId. They are filled automatically.",
"VideosLoginAndRegisterMessage": "To be able to watch videos, you must sign in.",
"Filter": "Filter",
"VideoCourses": "Video Courses"
}
}

35
abp_io/README.md

@ -1,11 +1,32 @@
## Abp.io platform localization
## ABP Platform Websites Localization
This project is all localized resources of the abp.io platform.
This is the localization project of [abp.io platform](https://abp.io).
All *.abp.io websites are built on top of ABP Framework, and it uses ABP Framework's localization system.
You can correct a wrong localization text, or you can translate it into your own language.
By doing so, [abp.io](https://abp.io) websites will be translated into a new language and it will help to expand the ABP Community.
If you like, you can contribute to the localization resources in this project.
For example: `AbpIoLocalization\AbpIoLocalization\Www\Localization\Resources\zh-Hans.json`
If the file is missing some translations or the translation is wrong, you can add it.
If the language file is missing (eg `kr.json`), you can also add it.
Please refer to the [Contribution Guide](https://github.com/abpframework/abp/blob/dev/docs/en/Contribution/Index.md) for details.
## How to Translate abp.io Into Your Language:
1. Install [ABP CLI](https://docs.abp.io/en/abp/latest/CLI) command line tool.
2. Run the following command to generate the localization file.
For example, for translating from English to French `fr`:
```bash
abp translate -c fr
```
3. After you fill in the empty localization keys, run the following command to apply it.
```bash
abp translate -a
```
4. Send your PR to the team; after the review process, we wil merge it.
---
## References:
* [ABP CLI Translate Command](https://docs.abp.io/en/abp/latest/Contribution/Index#using-the-abp-translate-command)
* [Contribution Guide](https://github.com/abpframework/abp/blob/dev/docs/en/Contribution/Index.md)

6
common.props

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>8.0.0</Version>
<Version>8.1.0</Version>
<NoWarn>$(NoWarn);CS1591;CS0436</NoWarn>
<PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>https://abp.io/</PackageProjectUrl>
@ -29,8 +29,8 @@
<Pack>true</Pack>
<PackagePath>content\</PackagePath>
</Content>
<None Remove="*.abppkg.json" />
<Content Include="*.abppkg.json">
<None Remove="*.abppkg" />
<Content Include="*.abppkg">
<Pack>true</Pack>
<PackagePath>content\</PackagePath>
</Content>

223
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/POST.md

@ -0,0 +1,223 @@
# ABP.IO Platform 8.0 RC Has Been Released
Today, we are happy to release the [ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) version **8.0 RC** (Release Candidate). This blog post introduces the new features and important changes in this new version.
Try this version and provide feedback for a more stable version of ABP v8.0! Thanks to all of you.
## Get Started with the 8.0 RC
Follow the steps below to try version 8.0.0 RC today:
1) **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
````
2) Create a **new application** with the `--preview` option:
````bash
abp new BookStore --preview
````
See the [ABP CLI documentation](https://docs.abp.io/en/abp/latest/CLI) for all the available options.
> You can also use the [Get Started](https://abp.io/get-started) page to generate a CLI command to create a new application.
You can use any IDE that supports .NET 8.x, like [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/).
## Migration Guides
There are a few breaking changes in this version that may affect your application.
Please see the following migration documents, if you are upgrading from v7.x or earlier:
* [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)
## What's New with ABP Framework 8.0?
In this section, I will introduce some major features released in this version.
Here is a brief list of titles explained in the next sections:
* Upgraded to .NET 8.0
* Upgraded to Angular 17
* Dynamic Claims
* CDN Support for Bundling & Minification System
* Read-Only Repositories
* Account Module: Set Username After Social/External Login
* Other News...
### Upgraded to .NET 8.0
We've upgraded the ABP Framework to .NET 8.0, so you need to move your solutions to .NET 8.0 if you want to use ABP 8.0. You can check [Microsoft’s Migrate from ASP.NET Core 7.0 to 8.0 documentation](https://learn.microsoft.com/en-us/aspnet/core/migration/70-80), to see how to update an existing ASP.NET Core 7.0 project to ASP.NET Core 8.0.
### Upgraded to Angular 17
Angular 17 [was released on November 8](https://blog.angular.io/introducing-angular-v17-4d7033312e4b) and ABP Framework & ABP Commercial startup templates were immediately migrated to **Angular 17**!
So, when you create a new solution with the Angular UI, you will take advantage of the new Angular with the new cutting-edge features and enhancements right from the start!
### Dynamic Claims
The **Dynamic Claims** feature is used to dynamically generate claims for the user in each request. It's used to automatically and dynamically override the configured claim values in the client's authentication token/cookie by the latest user claims.
In the prior versions, whenever a user changed their email address or confirmed their own email address, or any other information related to the user (and if it's in the claims), he/she would need to logout and then login to refresh its claims. The new **Dynamic Claims** feature overcomes this problem and allows to **always get the latest user claims**.
This feature is disabled by default and you can enable it easily for your existing MVC applications by following the [Dynamic Claims documentation](https://docs.abp.io/en/abp/8.0/Dynamic-Claims). For the other UI options (Angular & Blazor UIs), you don't need to enable this feature, since they obtain claims ftom a configuration endpoint.
> **Note**: Beginning from the v8.0, all the startup templates are pre-configured and the **Dynamic Claims** feature is enabled by default.
### CDN Support for Bundling & Minification System
In this version, ABP Framework's [Bundling & Minification System](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Bundling-Minification) provides CDN support for MVC / Razor Pages UI. The bundling system automatically recognizes the external/CDN files and places them as link/script tags on the page along with the bundled CSS/JSS files.
> Read the documentation for more info: https://docs.abp.io/en/abp/8.0/UI/AspNetCore/Bundling-Minification
### Read-Only Repositories
ABP Framework provides read-only repository interfaces (`IReadOnlyRepository<>` or `IReadOnlyBasicRepository<>`) to explicitly indicate that your purpose is to query data, but not change it. It uses [EF Core's No-Tracking Feature](https://learn.microsoft.com/en-us/ef/core/querying/tracking#no-tracking-queries) behind the scenes, which means the entities returned from the repository will not be tracked by the EF Core's [change tracker](https://learn.microsoft.com/en-us/ef/core/change-tracking/) and thanks to that you get significant performance gains.
```csharp
public class MyService
{
private readonly IReadOnlyRepository<Book, Guid> _bookRepository;
public async Task MyMethod()
{
var books = await _bookRepository.GetListAsync(); //change tracking not involved
//...
}
}
```
> In addition to the read-only repository interfaces, ABP Framework introduces the `IRepository.DisableTracking()` and `IRepository.EnableTracking()` extension methods to allow developers to disable/enable entity tracking by these methods manually. If you don't want to use the read-only repositories, you can use these methods to enable or disable the change tracker controlled. Read the documentation to learn more: [https://docs.abp.io/en/abp/8.0/Repositories#enabling-disabling-the-change-tracking](https://docs.abp.io/en/abp/8.0/Repositories#enabling-disabling-the-change-tracking)
### Account Module: Set Username After Social/External Login
Prior to this version, when you registered with your social accounts for the first time, your email address was becoming your username and it was shown everywhere in the application. Therefore, you would need to update your username later on and this is not a good user experience.
Thus, in this version, we have enhanced this flow, and now, when you register as an external user for the first time, a username and email address are shown you in a form for you to revise and update if you want, before logging into the application. Thanks to that, after the social registration you would not need to update your username and email address. This is also good at the point of GDPR regulations because your email address will not be shown as a username and will not exposed.
![](account-module-register.png)
### Other News
* LDAP over SSL (LDAPS) setting has been added and recommended to establish a secure connection. See [#17865](https://github.com/abpframework/abp/pull/17865) for more information.
* Object Mapping Enhancements (supports mapping collection of objects for custom object mappers).
* Email Sending Improvements (sending attachments with `IEmailSender.QueueAsync()` method).
## What's New with ABP Commercial 8.0?
We've also worked on ABP Commercial to align the features and changes made in the ABP Framework. The following sections introduce a few new features coming with ABP Commercial 8.0.
### Suite: Generating Master/Detail Relationship
In this version, we have introduced the **Master/Detail Relationship** support in Suite. The Master-Detail (or Master-Child) relationship refers to a hierarchical connection between two entities, where one entity (the master or parent entity) influences or controls the behavior or properties of another element (the child entity) relationship. The relationship between **Order - Order Lines** can be considered as an example of a master-detail relationship.
![](suite-master-child-datagrid.png)
ABP Suite allows you to create a master-detail relationship with a few clicks. It generates the necessary code for the master and detail tables, including the foreign key relationship between the two tables.
To establish a master-detail relationship, you need to apply the following two steps:
1-) Create the master entity,
2-) Create a child entity and associate it with a master entity.
That's it! ABP Suite will be generating the entities, making the related configurations, establishing database relations (including the foreign key relationship), generating the UI for the master entity (with child-grids for child entities), and so on...
It’s already documented and you can read the documentation at [https://docs.abp.io/en/commercial/8.0/abp-suite/creating-master-detail-relationship](https://docs.abp.io/en/commercial/8.0/abp-suite/creating-master-detail-relationship).
#### Known Issues
* After you generate CRUD pages via Suite for the Angular UI, you should start the backend project and run the `abp generate-proxy -t ng` command in the root directory of the Angular application manually. It will be automatically done with the next version, so you will not need to run the command manually in further versions.
### Get Profile Picture From Social/External Logins
A user's profile picture would be blank when they first register for an application using a social account through an external authentication provider like Google or Facebook because it hasn't been configured yet. The user must update their profile photo after logging into the application.
In order to save the user from having to change their profile picture after logging in for the first time, we have improved this behavior in this version and are now attempting to retrieve the user's profile picture from external authentication providers (like Google) and set it as their profile picture. Later on, if desired, he or she might modify the profile image.
### Switch Ocelot to YARP for the API Gateway
Until this version, ABP Commercial was using the [Ocelot](https://github.com/ThreeMammals/Ocelot) for the API Gateway, in the [Microservice Startup Template](https://docs.abp.io/en/commercial/latest/startup-templates/microservice/index). Since the **Ocelot** library is not actively maintained, we have searched for an alternative and decided to switch from Ocelot to [YARP](https://github.com/microsoft/reverse-proxy) for the API Gateway. YARP is maintained by Microsoft and is actively being developed and seems a better alternative than Ocelot and provides the same feature stack and even more.
You can read the [Migrating to YARP](https://docs.abp.io/en/commercial/8.0/migration-guides/migrating-to-yarp) documentation for migrating your existing microservice application's API Gateway from [Ocelot](https://github.com/ThreeMammals/Ocelot) to [YARP](https://github.com/microsoft/reverse-proxy).
> We have made the all related changes in the Microservice Startup Template, and also updated the documentation, which you can read [here](https://docs.abp.io/en/commercial/8.0/startup-templates/microservice/gateways).
### Password Complexity Indicators (MVC & Blazor UIs)
In v7.4, we have introduced the [Password Complexity Indicators for Angular UI](https://docs.abp.io/en/commercial/7.4/ui/angular/password-complexity-indicator-component) and with this version, we have implemented it for the MVC & Blazor UIs as well. You can use this feature to dynamically evaluate and rate the strength of user-generated passwords, providing real-time feedback to users as they create or update their passwords.
![](password-complexity-indicators.png)
### Read-Only View for Users Page
In your application, you may want to grant permission to a specific group or people to read-only view the users of your application to be able to do some actions. For example, you may want to marketing team to see the users to organize campaigns for the customers, or make controls. In this case, you can grant default permissions for these groups, however, they could not see the details of a user, because in the current design, if the edit permission is not granted you can't see the detailed info for a user.
![](identity-users.gif)
In this version, we have added the read-only view action to the user's page. This allows you to only grant the default view permission to the specific users and allow them to view user information as read-only and not allow them to change or modify it.
### Export & Import Users as Excel / CSV
With v8.0, now it's possible to import and export user records in Excel and CSV formats. You can import external users, or import users from Excel or CSV files and also you can export users to Excel or CSV files:
![](users-page.png)
## Community News
### Highlights from .NET 8.0
Our team has closely followed the ASP.NET Core and Entity Framework Core 8.0 releases, read Microsoft's guides and documentation, and adapted the changes to our ABP.IO Platform. We are proud to say that we've shipped the ABP 8.0 RC.1 based on .NET 8.0 just after Microsoft's .NET 8.0 release.
In addition to the ABP's .NET 8.0 upgrade, our team has created 13 great articles to highlight the important features coming with ASP.NET Core 8.0 and Entity Framework Core 8.0.
> You can read [this post](https://volosoft.com/blog/Highlights-for-ASP-NET-Entity-Framework-Core-NET-8-0) to see the list of all articles.
### New ABP Community Articles
In addition to [the 13 articles to highlight .NET 8.0 features written by our team](https://volosoft.com/blog/Highlights-for-ASP-NET-Entity-Framework-Core-NET-8-0), here are some of the recent posts added to the [ABP Community](https://community.abp.io/):
* [Upgrade Your Existing Projects to .NET 8 & ABP 8.0](https://community.abp.io/posts/upgrade-your-existing-projects-to-.net-8-abp-8.0-x0n7hiqr) by [Engincan Veske](https://github.com/EngincanV)
* [How to Upload and Download Files in the ABP Framework using Angular](https://community.abp.io/posts/how-to-upload-and-download-files-in-the-abp-framework-using-angular-que8cdr8) by [Mahmut Gündoğdu](https://github.com/mahmut-gundogdu)
* New **ABP Framework Essentials** Videos by [Hamza Albreem](https://github.com/braim23):
* [ABP Essentials - Interception](https://community.abp.io/videos/abp-essentials-interception-ath78xhw)
* [ABP Essentials - Virtual File System](https://community.abp.io/videos/abp-essentials-virtual-file-system-hpgr2j72)
* [ABP Framework Essentials - Localization](https://community.abp.io/videos/abp-framework-essentials-localization-7taieh68)
* [ABP Framework Essentials - Dependency Injection](https://community.abp.io/videos/abp-framework-essentials-dependency-injection-q241mfrf)
* See the playlist for other videos of this series: https://www.youtube.com/playlist?list=PLsNclT2aHJcNupH2wz83y7htugpLoUZ_B
Thanks to the ABP Community for all the content they have published. You can also [post your ABP related (text or video) content](https://community.abp.io/articles/submit) to the ABP Community.
### We were in the .NET Conf 2023
Microsoft has released .NET 8.0 and celebrated it with a 3-day international online conference. The core team members of ABP Framework, [Alper Ebiçoğlu](https://twitter.com/alperebicoglu) and [Enis Necipoğlu](https://twitter.com/EnisNecipoglu) gave speeches at the .NET Conf 2023.
[Alper Ebiçoğlu](https://twitter.com/alperebicoglu)'s topic was "Building Multi-Tenant ASP.NET Core Applications and ABP Framework" and in this talk, he talked about what's SaaS development, what are its pros and challenges and multi-tenant development with the open-source ABP Framework:
<iframe width="560" height="315" src="https://www.youtube.com/embed/3uWeyEbV4c4?si=XuU8-QJs2w5j6Inp" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
On the other hand, [Enis Necipoğlu](https://twitter.com/EnisNecipoglu)'s topic was "Reactive programming with .NET MAUI" and he talked about applying reactive programming in .NET MAUI with MVVM and ReactiveUI:
<iframe width="560" height="315" src="https://www.youtube.com/embed/i0EFuRF2u-w?si=wPTSDxtbfkzMF5CN" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
### ABP Community Talks 2023.8: What’s coming with .NET 8.0 & ABP v8.0
![](community-talk-2023-8.png)
In this episode of ABP Community Talks, 2023.8; [Steve Sanderson](https://twitter.com/stevensanderson) will be our guest speaker and we'll talk about .NET 8.0 and ABP 8.0 with the ABP Core Team. We will dive into the features that came with .NET 8.0, how they are implemented in ABP 8.0, and the highlights in the .NET Conf 2023 with [Halil İbrahim Kalkan](https://github.com/hikalkan), [Alper Ebicoglu](https://github.com/ebicoglu), [Engincan Veske](https://github.com/EngincanV), [Berkan Sasmaz](https://github.com/berkansasmaz) and [Bige Besikci Yaman](https://github.com/bigebesikci).
## Conclusion
This version comes with some new features and a lot of enhancements to the existing features. You can see the [Road Map](https://docs.abp.io/en/abp/8.0/Road-Map) documentation to learn about the release schedule and planned features for the next releases. Please try ABP v8.0 RC and provide feedback to help us release a more stable version.
Thanks for being a part of this community!

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/account-module-register.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/community-talk-2023-8.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/cover-image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/identity-users.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 KiB

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/password-complexity-indicators.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/suite-master-child-datagrid.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

BIN
docs/en/Blog-Posts/2023-11-15 v8_0_Preview/users-page.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

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

@ -91,4 +91,5 @@ I summarized the new generation Blazor in a very simple way. This architecture w
* 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).
* "Full Stack Web UI with Blazor" — .NET Conf 2023 video 👉 [learn.microsoft.com/en-us/shows/dotnetconf-2023/full-stack-web-ui-with-blazor-in-dotnet-8](https://learn.microsoft.com/en-us/shows/dotnetconf-2023/full-stack-web-ui-with-blazor-in-dotnet-8)

0
docs/en/Community-Articles/2023-11-97-AOT-Compilation/Post.md → docs/en/Community-Articles/2023-11-17-AOT-Compilation/Post.md

30
docs/en/Dapr/Index.md

@ -60,29 +60,6 @@ Alternatively, you can configure the options in the `Dapr` section of your `apps
}
````
### Injecting DaprClient
ABP registers the `DaprClient` class to the [dependency injection](../Dependency-Injection.md) system. So, you can inject and use it whenever you need:
````csharp
public class MyService : ITransientDependency
{
private readonly DaprClient _daprClient;
public MyService(DaprClient daprClient)
{
_daprClient = daprClient;
}
public async Task DoItAsync()
{
// TODO: Use the injected _daprClient object
}
}
````
Injecting `DaprClient` is the recommended way of using it in your application code. When you inject it, the `IAbpDaprClientFactory` service is used to create it, which is explained in the next section.
### IAbpDaprClientFactory
`IAbpDaprClientFactory` can be used to create `DaprClient` or `HttpClient` objects to perform operations on Dapr. It uses `AbpDaprOptions`, so you can configure the settings in a central place.
@ -113,15 +90,14 @@ public class MyService : ITransientDependency
});
// Create an HttpClient object
HttpClient httpClient = await _daprClientFactory
.CreateHttpClientAsync("target-app-id");
HttpClient httpClient = await _daprClientFactory.CreateHttpClientAsync("target-app-id");
}
}
````
`CreateHttpClientAsync` method also gets optional `daprEndpoint` and `daprApiToken` parameters.
> ABP uses `IAbpDaprClientFactory` when it needs to create a Dapr client. You can also use Dapr API to create client objects in your application. Using `IAbpDaprClientFactory` is recommended, but not required.
> You can use Dapr API to create client objects in your application. Using `IAbpDaprClientFactory` is recommended, but not required.
## C# API Client Proxies Integration
@ -412,7 +388,7 @@ Or you can set it in your `appsettings.json` file:
}
````
Once you set it, it is used when you inject `DaprClient` or use `IAbpDaprClientFactory`. If you need that value in your application, you can inject `IDaprApiTokenProvider` and use its `GetDaprApiToken()` method.
Once you set it, it is used when you use `IAbpDaprClientFactory`. If you need that value in your application, you can inject `IDaprApiTokenProvider` and use its `GetDaprApiToken()` method.
### App API Token

18
docs/en/Dependency-Injection.md

@ -480,6 +480,24 @@ This example simply checks if the service class has `MyLogAttribute` attribute a
> Notice that `OnRegistered` callback might be called multiple times for the same service class if it exposes more than one service/interface. So, it's safe to use `Interceptors.TryAdd` method instead of `Interceptors.Add` method. See [the documentation](Dynamic-Proxying-Interceptors.md) of dynamic proxying / interceptors.
### IServiceCollection.OnActivated Event
The `OnActivated` event is raised once a service is fully constructed. Here you can perform application-level tasks that depend on the service being fully constructed - these should be rare.
````csharp
var serviceDescriptor = ServiceDescriptor.Transient<MyServer, MyServer>();
services.Add(serviceDescriptor);
if (setIsReadOnly)
{
services.OnActivated(serviceDescriptor, x =>
{
x.Instance.As<MyServer>().IsReadOnly = true;
});
}
````
> Notice that `OnActivated` event can be registered multiple times for the same `ServiceDescriptor`.
## 3rd-Party Providers
While ABP has no core dependency to any 3rd-party DI provider, it's required to use a provider that supports dynamic proxying and some other advanced features to make some ABP features properly work.

10
docs/en/Distributed-Event-Bus-RabbitMQ-Integration.md

@ -152,4 +152,14 @@ Configure<AbpRabbitMqEventBusOptions>(options =>
});
````
**Example: Configure the queue and exchange optional arguments**
```csharp
Configure<AbpRabbitMqEventBusOptions>(options =>
{
options.ExchangeArguments["x-delayed-type"] = "direct";
options.QueueArguments["x-message-ttl"] = 60000;
});
```
Using these options classes can be combined with the `appsettings.json` way. Configuring an option property in the code overrides the value in the configuration file.

64
docs/en/Dynamic-Claims.md

@ -1,14 +1,18 @@
# Dynamic Claims
## What is Dynamic Claims and Why do we need it
When a client authenticates and obtains an access token or an authentication cookie, the claims in that token or cookie are not changed unless it re-authenticates. For most of the claims, that may not be a problem since claims are not frequently changing values. However, some claims may be changed and these changes should be reflected to the current session immediately. For example, we can revoke a role from a user and that should be immediately effective, otherwise user will continue to use that role's permissions until re-login to the application.
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.
ABP's dynamic claims feature is used to automatically and dynamically override the configured claim values in the client's authentication token/cookie by the latest values of these 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
## How to use it
This feature is disabled by default. You should enable it for your application and use the Dynamic Claims middleware.
This feature is disabled by default. You can enable it by following code:
> **Beginning from the v8.0, all the [startup templates](Startup-Templates/Index.md) are pre-configured and the dynamic claims feature is enabled by default. So, if you have created a solution with v8.0 and above, you don't need to make any configuration. Follow the instructions only if you've upgraded from a version lower than 8.0.**
### Enabling the Dynamic Claims
You can enable it by the following code:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
@ -20,7 +24,7 @@ public override void ConfigureServices(ServiceConfigurationContext context)
}
````
If you are using the tiered solution you need to set the `RemoteRefreshUrl` to the Auth Server url in the UI project.
This is typically done on the authentication server. In a monolith application, you will typically have a single application, so you can configure it. If you are using the tiered solution structure (where the UI part is hosted in a separate application) you will need to also set the `RemoteRefreshUrl` to the Authentication Server's URL in the UI application. Example:
````csharp
public override void ConfigureServices(ServiceConfigurationContext context)
@ -33,46 +37,54 @@ public override void ConfigureServices(ServiceConfigurationContext context)
}
````
Then add the `DynamicClaims` middleware.
> The `RemoteRefreshUrl` is already configured inside methods `AddAbpOpenIdConnect` and `AddAbpJwtBearer`.
### The Dynamic Claims Middleware
Add the `DynamicClaims` middleware to all the applications that performs authentication (including the authentication server):
````csharp
public override void OnApplicationInitialization(ApplicationInitializationContext context)
public override void OnApplicationInitialization(
ApplicationInitializationContext context)
{
// Add this line before UseAuthorization.
app.UseDynamicClaims();
//...
app.UseDynamicClaims(); // Add this line before UseAuthorization.
app.UseAuthorization();
//...
}
````
## How it works
## 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.
There are three pre-built implementations of `IAbpDynamicClaimsPrincipalContributor` for different scenarios:
### IdentityDynamicClaimsPrincipalContributor
* `IdentityDynamicClaimsPrincipalContributor`: Provided by the [Identity module](Modules/Identity.md) and generates and overrides the actual dynamic claims, and writes to the distributed cache. Typically works in the authentication server in a distributed system.
* `RemoteDynamicClaimsPrincipalContributor`: For distributed scenarios, this implementation works in the UI application. It tries to get dynamic claim values in the distributed cache. If not found in the distributed cache, it makes an HTTP call to the authentication server and requests filling it by the authentication server. `AbpClaimsPrincipalFactoryOptions.RemoteRefreshUrl` should be properly configure to make it running.
* `WebRemoteDynamicClaimsPrincipalContributor`: Similar to the `RemoteDynamicClaimsPrincipalContributor` but works in the microservice applications.
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.
### IAbpDynamicClaimsPrincipalContributor
### RemoteDynamicClaimsPrincipalContributor
If you want to add your own dynamic claims contributor, you can create a class that implement the `IAbpDynamicClaimsPrincipalContributor` interface (and register it to the [dependency injection](Dependency-Injection.md) system. ABP Framework will call the `ContributeAsync` method to get the claims. It better to use a kind of cache to improve the performance since that is a frequently executed method (in every HTTP request).
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.
## AbpClaimsPrincipalFactoryOptions
## IAbpDynamicClaimsPrincipalContributor
`AbpClaimsPrincipalFactoryOptions` is the main options class to configure the behavior of the dynamic claims system. It has the following properties:
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.
* `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 ` and you should provide the full URL in the authentication server, like `http://my-account-server/api/account/dynamic-claims/refresh `.
* `DynamicClaims`: A list of dynamic claim types. Only the claims in that list will be overridden by the dynamic claims system.
* `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.
> It better to use cache to improve performance.
## WebRemoteDynamicClaimsPrincipalContributorOptions
## 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
`WebRemoteDynamicClaimsPrincipalContributorOptions` is the options class to configure the behavior of the `WebRemoteDynamicClaimsPrincipalContributor`. It has the following properties:
* `IsEnabled`: Enable or disable the `WebRemoteDynamicClaimsPrincipalContributor`. `false` by default.
* `AuthenticationScheme`: The authentication scheme to authenticate the HTTP call to the authentication server.
## See Also
* [Authorization](Authorization.md)

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

@ -103,7 +103,7 @@ You don't need to make any changes related to that, however it's important to kn
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.
## 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.
@ -113,6 +113,12 @@ Entity Framework Core read-only repository implementation uses [EF Core's No-Tra
> See the issue for more information: https://github.com/abpframework/abp/pull/17421
## Use `IAbpDaprClientFactory` to Obtain `DaprClient`
From this version on, instead of injecting the `DaprClient` directly, using the `IAbpDaprClientFactory.CreateAsync` method to create `DaprClient` or `HttpClient` objects to perform operations on Dapr is recommended.
The documentation is already updated according to this suggestion and can be found at https://docs.abp.io/en/abp/8.0/Dapr/Index. So, if you want to learn more you can check the documentation or see the PR: https://github.com/abpframework/abp/pull/18117.
## Angular UI
# Guards
@ -238,7 +244,7 @@ You can see the following list of NuGet libraries that have been upgraded with .
| 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 |
| Npgsql.EntityFrameworkCore.PostgreSQL | 7.0.0 | 8.0.0 |
| NSubstitute.Analyzers.CSharp | 1.0.15 | 1.0.16 |
| Octokit | 0.50.0 | 9.0.0 |
| OpenIddict.Abstractions | 4.8.0 | 4.10.0 |
@ -248,14 +254,14 @@ You can see the following list of NuGet libraries that have been upgraded with .
| 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 |
| Pomelo.EntityFrameworkCore.MySql | 7.0.0 | 8.0.0-beta.2 |
| 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 |
| Rebus | 6.6.5 | 8.0.1 |
| Rebus.ServiceProvider | 7.0.0 | 10.0.0 |
| Scriban | 5.4.4 | 5.9.0 |
| Serilog | 2.11.0 | 3.1.1 |
| Serilog.AspNetCore | 5.0.0 | 8.0.0 |

2
docs/en/Modules/OpenIddict.md

@ -349,7 +349,7 @@ public class MyClaimDestinationsHandler : IAbpOpenIddictClaimsPrincipalHandler,
}
}
Configure<AbpOpenIddictClaimDestinationsOptions>(options =>
Configure<AbpOpenIddictClaimsPrincipalOptions>(options =>
{
options.ClaimsPrincipalHandlers.Add<MyClaimDestinationsHandler>();
});

15
docs/en/Road-Map.md

@ -4,17 +4,18 @@ This document provides a road map, release schedule and planned features for the
## Next Versions
### v8.0
### v8.1
The next version will be 8.0 and planned to release the stable 8.0 version in December, 2023. We will be mostly working on the following topics:
The next version will be 8.1 and planned to release the stable 8.1 version in February, 2024. We will be mostly working on the following topics:
* Enabling nullable annotations for all projects ([#16610](https://github.com/abpframework/abp/issues/16610))
* Upgrade to .NET 8.0 ([#17355](https://github.com/abpframework/abp/issues/17355))
* Use NoTracking for readonly repositories for EF Core ([#597](https://github.com/abpframework/abp/issues/597))
* Support mapping collection of objects for custom object mappers ([#94](https://github.com/abpframework/abp/issues/94))
* Blazor Full-Stack UI ([#16156](https://github.com/abpframework/abp/issues/16156))
* Upgrade to OpenIddict 5.x ([#17605](https://github.com/abpframework/abp/issues/17605))
* Angular Universal ([#15782](https://github.com/abpframework/abp/issues/15782))
* Blazor - Forms & Validation Documentation ([#16400](https://github.com/abpframework/abp/issues/16400))
* Deployment Documents Improvements ([#15034](https://github.com/abpframework/abp/issues/15034))
* Improvements on the existing features and provide more guides.
See the [8.0 milestone](https://github.com/abpframework/abp/milestone/88) for all the issues we've planned to work on.
See the [8.1 milestone](https://github.com/abpframework/abp/milestone/94) for all the issues we've planned to work on.
## Backlog Items

39
docs/en/Themes/LeptonXLite/Blazor.md

@ -135,13 +135,17 @@ builder.RootComponents.Add<App>("#ApplicationContainer");
@attribute [Dependency(ReplaceServices = true)]
@Name
@code {
string Name = "My Main Layout";
}
```
* If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyMainLayout.razor.cs`, in your blazor application as shown below:
```csharp
[ExposeServices(typeof(MainLayout))]
[Dependency(ReplaceServices = true)
[Dependency(ReplaceServices = true)]
namespace LeptonXLite.DemoApp.Blazor.MyComponents
{
public partial class MyMainLayout
@ -152,6 +156,7 @@ namespace LeptonXLite.DemoApp.Blazor.MyComponents
```
> Don't forget to remove the repeated attributes from the razor page!
> Don't forget to remove the `@code` section from the razor page!
### Toolbars
@ -206,6 +211,10 @@ The **branding component** is a simple component that can be used to display you
@attribute [Dependency(ReplaceServices = true)]
@Name
@code {
string Name = "My Branding Component";
}
```
* If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyBrandingComponent.razor.cs`, in your blazor application as shown below:
@ -243,6 +252,10 @@ On websites that have a lot of pages, **breadcrumb navigation** can greatly **en
@attribute [Dependency(ReplaceServices = true)]
@Name
@code {
string Name = "My Breadcrumbs Component";
}
```
* If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyBreadcrumbsComponent.razor.cs`, in your blazor application as shown below:
@ -281,6 +294,10 @@ Sidebar menus have been used as **a directory for Related Pages** for a **Servic
@attribute [Dependency(ReplaceServices = true)]
@Name
@code {
string Name = "My Main Menu Component";
}
```
* If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyMainMenu.razor.cs`, in your blazor application as shown below:
@ -319,6 +336,10 @@ Toolbar items are used to add **extra functionality to the toolbar**. The toolba
@attribute [Dependency(ReplaceServices = true)]
@Name
@code {
string Name = "My Toolbar Items Component";
}
```
* If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyToolbarItemsComponent.razor.cs`, in your blazor application as shown below:
@ -357,6 +378,10 @@ Think about a **multi-lingual** website and the first thing that could **hit you
@attribute [Dependency(ReplaceServices = true)]
@Name
@code {
string Name = "My Language Switch Component";
}
```
* If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyLanguageSwitchComponent.razor.cs`, in your blazor application as shown below:
@ -395,6 +420,10 @@ The **mobile** **language switch component** is used to switch the language of t
@attribute [Dependency(ReplaceServices = true)]
@Name
@code {
string Name = "My Mobile Language Switch Component";
}
```
* If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyMobilLanguageSwitchComponent.razor.cs`, in your blazor application as shown below:
@ -433,6 +462,10 @@ The **User Menu** is the **menu** that **drops down** when you **click your name
@attribute [Dependency(ReplaceServices = true)]
@Name
@code {
string Name = "My User Menu Component";
}
```
* If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyUserMenuComponent.razor.cs`, in your blazor application as shown below:
@ -471,6 +504,10 @@ The **mobile user menu component** is used to display the **user menu on mobile
@attribute [Dependency(ReplaceServices = true)]
@Name
@code {
string Name = "My Mobile User Menu Component";
}
```
* If you prefer to use a code-behind file for the C# code of your component, create a razor component, like `MyMobileUserMenuComponent.razor.cs`, in your blazor application as shown below:

0
docs/en/UI/Angular/CapsLock.directive.md → docs/en/UI/Angular/Caps-Lock-Directive.md

8
docs/en/docs-nav.json

@ -1128,6 +1128,14 @@
"text": "Loading Directive",
"path": "UI/Angular/Loading-Directive.md"
},
{
"text": "Show Password Directive",
"path": "UI/Angular/Show-Password-Directive.md"
},
{
"text": "Caps Lock Directive",
"path": "UI/Angular/Caps-Lock-Directive.md"
},
{
"text": "Toast Overlay",
"path": "UI/Angular/Toaster-Service.md"

30
docs/zh-Hans/Dapr/Index.md

@ -60,29 +60,6 @@ Configure<AbpDaprOptions>(options =>
}
````
### 注入DaprClient
ABP 将 `DaprClient` 类注册到 [依赖注入](../Dependency-Injection.md) 系统中.因此,你可以在需要时注入并使用它:
````csharp
public class MyService : ITransientDependency
{
private readonly DaprClient _daprClient;
public MyService(DaprClient daprClient)
{
_daprClient = daprClient;
}
public async Task DoItAsync()
{
// TODO: Use the injected _daprClient object
}
}
````
注入 `DaprClient` 是在应用程序代码中使用它的推荐方法.当你注入它时,将使用 `IAbpDaprClientFactory` 服务创建它,这会在下一节中将进行说明.
### IAbpDaprClientFactory
`IAbpDaprClientFactory` 可用于创建 `DaprClient``HttpClient` 对象来执行对 Dapr 的操作.它使用 `AbpDaprOptions`,因此你可以配置设置.
@ -113,15 +90,14 @@ public class MyService : ITransientDependency
});
// Create an HttpClient object
HttpClient httpClient = await _daprClientFactory
.CreateHttpClientAsync("target-app-id");
HttpClient httpClient = await _daprClientFactory.CreateHttpClientAsync("target-app-id");
}
}
````
`CreateHttpClientAsync` 方法还获取可选的 `daprEndpoint``daprApiToken` 参数.
> ABP使用`IAbpDaprClientFactory`创建Dapr客户端.可以在应用程序中使用Dapr API创建客户端对象.推荐使用`IAbpDaprClientFactory`,但不是必需的.
> 你可以在应用程序中使用Dapr API创建客户端对象.推荐使用`IAbpDaprClientFactory`,但不是必需的.
## C# API 客户端代理集成
@ -412,7 +388,7 @@ Configure<AbpDaprOptions>(options =>
}
````
一旦你设置了它,它就会在你注入`DaprClient`或使用`IAbpDaprClientFactory`时使用.如果你需要在应用程序中使用该值,你可以注入`IDaprApiTokenProvider`并使用其`GetDaprApiToken()`方法.
一旦你设置了它,它就会在使用`IAbpDaprClientFactory`时使用.如果你需要在应用程序中使用该值,你可以注入`IDaprApiTokenProvider`并使用其`GetDaprApiToken()`方法.
### App API Token

18
docs/zh-Hans/Dependency-Injection.md

@ -310,6 +310,24 @@ public class AppModule : AbpModule
> 注意, 如果服务类公开了多于一个服务或接口, `OnRegistered` 回调(callback)可能被同一服务类多次调用. 因此, 较安全的方法是使用 `Interceptors.TryAdd` 方法而不是 `Interceptors.Add` 方法. 请参阅动态代理(dynamic proxying)/拦截器 [文档](Dynamic-Proxying-Interceptors.md).
### IServiceCollection.OnActivated 事件
一旦服务完全构建完成`OnActivated`事件就会触发. 你可以执行依赖于服务已完全构建的的一些任务, 虽然这种情况可能很少见.
````csharp
var serviceDescriptor = ServiceDescriptor.Transient<MyServer, MyServer>();
services.Add(serviceDescriptor);
if (setIsReadOnly)
{
services.OnActivated(serviceDescriptor, x =>
{
x.Instance.As<MyServer>().IsReadOnly = true;
});
}
````
> 注意,`OnActivated`事件可以为一个`ServiceDescriptor`注册多次.
## 第三方提供程序
虽然ABP框架没有对任何第三方DI提供程序的核心依赖, 但它必须使用一个提供程序来支持动态代理(dynamic proxying)和一些高级特性以便ABP特性能正常工作.

10
docs/zh-Hans/Distributed-Event-Bus-RabbitMQ-Integration.md

@ -152,4 +152,14 @@ Configure<AbpRabbitMqEventBusOptions>(options =>
});
````
**示例:配置队列和交换机的额外参数**
```csharp
Configure<AbpRabbitMqEventBusOptions>(options =>
{
options.ExchangeArguments["x-delayed-type"] = "direct";
options.QueueArguments["x-message-ttl"] = 60000;
});
```
使用这些选项类可以与 `appsettings.json` 组合在一起. 在代码中配置选项属性会覆盖配置文件中的值.

25
docs/zh-Hans/Local-Event-Bus.md

@ -197,33 +197,20 @@ namespace AbpDemo
这个类订阅 `EntityCreatedEventData<IdentityUser>`,它在用户创建后发布. 你可能需要向新用户发送一封"欢迎"电子邮件.
这些事件有两种类型:过去时态的事件和进行时态的事件.
### 用过去时态事件
当相关工作单元完成且实体更改成功保存到数据库时,将发布带有过去时态的事件. 如果在这些事件处理程序上抛出异常,则**无法回滚**事务,因为事务已经提交.
事件类型;
有以下预定义的事件类型;
* `EntityCreatedEventData<T>` 当实体创建成功后发布.
* `EntityUpdatedEventData<T>` 当实体更新成功后发布.
* `EntityDeletedEventData<T>` 当实体删除成功后发布.
* `EntityChangedEventData<T>` 当实体创建,更新,删除后发布. 如果你需要监听任何类型的更改,它是一种快捷方式 - 而不是订阅单个事件.
### 用于进行时态事件
带有进行时态的事件在完成事务之前发布(如果数据库事务由所使用的数据库提供程序支持). 如果在这些事件处理程序上抛出异常,它**会回滚**事务,因为事务还没有完成,更改也没有保存到数据库中.
事件类型;
* `EntityCreatingEventData<T>` 当新实体保存到数据库前发布.
* `EntityUpdatingEventData<T>` 当已存在实体更新到数据库前发布.
* `EntityDeletingEventData<T>` 删除实体前发布.
* `EntityChangingEventData<T>` 当实体创建,更新,删除前发布. 如果你需要监听任何类型的更改,它是一种快捷方式 - 而不是订阅单个事件.
#### 它是如何实现的?
### 它是如何实现的?
在将更改保存到数据库时发布预构建事件;
* 对于 EF Core, 他们在 `DbContext.SaveChanges` 发布.
* 对于 MongoDB, 在你调用仓储的 `InsertAsync`, `UpdateAsync``DeleteAsync` 方法发布(因为MongoDB没有更改追踪系统).
## 另请参阅
* [分布式事件总线](Distributed-Event-Bus.md)

418
framework/Volo.Abp.abpmdl.json → framework/Volo.Abp.abpmdl

File diff suppressed because it is too large

2
framework/Volo.Abp.abpsln.json → framework/Volo.Abp.abpsln

@ -2,7 +2,7 @@
"template": "empty",
"modules": {
"Volo.Abp": {
"path": "Volo.Abp.abpmdl.json"
"path": "Volo.Abp.abpmdl"
}
}
}

0
framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo.Abp.ApiVersioning.Abstractions.abppkg.json → framework/src/Volo.Abp.ApiVersioning.Abstractions/Volo.Abp.ApiVersioning.Abstractions.abppkg

36
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/Extensions/DependencyInjection/AbpJwtBearerExtensions.cs

@ -0,0 +1,36 @@
using System;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.Security.Claims;
namespace Microsoft.Extensions.DependencyInjection;
public static class AbpJwtBearerExtensions
{
public static AuthenticationBuilder AddAbpJwtBearer(this AuthenticationBuilder builder)
=> builder.AddAbpJwtBearer(JwtBearerDefaults.AuthenticationScheme, _ => { });
public static AuthenticationBuilder AddAbpJwtBearer(this AuthenticationBuilder builder, Action<JwtBearerOptions> configureOptions)
=> builder.AddAbpJwtBearer(JwtBearerDefaults.AuthenticationScheme, configureOptions);
public static AuthenticationBuilder AddAbpJwtBearer(this AuthenticationBuilder builder, string authenticationScheme, Action<JwtBearerOptions> configureOptions)
=> builder.AddAbpJwtBearer(authenticationScheme, "Bearer", configureOptions);
public static AuthenticationBuilder AddAbpJwtBearer(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<JwtBearerOptions> configureOptions)
{
builder.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
var jwtBearerOption = new JwtBearerOptions();
configureOptions?.Invoke(jwtBearerOption);
if (!jwtBearerOption.Authority.IsNullOrEmpty())
{
options.RemoteRefreshUrl = jwtBearerOption.Authority.RemovePostFix("/") + options.RemoteRefreshUrl;
}
});
return builder.AddJwtBearer(authenticationScheme, displayName, options =>
{
configureOptions?.Invoke(options);
});
}
}

0
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.abppkg.json → framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.abppkg

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

@ -18,10 +18,12 @@
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Security\Volo.Abp.Security.csproj" />
<ProjectReference Include="..\Volo.Abp.Caching\Volo.Abp.Caching.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
<PackageReference Include="IdentityModel" />
</ItemGroup>
</Project>

19
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/AbpAspNetCoreAuthenticationJwtBearerModule.cs

@ -1,10 +1,25 @@
using Volo.Abp.Modularity;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims;
using Volo.Abp.Caching;
using Volo.Abp.Modularity;
using Volo.Abp.Security;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Authentication.JwtBearer;
[DependsOn(typeof(AbpSecurityModule))]
[DependsOn(typeof(AbpSecurityModule), typeof(AbpCachingModule))]
public class AbpAspNetCoreAuthenticationJwtBearerModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddHttpClient();
context.Services.AddHttpContextAccessor();
if (context.Services.ExecutePreConfiguredActions<WebRemoteDynamicClaimsPrincipalContributorOptions>().IsEnabled &&
context.Services.ExecutePreConfiguredActions<AbpClaimsPrincipalFactoryOptions>().IsRemoteRefreshEnabled)
{
context.Services.AddTransient<WebRemoteDynamicClaimsPrincipalContributor>();
context.Services.AddTransient<WebRemoteDynamicClaimsPrincipalContributorCache>();
}
}
}

10
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributor.cs

@ -0,0 +1,10 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims;
[DisableConventionalRegistration]
public class WebRemoteDynamicClaimsPrincipalContributor : RemoteDynamicClaimsPrincipalContributorBase<WebRemoteDynamicClaimsPrincipalContributor, WebRemoteDynamicClaimsPrincipalContributorCache>
{
}

75
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorCache.cs

@ -0,0 +1,75 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using IdentityModel.Client;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.Caching;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims;
public class WebRemoteDynamicClaimsPrincipalContributorCache : RemoteDynamicClaimsPrincipalContributorCacheBase<WebRemoteDynamicClaimsPrincipalContributorCache>
{
public const string HttpClientName = nameof(WebRemoteDynamicClaimsPrincipalContributorCache);
protected IDistributedCache<AbpDynamicClaimCacheItem> Cache { get; }
protected IHttpClientFactory HttpClientFactory { get; }
protected IHttpContextAccessor HttpContextAccessor { get; }
protected IOptions<WebRemoteDynamicClaimsPrincipalContributorOptions> Options { get; }
public WebRemoteDynamicClaimsPrincipalContributorCache(
IDistributedCache<AbpDynamicClaimCacheItem> cache,
IHttpClientFactory httpClientFactory,
IOptions<AbpClaimsPrincipalFactoryOptions> abpClaimsPrincipalFactoryOptions,
IHttpContextAccessor httpContextAccessor,
IOptions<WebRemoteDynamicClaimsPrincipalContributorOptions> options)
: base(abpClaimsPrincipalFactoryOptions)
{
Cache = cache;
HttpClientFactory = httpClientFactory;
HttpContextAccessor = httpContextAccessor;
Options = options;
}
protected async override Task<AbpDynamicClaimCacheItem?> GetCacheAsync(Guid userId, Guid? tenantId = null)
{
return await Cache.GetAsync(AbpDynamicClaimCacheItem.CalculateCacheKey(userId, tenantId));
}
protected async override Task RefreshAsync(Guid userId, Guid? tenantId = null)
{
try
{
if (HttpContextAccessor.HttpContext == null)
{
throw new AbpException($"Failed to refresh remote claims for user: {userId} - HttpContext is null!");
}
var authenticateResult = await HttpContextAccessor.HttpContext.AuthenticateAsync(Options.Value.AuthenticationScheme);
if (!authenticateResult.Succeeded)
{
throw new AbpException($"Failed to refresh remote claims for user: {userId} - authentication failed!");
}
var accessToken = authenticateResult.Properties?.GetTokenValue("access_token");
if (accessToken.IsNullOrWhiteSpace())
{
throw new AbpException($"Failed to refresh remote claims for user: {userId} - access_token is null or empty!");
}
var client = HttpClientFactory.CreateClient(HttpClientName);
var requestMessage = new HttpRequestMessage(HttpMethod.Post, AbpClaimsPrincipalFactoryOptions.Value.RemoteRefreshUrl);
requestMessage.SetBearerToken(accessToken);
var response = await client.SendAsync(requestMessage);
response.EnsureSuccessStatusCode();
}
catch (Exception e)
{
Logger.LogWarning(e, $"Failed to refresh remote claims for user: {userId}");
throw;
}
}
}

16
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo/Abp/AspNetCore/Authentication/JwtBearer/DynamicClaims/WebRemoteDynamicClaimsPrincipalContributorOptions.cs

@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
namespace Volo.Abp.AspNetCore.Authentication.JwtBearer.DynamicClaims;
public class WebRemoteDynamicClaimsPrincipalContributorOptions
{
public bool IsEnabled { get; set; }
public string AuthenticationScheme { get; set; }
public WebRemoteDynamicClaimsPrincipalContributorOptions()
{
IsEnabled = false;
AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme;
}
}

0
framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.abppkg.json → framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.abppkg

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

@ -8,6 +8,7 @@ using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Volo.Abp.AspNetCore.Authentication.OpenIdConnect;
using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.Security.Claims;
namespace Microsoft.Extensions.DependencyInjection;
@ -24,6 +25,16 @@ public static class AbpOpenIdConnectExtensions
public static AuthenticationBuilder AddAbpOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<OpenIdConnectOptions> configureOptions)
{
builder.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
var openIdConnectOptions = new OpenIdConnectOptions();
configureOptions?.Invoke(openIdConnectOptions);
if (!openIdConnectOptions.Authority.IsNullOrEmpty())
{
options.RemoteRefreshUrl = openIdConnectOptions.Authority.RemovePostFix("/") + options.RemoteRefreshUrl;
}
});
return builder.AddOpenIdConnect(authenticationScheme, displayName, options =>
{
options.ClaimActions.MapAbpClaimTypes();
@ -38,7 +49,7 @@ public static class AbpOpenIdConnectExtensions
};
options.AccessDeniedPath = "/";
options.Events.OnTokenValidated = async (context) =>
{
var client = context.HttpContext.RequestServices.GetRequiredService<IOpenIdLocalUserCreationClient>();

0
framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo.Abp.AspNetCore.Authentication.OpenIdConnect.abppkg.json → framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo.Abp.AspNetCore.Authentication.OpenIdConnect.abppkg

0
framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Volo.Abp.AspNetCore.Components.Server.Theming.abppkg.json → framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Volo.Abp.AspNetCore.Components.Server.Theming.abppkg

0
framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.abppkg.json → framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.abppkg

9
framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
using Microsoft.AspNetCore.Http.Connections;
@ -8,6 +10,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Volo.Abp.AspNetCore.Auditing;
using Volo.Abp.AspNetCore.Components.Server.Extensibility;
using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.SignalR;
@ -30,7 +33,11 @@ public class AbpAspNetCoreComponentsServerModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
StaticWebAssetsLoader.UseStaticWebAssets(context.Services.GetHostingEnvironment(), context.Services.GetConfiguration());
context.Services.AddHttpClient();
context.Services.AddHttpClient(nameof(BlazorServerLookupApiRequestService))
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.All
});
var serverSideBlazorBuilder = context.Services.AddServerSideBlazor(options =>
{
if (context.Services.GetHostingEnvironment().IsDevelopment())

20
framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs

@ -41,27 +41,25 @@ public class BlazorServerLookupApiRequestService : ILookupApiRequestService, ITr
public async Task<string> SendAsync(string url)
{
var client = HttpClientFactory.CreateClient();
var client = HttpClientFactory.CreateClient(nameof(BlazorServerLookupApiRequestService));
var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
var uri = new Uri(url, UriKind.RelativeOrAbsolute);
if (!uri.IsAbsoluteUri)
{
var baseUrl = string.Empty;
try
var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultOrNullAsync("Default");
if (remoteServiceConfig != null)
{
//Blazor tiered -- mode
var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync("Default");
baseUrl = remoteServiceConfig.BaseUrl;
// Blazor tiered mode
var baseUrl = remoteServiceConfig.BaseUrl;
client.BaseAddress = new Uri(baseUrl);
AddHeaders(requestMessage);
await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client,
requestMessage, new RemoteServiceConfiguration(baseUrl), string.Empty));
await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client, requestMessage, new RemoteServiceConfiguration(baseUrl), string.Empty));
}
catch (AbpException) // Blazor-Server mode.
else
{
baseUrl = NavigationManager.BaseUri;
client.BaseAddress = new Uri(baseUrl);
// Blazor server mode
client.BaseAddress = new Uri(NavigationManager.BaseUri);
foreach (var header in HttpContextAccessor.HttpContext!.Request.Headers)
{
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());

0
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Volo.Abp.AspNetCore.Components.Web.Theming.abppkg.json → framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Volo.Abp.AspNetCore.Components.Web.Theming.abppkg

0
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo.Abp.AspNetCore.Components.Web.abppkg.json → framework/src/Volo.Abp.AspNetCore.Components.Web/Volo.Abp.AspNetCore.Components.Web.abppkg

4
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/AbpBlazorMessageLocalizerHelper.cs

@ -20,7 +20,7 @@ public class AbpBlazorMessageLocalizerHelper<T>
{
var argumentsList = arguments?.ToList();
return argumentsList?.Count > 0
? stringLocalizer[message, LocalizeMessageArguments(argumentsList)]
? stringLocalizer[message, LocalizeMessageArguments(argumentsList).ToArray()]
: stringLocalizer[message];
}
catch
@ -29,7 +29,7 @@ public class AbpBlazorMessageLocalizerHelper<T>
}
}
private IEnumerable<string> LocalizeMessageArguments(List<string> arguments)
private IEnumerable<object> LocalizeMessageArguments(List<string> arguments)
{
foreach (var argument in arguments)
{

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,18 +12,16 @@ 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 _abpClaimsPrincipalFactory.CreateDynamicAsync((await task).User);
Principal = (await task).User;
};
}
}
@ -34,7 +32,6 @@ public class AbpComponentsClaimsCache : IScopedDependency
{
var authenticationState = await _authenticationStateProvider.GetAuthenticationStateAsync();
Principal = authenticationState.User;
await _abpClaimsPrincipalFactory.CreateDynamicAsync(Principal);
}
}
}

0
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.abppkg.json → framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.abppkg

0
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo.Abp.AspNetCore.Components.WebAssembly.abppkg.json → framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo.Abp.AspNetCore.Components.WebAssembly.abppkg

8
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Extensibility/WebAssemblyLookupApiRequestService.cs

@ -32,14 +32,18 @@ public class WebAssemblyLookupApiRequestService : ILookupApiRequestService, ITra
public async Task<string> SendAsync(string url)
{
var client = HttpClientFactory.CreateClient();
var client = HttpClientFactory.CreateClient(nameof(WebAssemblyLookupApiRequestService));
var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
AddHeaders(requestMessage);
var uri = new Uri(url, UriKind.RelativeOrAbsolute);
if (!uri.IsAbsoluteUri)
{
var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync("Default");
var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultOrNullAsync("Default");
if (remoteServiceConfig == null)
{
throw new AbpException("Remote service configuration 'Default' was not found!");
}
client.BaseAddress = new Uri(remoteServiceConfig.BaseUrl);
await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client, requestMessage, new RemoteServiceConfiguration(remoteServiceConfig.BaseUrl), string.Empty));
}

0
framework/src/Volo.Abp.AspNetCore.Components/Volo.Abp.AspNetCore.Components.abppkg.json → framework/src/Volo.Abp.AspNetCore.Components/Volo.Abp.AspNetCore.Components.abppkg

0
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo.Abp.AspNetCore.MultiTenancy.abppkg.json → framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo.Abp.AspNetCore.MultiTenancy.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo.Abp.AspNetCore.Mvc.Client.Common.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo.Abp.AspNetCore.Mvc.Client.Common.abppkg

8
framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientCommonModule.cs

@ -7,6 +7,7 @@ using Volo.Abp.Features;
using Volo.Abp.Http.Client;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Security.Claims;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Mvc.Client;
@ -40,5 +41,12 @@ public class AbpAspNetCoreMvcClientCommonModule : AbpModule
context.Services.AddTransient<AbpApplicationConfigurationClientProxy>();
context.Services.AddTransient<AbpTenantClientProxy>();
var abpClaimsPrincipalFactoryOptions = context.Services.ExecutePreConfiguredActions<AbpClaimsPrincipalFactoryOptions>();
if (abpClaimsPrincipalFactoryOptions.IsRemoteRefreshEnabled)
{
context.Services.AddTransient<RemoteDynamicClaimsPrincipalContributor>();
context.Services.AddTransient<RemoteDynamicClaimsPrincipalContributorCache>();
}
}
}

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

@ -1,44 +1,10 @@
using System;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.AspNetCore.Mvc.Client;
public class RemoteDynamicClaimsPrincipalContributor : AbpDynamicClaimsPrincipalContributorBase
[DisableConventionalRegistration]
public class RemoteDynamicClaimsPrincipalContributor : RemoteDynamicClaimsPrincipalContributorBase<RemoteDynamicClaimsPrincipalContributor, RemoteDynamicClaimsPrincipalContributorCache>
{
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);
}
}

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

@ -3,24 +3,20 @@ 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 class RemoteDynamicClaimsPrincipalContributorCache : RemoteDynamicClaimsPrincipalContributorCacheBase<RemoteDynamicClaimsPrincipalContributorCache>
{
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(
@ -28,25 +24,20 @@ public class RemoteDynamicClaimsPrincipalContributorCache : ITransientDependency
IHttpClientFactory httpClientFactory,
IOptions<AbpClaimsPrincipalFactoryOptions> abpClaimsPrincipalFactoryOptions,
IRemoteServiceHttpClientAuthenticator httpClientAuthenticator)
: base(abpClaimsPrincipalFactoryOptions)
{
Cache = cache;
HttpClientFactory = httpClientFactory;
AbpClaimsPrincipalFactoryOptions = abpClaimsPrincipalFactoryOptions;
HttpClientAuthenticator = httpClientAuthenticator;
Logger = NullLogger<RemoteDynamicClaimsPrincipalContributorCache>.Instance;
}
public virtual async Task<AbpDynamicClaimCacheItem> GetAsync(Guid userId, Guid? tenantId = null)
protected async override Task<AbpDynamicClaimCacheItem?> GetCacheAsync(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;
}
return await Cache.GetAsync(AbpDynamicClaimCacheItem.CalculateCacheKey(userId, tenantId));
}
Logger.LogDebug($"Refresh dynamic claims for user: {userId} from remote service.");
protected async override Task RefreshAsync(Guid userId, Guid? tenantId = null)
{
try
{
var client = HttpClientFactory.CreateClient(HttpClientName);
@ -60,13 +51,5 @@ public class RemoteDynamicClaimsPrincipalContributorCache : ITransientDependency
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!;
}
}

0
framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo.Abp.AspNetCore.Mvc.Client.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo.Abp.AspNetCore.Mvc.Contracts.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo.Abp.AspNetCore.Mvc.Dapr.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo.Abp.AspNetCore.Mvc.Dapr.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson.abppkg

22
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs

@ -289,7 +289,16 @@ public class AbpInputTagHelperService : AbpTagHelperService<AbpInputTagHelper>
label.Attributes.Add("data-bs-html", "true");
}
label.Attributes.Add("title", TagHelper.LabelTooltip);
label.InnerHtml.AppendHtml($" <i class=\"bi {TagHelper.LabelTooltipIcon}\"></i>");
var iconClass = TagHelper.LabelTooltipIcon;
if (iconClass.StartsWith("bi-"))
{
iconClass = "bi " + iconClass;
}
else if (iconClass.StartsWith("fa-"))
{
iconClass = "fa " + iconClass;
}
label.InnerHtml.AppendHtml($" <i class=\"{iconClass}\"></i>");
}
return label.ToHtmlString();
@ -372,7 +381,16 @@ public class AbpInputTagHelperService : AbpTagHelperService<AbpInputTagHelper>
var innerOutput = await labelTagHelper.ProcessAndGetOutputAsync(attributeList, context, "label", TagMode.StartTagAndEndTag);
if (!TagHelper.LabelTooltip.IsNullOrEmpty())
{
innerOutput.Content.AppendHtml($" <i class=\"bi {TagHelper.LabelTooltipIcon}\"></i>");
var iconClass = TagHelper.LabelTooltipIcon;
if (iconClass.StartsWith("bi-"))
{
iconClass = "bi " + iconClass;
}
else if (iconClass.StartsWith("fa-"))
{
iconClass = "fa " + iconClass;
}
innerOutput.Content.AppendHtml($" <i class=\"{iconClass}\"></i>");
}
return innerOutput.Render(_encoder);

22
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs

@ -547,7 +547,16 @@ public abstract class AbpDatePickerBaseTagHelperService<TTagHelper> : AbpTagHelp
}
label.Attributes.Add("title", TagHelper.LabelTooltip);
label.InnerHtml.AppendHtml($" <i class=\"bi {TagHelper.LabelTooltipIcon}\"></i>");
var iconClass = TagHelper.LabelTooltipIcon;
if (iconClass.StartsWith("bi-"))
{
iconClass = "bi " + iconClass;
}
else if (iconClass.StartsWith("fa-"))
{
iconClass = "fa " + iconClass;
}
label.InnerHtml.AppendHtml($" <i class=\"{iconClass}\"></i>");
}
return label.ToHtmlString();
@ -607,7 +616,16 @@ public abstract class AbpDatePickerBaseTagHelperService<TTagHelper> : AbpTagHelp
await labelTagHelper.ProcessAndGetOutputAsync(attributeList, context, "label", TagMode.StartTagAndEndTag);
if (!TagHelper.LabelTooltip.IsNullOrEmpty())
{
innerOutput.Content.AppendHtml($" <i class=\"bi {TagHelper.LabelTooltipIcon}\"></i>");
var iconClass = TagHelper.LabelTooltipIcon;
if (iconClass.StartsWith("bi-"))
{
iconClass = "bi " + iconClass;
}
else if (iconClass.StartsWith("fa-"))
{
iconClass = "fa " + iconClass;
}
innerOutput.Content.AppendHtml($" <i class=\"{iconClass}\"></i>");
}
return innerOutput.Render(Encoder);

0
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo.Abp.AspNetCore.Mvc.UI.Bundling.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo.Abp.AspNetCore.Mvc.UI.Bundling.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo.Abp.AspNetCore.Mvc.UI.Packages.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo.Abp.AspNetCore.Mvc.UI.Packages.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Demo.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo.Abp.AspNetCore.Mvc.UI.abppkg

0
framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.abppkg.json → framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.abppkg

0
framework/src/Volo.Abp.AspNetCore.Serilog/Volo.Abp.AspNetCore.Serilog.abppkg.json → framework/src/Volo.Abp.AspNetCore.Serilog/Volo.Abp.AspNetCore.Serilog.abppkg

0
framework/src/Volo.Abp.AspNetCore.SignalR/Volo.Abp.AspNetCore.SignalR.abppkg.json → framework/src/Volo.Abp.AspNetCore.SignalR/Volo.Abp.AspNetCore.SignalR.abppkg

0
framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.abppkg.json → framework/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.abppkg

0
framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.abppkg.json → framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.abppkg

0
framework/src/Volo.Abp.Auditing.Contracts/Volo.Abp.Auditing.Contracts.abppkg.json → framework/src/Volo.Abp.Auditing.Contracts/Volo.Abp.Auditing.Contracts.abppkg

0
framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.abppkg.json → framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.abppkg

0
framework/src/Volo.Abp.Authorization.Abstractions/Volo.Abp.Authorization.Abstractions.abppkg.json → framework/src/Volo.Abp.Authorization.Abstractions/Volo.Abp.Authorization.Abstractions.abppkg

0
framework/src/Volo.Abp.Authorization/Volo.Abp.Authorization.abppkg.json → framework/src/Volo.Abp.Authorization/Volo.Abp.Authorization.abppkg

0
framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.abppkg.json → framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.abppkg

0
framework/src/Volo.Abp.Autofac.WebAssembly/Volo.Abp.Autofac.WebAssembly.abppkg.json → framework/src/Volo.Abp.Autofac.WebAssembly/Volo.Abp.Autofac.WebAssembly.abppkg

25
framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Autofac.Core;
using Autofac.Extras.DynamicProxy;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Autofac;
using Volo.Abp.Castle.DynamicProxy;
using Volo.Abp.DependencyInjection;
@ -14,10 +15,14 @@ public static class AbpRegistrationBuilderExtensions
{
public static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> ConfigureAbpConventions<TLimit, TActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> registrationBuilder,
ServiceDescriptor serviceDescriptor,
IModuleContainer moduleContainer,
ServiceRegistrationActionList registrationActionList)
ServiceRegistrationActionList registrationActionList,
ServiceActivatedActionList activatedActionList)
where TActivatorData : ReflectionActivatorData
{
registrationBuilder = registrationBuilder.InvokeActivatedActions(activatedActionList, serviceDescriptor);
var serviceType = registrationBuilder.RegistrationData.Services.OfType<IServiceWithType>().FirstOrDefault()?.ServiceType;
if (serviceType == null)
{
@ -36,6 +41,24 @@ public static class AbpRegistrationBuilderExtensions
return registrationBuilder;
}
private static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> InvokeActivatedActions<TLimit, TActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> registrationBuilder,
ServiceActivatedActionList activatedActionList,
ServiceDescriptor serviceDescriptor)
where TActivatorData : ReflectionActivatorData
{
registrationBuilder.OnActivated(context =>
{
var serviceActivatedContext = new OnServiceActivatedContext(context.Instance!);
foreach (var action in activatedActionList.GetActions(serviceDescriptor))
{
action.Invoke(serviceActivatedContext);
}
});
return registrationBuilder;
}
private static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> InvokeRegistrationActions<TLimit, TActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> registrationBuilder,
ServiceRegistrationActionList registrationActionList,

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

@ -183,6 +183,7 @@ public static class AutofacRegistration
{
var moduleContainer = services.GetSingletonInstance<IModuleContainer>();
var registrationActionList = services.GetRegistrationActionList();
var activatedActionList = services.GetServiceActivatedActionList();
foreach (var descriptor in services)
{
@ -196,7 +197,7 @@ public static class AutofacRegistration
.RegisterGeneric(descriptor.ImplementationType)
.As(descriptor.ServiceType)
.ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons)
.ConfigureAbpConventions(moduleContainer, registrationActionList);
.ConfigureAbpConventions(descriptor, moduleContainer, registrationActionList, activatedActionList);
}
else
{
@ -204,7 +205,7 @@ public static class AutofacRegistration
.RegisterType(descriptor.ImplementationType)
.As(descriptor.ServiceType)
.ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons)
.ConfigureAbpConventions(moduleContainer, registrationActionList);
.ConfigureAbpConventions(descriptor, moduleContainer, registrationActionList, activatedActionList);
}
}
else if (descriptor.ImplementationFactory != null)

0
framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.abppkg.json → framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.abppkg

0
framework/src/Volo.Abp.AzureServiceBus/Volo.Abp.AzureServiceBus.abppkg.json → framework/src/Volo.Abp.AzureServiceBus/Volo.Abp.AzureServiceBus.abppkg

0
framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo.Abp.BackgroundJobs.Abstractions.abppkg.json → framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo.Abp.BackgroundJobs.Abstractions.abppkg

0
framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo.Abp.BackgroundJobs.HangFire.abppkg.json → framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo.Abp.BackgroundJobs.HangFire.abppkg

0
framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo.Abp.BackgroundJobs.Quartz.abppkg.json → framework/src/Volo.Abp.BackgroundJobs.Quartz/Volo.Abp.BackgroundJobs.Quartz.abppkg

0
framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo.Abp.BackgroundJobs.RabbitMQ.abppkg.json → framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo.Abp.BackgroundJobs.RabbitMQ.abppkg

0
framework/src/Volo.Abp.BackgroundJobs/Volo.Abp.BackgroundJobs.abppkg.json → framework/src/Volo.Abp.BackgroundJobs/Volo.Abp.BackgroundJobs.abppkg

0
framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo.Abp.BackgroundWorkers.Hangfire.abppkg.json → framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo.Abp.BackgroundWorkers.Hangfire.abppkg

0
framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo.Abp.BackgroundWorkers.Quartz.abppkg.json → framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo.Abp.BackgroundWorkers.Quartz.abppkg

0
framework/src/Volo.Abp.BackgroundWorkers/Volo.Abp.BackgroundWorkers.abppkg.json → framework/src/Volo.Abp.BackgroundWorkers/Volo.Abp.BackgroundWorkers.abppkg

0
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo.Abp.BlobStoring.Aliyun.abppkg.json → framework/src/Volo.Abp.BlobStoring.Aliyun/Volo.Abp.BlobStoring.Aliyun.abppkg

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

Loading…
Cancel
Save