Browse Source

Merge branch 'dev' into liangshiwei/inoutbox

pull/11243/head
liangshiwei 5 years ago
parent
commit
9c9c65f56c
  1. 16
      .github/workflows/auto-pr.yml
  2. 2
      common.props
  3. 7
      deploy/_run_all.ps1
  4. 94
      docs/en/Blog-Posts/2022-01-11 v5_1_Preview/POST.md
  5. BIN
      docs/en/Blog-Posts/2022-01-11 v5_1_Preview/abp-community-talks-2022-1.png
  6. 111
      docs/en/Community-Articles/2022-01-10-How-to-test-Blazor-components-in-ABP/POST.md
  7. 8
      docs/en/Tutorials/Part-10.md
  8. 2
      docs/zh-Hans/Entities.md
  9. 1211
      docs/zh-Hans/Tutorials/Part-10.md
  10. 2
      docs/zh-Hans/Tutorials/Part-2.md
  11. 4
      docs/zh-Hans/Tutorials/Part-3.md
  12. 2
      docs/zh-Hans/Tutorials/Part-4.md
  13. 2
      docs/zh-Hans/Tutorials/Part-5.md
  14. 2
      docs/zh-Hans/Tutorials/Part-6.md
  15. 4
      docs/zh-Hans/Tutorials/Part-8.md
  16. 2
      docs/zh-Hans/Tutorials/Part-9.md
  17. BIN
      docs/zh-Hans/Tutorials/images/blazor-bookstore-book-list-with-authors.png
  18. BIN
      docs/zh-Hans/Tutorials/images/book-create-modal-with-author.png
  19. BIN
      docs/zh-Hans/Tutorials/images/bookstore-angular-author-selection.png
  20. BIN
      docs/zh-Hans/Tutorials/images/bookstore-books-with-authorname-angular.png
  21. 3
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js
  22. 15
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs
  23. 89
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs
  24. 1
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs
  25. 40
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs
  26. 1
      framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Program.cs
  27. 2
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
  28. 6
      framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs
  29. 6
      framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs
  30. 591
      framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs
  31. 6
      framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs
  32. 243
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs
  33. 33
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs
  34. 52
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvoker.cs
  35. 8
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvokerCacheItem.cs
  36. 34
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerMethodExecutor.cs
  37. 9
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventHandlerInvoker.cs
  38. 5
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs
  39. 132
      framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs
  40. 5
      framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelDiscoveryDocumentCacheItem.cs
  41. 128
      framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventHandlerInvoker_Tests.cs
  42. 4
      modules/account/Volo.Abp.Account.abpmdl.json
  43. 11
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo.Abp.Account.Application.Contracts.abppkg.analyze.json
  44. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ar.json
  45. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/de-DE.json
  46. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json
  47. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/es.json
  48. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fi.json
  49. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fr.json
  50. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hi.json
  51. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/it.json
  52. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/pt-BR.json
  53. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sk.json
  54. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sl.json
  55. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/tr.json
  56. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json
  57. 1
      modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json
  58. 49
      modules/account/src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.abppkg.analyze.json
  59. 11
      modules/account/src/Volo.Abp.Account.HttpApi.Client/Volo.Abp.Account.HttpApi.Client.abppkg.analyze.json
  60. 11
      modules/account/src/Volo.Abp.Account.HttpApi/Volo.Abp.Account.HttpApi.abppkg.analyze.json
  61. 1
      modules/account/src/Volo.Abp.Account.Installer/Volo.Abp.Account.Installer.abppkg.json
  62. 11
      modules/account/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.abppkg.analyze.json
  63. 4
      modules/audit-logging/Volo.Abp.AuditLogging.abpmdl.json
  64. 11
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo.Abp.AuditLogging.Domain.Shared.abppkg.analyze.json
  65. 41
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo.Abp.AuditLogging.Domain.abppkg.analyze.json
  66. 39
      modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo.Abp.AuditLogging.EntityFrameworkCore.abppkg.analyze.json
  67. 1
      modules/audit-logging/src/Volo.Abp.AuditLogging.Installer/Volo.Abp.AuditLogging.Installer.abppkg.json
  68. 24
      modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo.Abp.AuditLogging.MongoDB.abppkg.analyze.json
  69. 4
      modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo.Abp.AuditLogging.TestBase.abppkg.json
  70. 4
      modules/background-jobs/Volo.Abp.BackgroundJobs.abpmdl.json
  71. 11
      modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain.Shared/Volo.Abp.BackgroundJobs.Domain.Shared.abppkg.analyze.json
  72. 35
      modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo.Abp.BackgroundJobs.Domain.abppkg.analyze.json
  73. 24
      modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo.Abp.BackgroundJobs.EntityFrameworkCore.abppkg.analyze.json
  74. 1
      modules/background-jobs/src/Volo.Abp.BackgroundJobs.Installer/Volo.Abp.BackgroundJobs.Installer.abppkg.json
  75. 24
      modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo.Abp.BackgroundJobs.MongoDB.abppkg.analyze.json
  76. 4
      modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo.Abp.BackgroundJobs.TestBase.abppkg.json
  77. 4
      modules/basic-theme/Volo.Abp.BasicTheme.abpmdl.json
  78. 1
      modules/basic-theme/src/Volo.Abp.BasicTheme.Installer/Volo.Abp.BasicTheme.Installer.abppkg.json
  79. 4
      modules/blob-storing-database/Volo.Abp.BlobStoring.Database.abpmdl.json
  80. 11
      modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared/Volo.Abp.BlobStoring.Database.Domain.Shared.abppkg.analyze.json
  81. 59
      modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain/Volo.Abp.BlobStoring.Database.Domain.abppkg.analyze.json
  82. 29
      modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo.Abp.BlobStoring.Database.EntityFrameworkCore.abppkg.analyze.json
  83. 1
      modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Installer/Volo.Abp.BlobStoring.Database.Installer.abppkg.json
  84. 29
      modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo.Abp.BlobStoring.Database.MongoDB.abppkg.analyze.json
  85. 4
      modules/blob-storing-database/test/Volo.Abp.BlobStoring.Database.TestBase/Volo.Abp.BlobStoring.Database.TestBase.abppkg.json
  86. 103
      modules/blogging/Volo.Blogging.abpmdl.json
  87. 7
      modules/blogging/Volo.Blogging.abpsln.json
  88. 3
      modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Volo.BloggingTestApp.EntityFrameworkCore.abppkg.json
  89. 3
      modules/blogging/app/Volo.BloggingTestApp.MongoDb/Volo.BloggingTestApp.MongoDB.abppkg.json
  90. 3
      modules/blogging/app/Volo.BloggingTestApp/Volo.BloggingTestApp.abppkg.json
  91. 11
      modules/blogging/src/Volo.Blogging.Admin.Application.Contracts/Volo.Blogging.Admin.Application.Contracts.abppkg.analyze.json
  92. 3
      modules/blogging/src/Volo.Blogging.Admin.Application.Contracts/Volo.Blogging.Admin.Application.Contracts.abppkg.json
  93. 20
      modules/blogging/src/Volo.Blogging.Admin.Application/Volo.Blogging.Admin.Application.abppkg.analyze.json
  94. 3
      modules/blogging/src/Volo.Blogging.Admin.Application/Volo.Blogging.Admin.Application.abppkg.json
  95. 3
      modules/blogging/src/Volo.Blogging.Admin.HttpApi.Client/Volo.Blogging.Admin.HttpApi.Client.abppkg.json
  96. 11
      modules/blogging/src/Volo.Blogging.Admin.HttpApi/Volo.Blogging.Admin.HttpApi.abppkg.analyze.json
  97. 3
      modules/blogging/src/Volo.Blogging.Admin.HttpApi/Volo.Blogging.Admin.HttpApi.abppkg.json
  98. 11
      modules/blogging/src/Volo.Blogging.Admin.Web/Volo.Blogging.Admin.Web.abppkg.analyze.json
  99. 3
      modules/blogging/src/Volo.Blogging.Admin.Web/Volo.Blogging.Admin.Web.abppkg.json
  100. 1
      modules/blogging/src/Volo.Blogging.Application.Contracts.Shared/Volo.Blogging.Application.Contracts.Shared.abppkg.json

16
.github/workflows/auto-pr.yml

@ -1,10 +1,10 @@
name: Merge branch dev with rel-5.0
name: Merge branch dev with rel-5.1
on:
push:
branches:
- rel-5.0
- rel-5.1
jobs:
merge-dev-with-rel-5-0:
merge-dev-with-rel-5-1:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@ -12,13 +12,13 @@ jobs:
ref: dev
- name: Reset promotion branch
run: |
git fetch origin rel-5.0:rel-5.0
git reset --hard rel-5.0
git fetch origin rel-5.1:rel-5.1
git reset --hard rel-5.1
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
branch: auto-merge/rel-5-0/${{github.run_number}}
title: Merge branch dev with rel-5.0
body: This PR generated automatically to merge dev with rel-5.0. Please review the changed files before merging to prevent any errors that may occur.
branch: auto-merge/rel-5-1/${{github.run_number}}
title: Merge branch dev with rel-5.1
body: This PR generated automatically to merge dev with rel-5.1. Please review the changed files before merging to prevent any errors that may occur.
reviewers: ${{github.actor}}
token: ${{ github.token }}

2
common.props

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

7
deploy/_run_all.ps1

@ -0,0 +1,7 @@
./1-fetch-and-build.ps1
./2-nuget-pack.ps1
./3-nuget-push.ps1
./4-npm-publish-mvc.ps1
./5-npm-publish-angular.ps1
./6-git-commit.ps1
echo "Create a new release on GitHub manually and run the step 8..."

94
docs/en/Blog-Posts/2022-01-11 v5_1_Preview/POST.md

@ -0,0 +1,94 @@
# ABP.IO Platform 5.1 RC.1 Has Been Released
Today, we are releasing the [ABP Framework](https://abp.io/) and the [ABP Commercial](https://commercial.abp.io/) version **5.1 RC** (Release Candidate). This blog post introduces the new features and important changes in this new version.
> **The planned release date for the [5.1 stable](https://github.com/abpframework/abp/milestone/64) version is February 8, 2022**.
Please try this version and provide feedback for a more stable ABP version 5.1! Thank you all.
## Get Started with the 5.1 RC
follow the steps below to try the version 5.1 RC today;
1) **Upgrade** the ABP CLI to the version `5.1.0-rc.1` using a command line terminal:
````bash
dotnet tool update Volo.Abp.Cli -g --version 5.1.0-rc.1
````
**or install** if you haven't installed before:
````bash
dotnet tool install Volo.Abp.Cli -g --version 5.1.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 *Direct Download* tab on the [Get Started](https://abp.io/get-started) page by selecting the **Preview checkbox**.
You can use any IDE that supports .NET 6.0 development (e.g. [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/)).
### Migration Notes & Breaking Changes
TODO: Startup template changes
## What's new with 5.1?
In this section, I will introduce some major features released with this version.
### DRAFT list of things done
#### ABP Framework
* Use new hosting model for the app template. [#10928](https://github.com/abpframework/abp/pull/10928) - what to do for existing solutions?
* Async application initialization methods on the AbpModule class [#6828](https://github.com/abpframework/abp/issues/6828)
* Angular 13?
* [#10552](https://github.com/abpframework/abp/pull/10696) Used file scoped namespaces :)
* Support markdown in CMS-Kit comments [#10792](https://github.com/abpframework/abp/pull/10792)
* eShopOnAbp is getting mature
* Nightly builds are working again
* Coming: New ABP.IO design!
All issues & PRs in [5.1 milesone](https://github.com/abpframework/abp/milestone/60?closed=1).
#### ABP Commercial
* CMS Kit Pro: URL forwarding
* LeptonX is coming for ABP Blazor and MVC UI too (share the sample dashboard)
### Header 1
TODO
## Community News
### ABP Community Talks 2021.1
![abp-community-talks-2022-1](abp-community-talks-2022-1.png)
This is the second episode of the ABP Community Talks and we are talking about microservice development with the ABP Framework, based on the [eShopOnAbp](https://github.com/abpframework/eShopOnAbp) reference solution. This live meeting will be at **January 20, 2022, 17:00 (UTC)** on YouTube.
**Join this event on the Kommunity platform: https://kommunity.com/volosoft/events/abp-community-talks-20221-microservice-development-acd0f44b**
You can also [subscribe to the Volosoft channel](https://www.youtube.com/channel/UCO3XKlpvq8CA5MQNVS6b3dQ) for reminders for further ABP events and videos.
### New ABP Community posts
Here, some of the recent posts added to the [ABP community](https://community.abp.io/):
* [Minimal API development with the ABP Framework](https://community.abp.io/articles/minimal-api-with-abp-hello-world-part-1-sg5i44p8) by [@antosubash](https://github.com/antosubash) (three parts, video tutorial).
* [Integrating the Syncfusion MVC Components to the ABP MVC UI](https://community.abp.io/articles/integrating-the-syncfusion-mvc-components-to-the-abp-mvc-ui-0gpkr1if) by [@EngincanV](https://github.com/EngincanV).
* [Add Tailwind CSS to your ABP Blazor UI](https://community.abp.io/articles/add-tailwindcss-to-your-abp-blazor-ui-vidiwzcy) by [@antosubash](https://github.com/antosubash) (video tutorial).
* [Import external users into the users Table from an ABP Framework application](https://community.abp.io/articles/import-external-users-into-the-users-table-from-an-abp-framework-application-7lnyw415) by [@bartvanhoey](https://github.com/bartvanhoey).
Thanks to the ABP Community for all the contents they have published. You can also [post your ABP and .NET related (text or video) contents](https://community.abp.io/articles/submit) to the ABP Community.
## Conclusion
In this blog post, I summarized the news about that new version and the ABP Community. Please try it and provide feedback by opening issues on [the GitHub repository](https://github.com/abpframework/abp). Thank you all!

BIN
docs/en/Blog-Posts/2022-01-11 v5_1_Preview/abp-community-talks-2022-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 KiB

111
docs/en/Community-Articles/2022-01-10-How-to-test-Blazor-components-in-ABP/POST.md

@ -0,0 +1,111 @@
# How to Test Blazor Components in ABP
## Source Code
You can find the source of the example solution used in this article [here](https://github.com/abpframework/abp-samples/tree/master/BlazorPageUniTest).
In this article, I will use [bUnit](https://github.com/bUnit-dev/bUnit) for a simple test of a Blazor component.
## Getting Started
Use the ABP CLI to create a blazor app
`abp new BookStore -t app -u blazor`
Then add the `BookStore.Blazor.Tests` xunit test project to the solution, and add [bUnit](https://github.com/bUnit-dev/bUnit) package and `ProjectReference` to the test project.
The contents of `BookStore.Blazor.Tests.csproj`
```xml
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="bunit" Version="1.2.49" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="Volo.Abp.Authorization.Abstractions" Version="5.0.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\BookStore.Blazor\BookStore.Blazor.csproj" />
<ProjectReference Include="..\BookStore.EntityFrameworkCore.Tests\BookStore.EntityFrameworkCore.Tests.csproj" />
</ItemGroup>
</Project>
```
Create `BookStoreBlazorTestModule` that depends on `AbpAspNetCoreComponentsModule` and `BookStoreEntityFrameworkCoreTestModule`.
```cs
[DependsOn(
typeof(AbpAspNetCoreComponentsModule),
typeof(BookStoreEntityFrameworkCoreTestModule)
)]
public class BookStoreBlazorTestModule : AbpModule
{
}
```
Create a `BookStoreBlazorTestBase` class and add the `CreateTestContext` method. The `CreateTestContext` have key code.
It uses ABP's `ServiceProvider` as a fallback `ServiceProvider` and add all ABP's services to the `TestContext`.
```cs
public abstract class BookStoreBlazorTestBase : BookStoreTestBase<BookStoreBlazorTestModule>
{
protected virtual TestContext CreateTestContext()
{
var testContext = new TestContext();
testContext.Services.AddFallbackServiceProvider(ServiceProvider);
foreach (var service in ServiceProvider.GetRequiredService<IAbpApplicationWithExternalServiceProvider>().Services)
{
testContext.Services.Add(service);
}
testContext.Services.AddBlazorise().AddBootstrap5Providers().AddFontAwesomeIcons();
return testContext;
}
}
```
Finally, we add an `Index_Tests` class to test the `Index` component.
```cs
public class Index_Tests : BookStoreBlazorTestBase
{
[Fact]
public void Index_Test()
{
using (var ctx = CreateTestContext())
{
// Act
var cut = ctx.RenderComponent<BookStore.Blazor.Pages.Index>();
// Assert
cut.Find(".lead").InnerHtml.Contains("Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.").ShouldBeTrue();
cut.Find("#username").InnerHtml.Contains("Welcome admin").ShouldBeTrue();
}
}
}
```
## Reference document
https://github.com/bUnit-dev/bUnit
https://docs.microsoft.com/en-us/aspnet/core/blazor/test

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

@ -325,7 +325,7 @@ This new method will be used from the UI to get a list of authors and fill a dro
### BookAppService
Open the `BookAppService` interface in the `Books` folder of the `Acme.BookStore.Application` project and replace the file content with the following code:
Open the `BookAppService` class in the `Books` folder of the `Acme.BookStore.Application` project and replace the file content with the following code:
{{if DB=="EF"}}
@ -449,7 +449,7 @@ namespace Acme.BookStore.Books
{
return sorting.Replace(
"authorName",
"author.Name",
"author.Name",
StringComparison.OrdinalIgnoreCase
);
}
@ -533,7 +533,7 @@ namespace Acme.BookStore.Books
{
input.Sorting = nameof(Book.Name);
}
//Get the IQueryable<Book> from the repository
var queryable = await Repository.GetQueryableAsync();
@ -582,7 +582,7 @@ namespace Acme.BookStore.Books
.ToArray();
var queryable = await _authorRepository.GetQueryableAsync();
var authors = await AsyncExecuter.ToListAsync(
queryable.Where(a => authorIds.Contains(a.Id))
);

2
docs/zh-Hans/Entities.md

@ -26,7 +26,7 @@ public class Book : Entity<Guid>
如果你的实体Id类型为 `Guid`,有一些好的实践可以实现:
* 创建一个构造函数,获取ID作为参数传递给基类.
* 如果没有为GUID Id斌值,**ABP框架会在保存时设置它**,但是在将实体保存到数据库之前最好在实体上有一个有效的Id.
* 如果没有为GUID Id赋值,**ABP框架会在保存时设置它**,但是在将实体保存到数据库之前最好在实体上有一个有效的Id.
* 如果使用带参数的构造函数创建实体,那么还要创建一个 `private` 或 `protected` 构造函数. 当数据库提供程序从数据库读取你的实体时(反序列化时)将使用它.
* 不要使用 `Guid.NewGuid()` 来设置Id! 在创建实体的代码中**使用[`IGuidGenerator`服务](Guid-Generation.md)**传递Id参数. `IGuidGenerator`经过优化可以产生连续的GUID.这对于关系数据库中的聚集索引非常重要.

1211
docs/zh-Hans/Tutorials/Part-10.md

File diff suppressed because it is too large

2
docs/zh-Hans/Tutorials/Part-2.md

@ -16,7 +16,7 @@
本教程分为以下部分:
- [Part 1: 创建服务端](Part-1.md)
- **Part 2: 图书列表页面**(本章)
- **Part 2: 图书列表页面 (本章)**
- [Part 3: 创建,更新和删除图书](Part-3.md)
- [Part 4: 集成测试](Part-4.md)
- [Part 5: 授权](Part-5.md)

4
docs/zh-Hans/Tutorials/Part-3.md

@ -17,7 +17,7 @@
- [Part 1: 创建服务端](Part-1.md)
- [Part 2: 图书列表页面](Part-2.md)
- **Part 3: 创建,更新和删除图书**(本章)
- **Part 3: 创建,更新和删除图书 (本章)**
- [Part 4: 集成测试](Part-4.md)
- [Part 5: 授权](Part-5.md)
- [Part 6: 作者: 领域层](Part-6.md)
@ -1596,4 +1596,4 @@ namespace Acme.BookStore.Blazor
## 下一章
查看本教程的[下一章](Part-4.md).
查看本教程的[下一章](Part-4.md).

2
docs/zh-Hans/Tutorials/Part-4.md

@ -18,7 +18,7 @@
- [Part 1: 创建服务端](Part-1.md)
- [Part 2: 图书列表页面](Part-2.md)
- [Part 3: 创建,更新和删除图书](Part-3.md)
- **Part 4: 集成测试**(本章)
- **Part 4: 集成测试 (本章)**
- [Part 5: 授权](Part-5.md)
- [Part 6: 作者: 领域层](Part-6.md)
- [Part 7: 作者: 数据库集成](Part-7.md)

2
docs/zh-Hans/Tutorials/Part-5.md

@ -19,7 +19,7 @@
- [Part 2: 图书列表页面](Part-2.md)
- [Part 3: 创建,更新和删除图书](Part-2.md)
- [Part 4: 集成测试](Part-4.md)
- **Part 5: 授权**(本章)
- **Part 5: 授权 (本章)**
- [Part 6: 作者: 领域层](Part-6.md)
- [Part 7: 作者: 数据库集成](Part-7.md)
- [Part 8: 作者: 应用服务层](Part-8.md)

2
docs/zh-Hans/Tutorials/Part-6.md

@ -20,7 +20,7 @@
- [Part 3: 创建,更新和删除图书](Part-2.md)
- [Part 4: 集成测试](Part-4.md)
- [Part 5: 授权](Part-5.md)
- **Part 6: 作者: 领域层**(本章)
- **Part 6: 作者: 领域层 (本章)**
- [Part 7: 作者: 数据库集成](Part-7.md)
- [Part 8: 作者: 应用服务层](Part-8.md)
- [Part 9: 作者: 用户页面](Part-9.md)

4
docs/zh-Hans/Tutorials/Part-8.md

@ -22,7 +22,7 @@
- [Part 5: 授权](Part-5.md)
- [Part 6: 作者: 领域层](Part-6.md)
- [Part 7: 作者: 数据库集成](Part-7.md)
- [Part 8: 作者: 应用服务层](本章)
- **Part 8: 作者: 应用服务层 (本章)**
- [Part 9: 作者: 用户页面](Part-9.md)
- [Part 10: 图书到作者的关系](Part-10.md)
@ -391,7 +391,7 @@ authorsPermission.AddChild(
CreateMap<Author, AuthorDto>();
````
## 种子数据
## 数据种子
如同图书管理部分所做的, 在数据库中生成一些初始作者实体. 不仅当第一次运行应用程序时是有用的, 对自动化测试也是很有用的.

2
docs/zh-Hans/Tutorials/Part-9.md

@ -23,7 +23,7 @@
- [Part 6: 作者: 领域层](Part-6.md)
- [Part 7: 作者: 数据库集成](Part-7.md)
- [Part 8: 作者: 应用服务层](Part-8.md)
- [Part 9: 作者: 用户页面](本章)
- **Part 9: 作者: 用户页面 (本章)**
- [Part 10: 图书到作者的关系](Part-10.md)
## 下载源码

BIN
docs/zh-Hans/Tutorials/images/blazor-bookstore-book-list-with-authors.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
docs/zh-Hans/Tutorials/images/book-create-modal-with-author.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
docs/zh-Hans/Tutorials/images/bookstore-angular-author-selection.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
docs/zh-Hans/Tutorials/images/bookstore-books-with-authorname-angular.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

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

@ -100,10 +100,11 @@ var abp = abp || {};
abp.event.on('abp.configurationInitialized', function () {
var l = abp.localization.getResource('AbpUi');
abp.libs.sweetAlert.config.default.confirmButtonText = l('Yes');
abp.libs.sweetAlert.config.default.confirmButtonText = l('Ok');
abp.libs.sweetAlert.config.default.denyButtonText = l('No');
abp.libs.sweetAlert.config.default.cancelButtonText = l('Cancel');
abp.libs.sweetAlert.config.confirm.title = l('AreYouSure');
abp.libs.sweetAlert.config.confirm.confirmButtonText = l('Yes');
abp.libs.sweetAlert.config.confirm.showCancelButton = true;
abp.libs.sweetAlert.config.confirm.reverseButtons = true;
});

15
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs

@ -92,6 +92,21 @@ public class AuthService : IAuthService, ITransientDependency
File.WriteAllText(CliPaths.AccessToken, accessToken, Encoding.UTF8);
}
public async Task DeviceLoginAsync()
{
var configuration = new IdentityClientConfiguration(
CliUrls.AccountAbpIo,
"role email abpio abpio_www abpio_commercial openid offline_access",
"abp-cli",
"1q2w3e*",
OidcConstants.GrantTypes.DeviceCode
);
var accessToken = await AuthenticationService.GetAccessTokenAsync(configuration);
File.WriteAllText(CliPaths.AccessToken, accessToken, Encoding.UTF8);
}
public async Task LogoutAsync()
{
string accessToken = null;

89
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs

@ -42,52 +42,70 @@ public class LoginCommand : IConsoleCommand, ITransientDependency
public async Task ExecuteAsync(CommandLineArgs commandLineArgs)
{
if (commandLineArgs.Target.IsNullOrEmpty())
if (!commandLineArgs.Options.ContainsKey("device"))
{
throw new CliUsageException(
"Username name is missing!" +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
var organization = commandLineArgs.Options.GetOrNull(Options.Organization.Short, Options.Organization.Long);
if (await HasMultipleOrganizationAndThisNotSpecified(commandLineArgs, organization))
{
return;
}
var password = commandLineArgs.Options.GetOrNull(Options.Password.Short, Options.Password.Long);
if (password == null)
{
Console.Write("Password: ");
password = ConsoleHelper.ReadSecret();
if (password.IsNullOrWhiteSpace())
if (commandLineArgs.Target.IsNullOrEmpty())
{
throw new CliUsageException(
"Password is missing!" +
"Username name is missing!" +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
}
try
{
await AuthService.LoginAsync(
commandLineArgs.Target,
password,
organization
);
var organization = commandLineArgs.Options.GetOrNull(Options.Organization.Short, Options.Organization.Long);
if (await HasMultipleOrganizationAndThisNotSpecified(commandLineArgs, organization))
{
return;
}
var password = commandLineArgs.Options.GetOrNull(Options.Password.Short, Options.Password.Long);
if (password == null)
{
Console.Write("Password: ");
password = ConsoleHelper.ReadSecret();
if (password.IsNullOrWhiteSpace())
{
throw new CliUsageException(
"Password is missing!" +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
}
try
{
await AuthService.LoginAsync(
commandLineArgs.Target,
password,
organization
);
}
catch (Exception ex)
{
LogCliError(ex, commandLineArgs);
return;
}
Logger.LogInformation($"Successfully logged in as '{commandLineArgs.Target}'");
}
catch (Exception ex)
else
{
LogCliError(ex, commandLineArgs);
return;
}
try
{
await AuthService.DeviceLoginAsync();
}
catch (Exception ex)
{
LogCliError(ex, commandLineArgs);
return;
}
Logger.LogInformation($"Successfully logged in as '{commandLineArgs.Target}'");
var loginInfo = await AuthService.GetLoginInfoAsync();
Logger.LogInformation($"Successfully logged in as '{loginInfo.Username}'");
}
}
private async Task<bool> HasMultipleOrganizationAndThisNotSpecified(CommandLineArgs commandLineArgs, string organization)
@ -178,6 +196,7 @@ public class LoginCommand : IConsoleCommand, ITransientDependency
sb.AppendLine("Usage:");
sb.AppendLine(" abp login <username>");
sb.AppendLine(" abp login <username> -p <password>");
sb.AppendLine(" abp login <username> --device");
sb.AppendLine("");
sb.AppendLine("Example:");
sb.AppendLine("");

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

@ -182,6 +182,7 @@ public abstract class AppTemplateBase : TemplateInfo
}
else
{
context.Symbols.Add("PUBLIC-REDIS");
context.Symbols.Add("public-website");
}

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

@ -121,7 +121,6 @@ public class NpmPackagesUpdater : ITransientDependency
{
var fileName = Path.Combine(directoryName, ".npmrc");
var abpRegistry = "@abp:registry=https://www.myget.org/F/abp-nightly/npm";
var voloRegistry = await GetVoloRegistryAsync();
if (await NpmrcFileExistAsync(directoryName))
{
@ -132,11 +131,6 @@ public class NpmPackagesUpdater : ITransientDependency
fileContent += Environment.NewLine + abpRegistry;
}
if (!fileContent.Contains(voloRegistry))
{
fileContent += Environment.NewLine + voloRegistry;
}
File.WriteAllText(fileName, fileContent);
return;
@ -145,42 +139,10 @@ public class NpmPackagesUpdater : ITransientDependency
using var fs = File.Create(fileName);
var content = new UTF8Encoding(true)
.GetBytes(abpRegistry + Environment.NewLine + voloRegistry);
.GetBytes(abpRegistry);
fs.Write(content, 0, content.Length);
}
private async Task<string> GetVoloRegistryAsync()
{
var apikey = await GetApiKeyAsync();
if (string.IsNullOrWhiteSpace(apikey))
{
return "";
}
return "@volo:registry=https://www.myget.org/F/abp-commercial/auth/" + apikey + "/npm/";
}
public async Task<string> GetApiKeyAsync()
{
try
{
var client = _cliHttpClientFactory.CreateClient();
using (var response = await client.GetHttpResponseMessageWithRetryAsync(
url: $"{CliUrls.WwwAbpIo}api/myget/apikey/",
cancellationToken: CancellationTokenProvider.Token,
logger: Logger
))
{
return Encoding.Default.GetString(await response.Content.ReadAsByteArrayAsync());
}
}
catch (Exception)
{
return string.Empty;
}
}
private static bool IsAngularProject(string fileDirectory)
{
return File.Exists(Path.Combine(fileDirectory, "angular.json"));

1
framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Program.cs

@ -18,6 +18,7 @@ public class Program
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("Volo.Abp", LogEventLevel.Warning)
.MinimumLevel.Override("System.Net.Http.HttpClient", LogEventLevel.Warning)
.MinimumLevel.Override("Volo.Abp.IdentityModel", LogEventLevel.Information)
#if DEBUG
.MinimumLevel.Override("Volo.Abp.Cli", LogEventLevel.Debug)
#else

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

@ -486,7 +486,7 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
entry.Reload();
entry.Entity.As<ISoftDelete>().IsDeleted = true;
entry.State = EntityState.Modified;
SetDeletionAuditProperties(entry);
}
protected virtual bool IsHardDeleted(EntityEntry entry)

6
framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs

@ -39,13 +39,15 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
IOptions<AbpAzureEventBusOptions> abpAzureEventBusOptions,
IAzureServiceBusSerializer serializer,
IAzureServiceBusMessageConsumerFactory messageConsumerFactory,
IPublisherPool publisherPool)
IPublisherPool publisherPool,
IEventHandlerInvoker eventHandlerInvoker)
: base(serviceScopeFactory,
currentTenant,
unitOfWorkManager,
abpDistributedEventBusOptions,
guidGenerator,
clock)
clock,
eventHandlerInvoker)
{
_options = abpAzureEventBusOptions.Value;
_serializer = serializer;

6
framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs

@ -39,14 +39,16 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
IKafkaSerializer serializer,
IProducerPool producerPool,
IGuidGenerator guidGenerator,
IClock clock)
IClock clock,
IEventHandlerInvoker eventHandlerInvoker)
: base(
serviceScopeFactory,
currentTenant,
unitOfWorkManager,
abpDistributedEventBusOptions,
guidGenerator,
clock)
clock,
eventHandlerInvoker)
{
AbpKafkaEventBusOptions = abpKafkaEventBusOptions.Value;
MessageConsumerFactory = messageConsumerFactory;

591
framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs

@ -16,215 +16,207 @@ using Volo.Abp.Threading;
using Volo.Abp.Timing;
using Volo.Abp.Uow;
namespace Volo.Abp.EventBus.RabbitMq
namespace Volo.Abp.EventBus.RabbitMq;
/* TODO: How to handle unsubscribe to unbind on RabbitMq (may not be possible for)
*/
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IDistributedEventBus), typeof(RabbitMqDistributedEventBus))]
public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDependency
{
/* TODO: How to handle unsubscribe to unbind on RabbitMq (may not be possible for)
*/
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IDistributedEventBus), typeof(RabbitMqDistributedEventBus))]
public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDependency
protected AbpRabbitMqEventBusOptions AbpRabbitMqEventBusOptions { get; }
protected IConnectionPool ConnectionPool { get; }
protected IRabbitMqSerializer Serializer { get; }
//TODO: Accessing to the List<IEventHandlerFactory> may not be thread-safe!
protected ConcurrentDictionary<Type, List<IEventHandlerFactory>> HandlerFactories { get; }
protected ConcurrentDictionary<string, Type> EventTypes { get; }
protected IRabbitMqMessageConsumerFactory MessageConsumerFactory { get; }
protected IRabbitMqMessageConsumer Consumer { get; private set; }
public RabbitMqDistributedEventBus(
IOptions<AbpRabbitMqEventBusOptions> options,
IConnectionPool connectionPool,
IRabbitMqSerializer serializer,
IServiceScopeFactory serviceScopeFactory,
IOptions<AbpDistributedEventBusOptions> distributedEventBusOptions,
IRabbitMqMessageConsumerFactory messageConsumerFactory,
ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager,
IGuidGenerator guidGenerator,
IClock clock,
IEventHandlerInvoker eventHandlerInvoker)
: base(
serviceScopeFactory,
currentTenant,
unitOfWorkManager,
distributedEventBusOptions,
guidGenerator,
clock,
eventHandlerInvoker)
{
protected AbpRabbitMqEventBusOptions AbpRabbitMqEventBusOptions { get; }
protected IConnectionPool ConnectionPool { get; }
protected IRabbitMqSerializer Serializer { get; }
//TODO: Accessing to the List<IEventHandlerFactory> may not be thread-safe!
protected ConcurrentDictionary<Type, List<IEventHandlerFactory>> HandlerFactories { get; }
protected ConcurrentDictionary<string, Type> EventTypes { get; }
protected IRabbitMqMessageConsumerFactory MessageConsumerFactory { get; }
protected IRabbitMqMessageConsumer Consumer { get; private set; }
public RabbitMqDistributedEventBus(
IOptions<AbpRabbitMqEventBusOptions> options,
IConnectionPool connectionPool,
IRabbitMqSerializer serializer,
IServiceScopeFactory serviceScopeFactory,
IOptions<AbpDistributedEventBusOptions> distributedEventBusOptions,
IRabbitMqMessageConsumerFactory messageConsumerFactory,
ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager,
IGuidGenerator guidGenerator,
IClock clock)
: base(
serviceScopeFactory,
currentTenant,
unitOfWorkManager,
distributedEventBusOptions,
guidGenerator,
clock)
{
ConnectionPool = connectionPool;
Serializer = serializer;
MessageConsumerFactory = messageConsumerFactory;
AbpRabbitMqEventBusOptions = options.Value;
ConnectionPool = connectionPool;
Serializer = serializer;
MessageConsumerFactory = messageConsumerFactory;
AbpRabbitMqEventBusOptions = options.Value;
HandlerFactories = new ConcurrentDictionary<Type, List<IEventHandlerFactory>>();
EventTypes = new ConcurrentDictionary<string, Type>();
}
HandlerFactories = new ConcurrentDictionary<Type, List<IEventHandlerFactory>>();
EventTypes = new ConcurrentDictionary<string, Type>();
}
public void Initialize()
{
Consumer = MessageConsumerFactory.Create(
new ExchangeDeclareConfiguration(
AbpRabbitMqEventBusOptions.ExchangeName,
type: "direct",
durable: true
),
new QueueDeclareConfiguration(
AbpRabbitMqEventBusOptions.ClientName,
durable: true,
exclusive: false,
autoDelete: false
),
AbpRabbitMqEventBusOptions.ConnectionName
);
Consumer.OnMessageReceived(ProcessEventAsync);
SubscribeHandlers(AbpDistributedEventBusOptions.Handlers);
}
public void Initialize()
private async Task ProcessEventAsync(IModel channel, BasicDeliverEventArgs ea)
{
var eventName = ea.RoutingKey;
var eventType = EventTypes.GetOrDefault(eventName);
if (eventType == null)
{
Consumer = MessageConsumerFactory.Create(
new ExchangeDeclareConfiguration(
AbpRabbitMqEventBusOptions.ExchangeName,
type: "direct",
durable: true
),
new QueueDeclareConfiguration(
AbpRabbitMqEventBusOptions.ClientName,
durable: true,
exclusive: false,
autoDelete: false
),
AbpRabbitMqEventBusOptions.ConnectionName
);
Consumer.OnMessageReceived(ProcessEventAsync);
SubscribeHandlers(AbpDistributedEventBusOptions.Handlers);
return;
}
private async Task ProcessEventAsync(IModel channel, BasicDeliverEventArgs ea)
var eventBytes = ea.Body.ToArray();
if (await AddToInboxAsync(ea.BasicProperties.MessageId, eventName, eventType, eventBytes))
{
var eventName = ea.RoutingKey;
var eventType = EventTypes.GetOrDefault(eventName);
if (eventType == null)
{
return;
}
return;
}
var eventBytes = ea.Body.ToArray();
var eventData = Serializer.Deserialize(eventBytes, eventType);
if (await AddToInboxAsync(ea.BasicProperties.MessageId, eventName, eventType, eventBytes))
{
return;
}
await TriggerHandlersAsync(eventType, eventData);
}
var eventData = Serializer.Deserialize(eventBytes, eventType);
public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory)
{
var handlerFactories = GetOrCreateHandlerFactories(eventType);
await TriggerHandlersAsync(eventType, eventData);
if (factory.IsInFactories(handlerFactories))
{
return NullDisposable.Instance;
}
public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory)
handlerFactories.Add(factory);
if (handlerFactories.Count == 1) //TODO: Multi-threading!
{
var handlerFactories = GetOrCreateHandlerFactories(eventType);
Consumer.BindAsync(EventNameAttribute.GetNameOrDefault(eventType));
}
if (factory.IsInFactories(handlerFactories))
{
return NullDisposable.Instance;
}
return new EventHandlerFactoryUnregistrar(this, eventType, factory);
}
handlerFactories.Add(factory);
/// <inheritdoc/>
public override void Unsubscribe<TEvent>(Func<TEvent, Task> action)
{
Check.NotNull(action, nameof(action));
if (handlerFactories.Count == 1) //TODO: Multi-threading!
GetOrCreateHandlerFactories(typeof(TEvent))
.Locking(factories =>
{
Consumer.BindAsync(EventNameAttribute.GetNameOrDefault(eventType));
}
return new EventHandlerFactoryUnregistrar(this, eventType, factory);
}
/// <inheritdoc/>
public override void Unsubscribe<TEvent>(Func<TEvent, Task> action)
{
Check.NotNull(action, nameof(action));
factories.RemoveAll(
factory =>
{
var singleInstanceFactory = factory as SingleInstanceHandlerFactory;
if (singleInstanceFactory == null)
{
return false;
}
GetOrCreateHandlerFactories(typeof(TEvent))
.Locking(factories =>
{
factories.RemoveAll(
factory =>
var actionHandler = singleInstanceFactory.HandlerInstance as ActionEventHandler<TEvent>;
if (actionHandler == null)
{
var singleInstanceFactory = factory as SingleInstanceHandlerFactory;
if (singleInstanceFactory == null)
{
return false;
}
var actionHandler = singleInstanceFactory.HandlerInstance as ActionEventHandler<TEvent>;
if (actionHandler == null)
{
return false;
}
return actionHandler.Action == action;
});
});
}
return false;
}
/// <inheritdoc/>
public override void Unsubscribe(Type eventType, IEventHandler handler)
{
GetOrCreateHandlerFactories(eventType)
.Locking(factories =>
{
factories.RemoveAll(
factory =>
factory is SingleInstanceHandlerFactory &&
(factory as SingleInstanceHandlerFactory).HandlerInstance == handler
);
});
}
return actionHandler.Action == action;
});
});
}
/// <inheritdoc/>
public override void Unsubscribe(Type eventType, IEventHandlerFactory factory)
{
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Remove(factory));
}
/// <inheritdoc/>
public override void Unsubscribe(Type eventType, IEventHandler handler)
{
GetOrCreateHandlerFactories(eventType)
.Locking(factories =>
{
factories.RemoveAll(
factory =>
factory is SingleInstanceHandlerFactory &&
(factory as SingleInstanceHandlerFactory).HandlerInstance == handler
);
});
}
/// <inheritdoc/>
public override void UnsubscribeAll(Type eventType)
{
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear());
}
/// <inheritdoc/>
public override void Unsubscribe(Type eventType, IEventHandlerFactory factory)
{
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Remove(factory));
}
protected async override Task PublishToEventBusAsync(Type eventType, object eventData)
{
await PublishAsync(eventType, eventData, null);
}
/// <inheritdoc/>
public override void UnsubscribeAll(Type eventType)
{
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear());
}
protected override void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord)
{
unitOfWork.AddOrReplaceDistributedEvent(eventRecord);
}
protected async override Task PublishToEventBusAsync(Type eventType, object eventData)
{
await PublishAsync(eventType, eventData, null);
}
public override Task PublishFromOutboxAsync(
OutgoingEventInfo outgoingEvent,
OutboxConfig outboxConfig)
{
return PublishAsync(outgoingEvent.EventName, outgoingEvent.EventData, null, eventId: outgoingEvent.Id);
}
protected override void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord)
{
unitOfWork.AddOrReplaceDistributedEvent(eventRecord);
}
public async override Task<MultipleOutgoingEventPublishResult> PublishManyFromOutboxAsync(
IEnumerable<OutgoingEventInfo> outgoingEvents,
OutboxConfig outboxConfig)
public override Task PublishFromOutboxAsync(
OutgoingEventInfo outgoingEvent,
OutboxConfig outboxConfig)
{
return PublishAsync(outgoingEvent.EventName, outgoingEvent.EventData, null, eventId: outgoingEvent.Id);
}
public async override Task<MultipleOutgoingEventPublishResult> PublishManyFromOutboxAsync(
IEnumerable<OutgoingEventInfo> outgoingEvents,
OutboxConfig outboxConfig)
{
using (var channel = ConnectionPool.Get(AbpRabbitMqEventBusOptions.ConnectionName).CreateModel())
{
using (var channel = ConnectionPool.Get(AbpRabbitMqEventBusOptions.ConnectionName).CreateModel())
{
var outgoingEventArray = outgoingEvents.ToArray();
channel.ConfirmSelect();
var outgoingEventArray = outgoingEvents.ToArray();
channel.ConfirmSelect();
var pendingConfirms = new ConcurrentDictionary<ulong, Guid>();
var failures = new ConcurrentBag<Guid>();
var pendingConfirms = new ConcurrentDictionary<ulong, Guid>();
var failures = new ConcurrentBag<Guid>();
void CleanPendingConfirms(ulong sequenceNumber, bool multiple, bool ack)
void CleanPendingConfirms(ulong sequenceNumber, bool multiple, bool ack)
{
if (multiple)
{
if (multiple)
var confirmed = pendingConfirms.Where(x => x.Key <= sequenceNumber);
foreach (var entry in confirmed)
{
var confirmed = pendingConfirms.Where(x => x.Key <= sequenceNumber);
foreach (var entry in confirmed)
{
pendingConfirms.TryRemove(entry.Key, out var eventId);
if (!ack)
{
failures.Add(eventId);
}
}
}
else
{
pendingConfirms.TryRemove(sequenceNumber, out var eventId);
pendingConfirms.TryRemove(entry.Key, out var eventId);
if (!ack)
{
@ -232,163 +224,174 @@ namespace Volo.Abp.EventBus.RabbitMq
}
}
}
foreach (var outgoingEvent in outgoingEventArray)
else
{
pendingConfirms.TryAdd(channel.NextPublishSeqNo, outgoingEvent.Id);
await PublishInternalAsync(channel, outgoingEvent.EventName, outgoingEvent.EventData, null, eventId: outgoingEvent.Id);
}
channel.BasicAcks += (_, ea) => CleanPendingConfirms(ea.DeliveryTag, ea.Multiple, true);
channel.BasicNacks += (_, ea) => CleanPendingConfirms(ea.DeliveryTag, ea.Multiple, false);
pendingConfirms.TryRemove(sequenceNumber, out var eventId);
channel.WaitForConfirms();
return new MultipleOutgoingEventPublishResult(outgoingEventArray.Where(x => !failures.Contains(x.Id)).ToList());
if (!ack)
{
failures.Add(eventId);
}
}
}
}
public async override Task ProcessFromInboxAsync(
IncomingEventInfo incomingEvent,
InboxConfig inboxConfig)
{
var eventType = EventTypes.GetOrDefault(incomingEvent.EventName);
if (eventType == null)
foreach (var outgoingEvent in outgoingEventArray)
{
return;
pendingConfirms.TryAdd(channel.NextPublishSeqNo, outgoingEvent.Id);
await PublishInternalAsync(channel, outgoingEvent.EventName, outgoingEvent.EventData, null,
eventId: outgoingEvent.Id);
}
var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType);
var exceptions = new List<Exception>();
await TriggerHandlersAsync(eventType, eventData, exceptions, inboxConfig);
if (exceptions.Any())
{
ThrowOriginalExceptions(eventType, exceptions);
}
}
channel.BasicAcks += (_, ea) => CleanPendingConfirms(ea.DeliveryTag, ea.Multiple, true);
channel.BasicNacks += (_, ea) => CleanPendingConfirms(ea.DeliveryTag, ea.Multiple, false);
protected override byte[] Serialize(object eventData)
{
return Serializer.Serialize(eventData);
channel.WaitForConfirms();
return new MultipleOutgoingEventPublishResult(outgoingEventArray.Where(x => !failures.Contains(x.Id)).ToList());
}
}
public virtual Task PublishAsync(Type eventType, object eventData, IBasicProperties properties, Dictionary<string, object> headersArguments = null)
public async override Task ProcessFromInboxAsync(
IncomingEventInfo incomingEvent,
InboxConfig inboxConfig)
{
var eventType = EventTypes.GetOrDefault(incomingEvent.EventName);
if (eventType == null)
{
var eventName = EventNameAttribute.GetNameOrDefault(eventType);
var body = Serializer.Serialize(eventData);
return PublishAsync(eventName, body, properties, headersArguments);
return;
}
protected virtual Task PublishAsync(
string eventName,
byte[] body,
IBasicProperties properties,
Dictionary<string, object> headersArguments = null,
Guid? eventId = null)
var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType);
var exceptions = new List<Exception>();
await TriggerHandlersAsync(eventType, eventData, exceptions, inboxConfig);
if (exceptions.Any())
{
using (var channel = ConnectionPool.Get(AbpRabbitMqEventBusOptions.ConnectionName).CreateModel())
{
return PublishInternalAsync(channel, eventName, body, properties, headersArguments, eventId);
}
ThrowOriginalExceptions(eventType, exceptions);
}
}
protected virtual Task PublishInternalAsync(
IModel channel,
string eventName,
byte[] body,
IBasicProperties properties,
Dictionary<string, object> headersArguments = null,
Guid? eventId = null)
{
channel.ExchangeDeclare(
AbpRabbitMqEventBusOptions.ExchangeName,
"direct",
durable: true
);
protected override byte[] Serialize(object eventData)
{
return Serializer.Serialize(eventData);
}
if (properties == null)
{
properties = channel.CreateBasicProperties();
properties.DeliveryMode = RabbitMqConsts.DeliveryModes.Persistent;
}
public virtual Task PublishAsync(Type eventType, object eventData, IBasicProperties properties,
Dictionary<string, object> headersArguments = null)
{
var eventName = EventNameAttribute.GetNameOrDefault(eventType);
var body = Serializer.Serialize(eventData);
if (properties.MessageId.IsNullOrEmpty())
{
properties.MessageId = (eventId ?? GuidGenerator.Create()).ToString("N");
}
return PublishAsync(eventName, body, properties, headersArguments);
}
SetEventMessageHeaders(properties, headersArguments);
protected virtual Task PublishAsync(
string eventName,
byte[] body,
IBasicProperties properties,
Dictionary<string, object> headersArguments = null,
Guid? eventId = null)
{
using (var channel = ConnectionPool.Get(AbpRabbitMqEventBusOptions.ConnectionName).CreateModel())
{
return PublishInternalAsync(channel, eventName, body, properties, headersArguments, eventId);
}
}
channel.BasicPublish(
exchange: AbpRabbitMqEventBusOptions.ExchangeName,
routingKey: eventName,
mandatory: true,
basicProperties: properties,
body: body
);
protected virtual Task PublishInternalAsync(
IModel channel,
string eventName,
byte[] body,
IBasicProperties properties,
Dictionary<string, object> headersArguments = null,
Guid? eventId = null)
{
channel.ExchangeDeclare(
AbpRabbitMqEventBusOptions.ExchangeName,
"direct",
durable: true
);
return Task.CompletedTask;
if (properties == null)
{
properties = channel.CreateBasicProperties();
properties.DeliveryMode = RabbitMqConsts.DeliveryModes.Persistent;
}
private void SetEventMessageHeaders(IBasicProperties properties, Dictionary<string, object> headersArguments)
if (properties.MessageId.IsNullOrEmpty())
{
if (headersArguments == null)
{
return;
}
properties.MessageId = (eventId ?? GuidGenerator.Create()).ToString("N");
}
properties.Headers ??= new Dictionary<string, object>();
SetEventMessageHeaders(properties, headersArguments);
foreach (var header in headersArguments)
{
properties.Headers[header.Key] = header.Value;
}
}
channel.BasicPublish(
exchange: AbpRabbitMqEventBusOptions.ExchangeName,
routingKey: eventName,
mandatory: true,
basicProperties: properties,
body: body
);
return Task.CompletedTask;
}
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType)
private void SetEventMessageHeaders(IBasicProperties properties, Dictionary<string, object> headersArguments)
{
if (headersArguments == null)
{
return HandlerFactories.GetOrAdd(
eventType,
type =>
{
var eventName = EventNameAttribute.GetNameOrDefault(type);
EventTypes[eventName] = type;
return new List<IEventHandlerFactory>();
}
);
return;
}
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetHandlerFactories(Type eventType)
properties.Headers ??= new Dictionary<string, object>();
foreach (var header in headersArguments)
{
var handlerFactoryList = new List<EventTypeWithEventHandlerFactories>();
properties.Headers[header.Key] = header.Value;
}
}
foreach (var handlerFactory in
HandlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key)))
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType)
{
return HandlerFactories.GetOrAdd(
eventType,
type =>
{
handlerFactoryList.Add(
new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value));
var eventName = EventNameAttribute.GetNameOrDefault(type);
EventTypes[eventName] = type;
return new List<IEventHandlerFactory>();
}
);
}
return handlerFactoryList.ToArray();
}
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetHandlerFactories(Type eventType)
{
var handlerFactoryList = new List<EventTypeWithEventHandlerFactories>();
private static bool ShouldTriggerEventForHandler(Type targetEventType, Type handlerEventType)
foreach (var handlerFactory in
HandlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key)))
{
//Should trigger same type
if (handlerEventType == targetEventType)
{
return true;
}
handlerFactoryList.Add(
new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value));
}
//TODO: Support inheritance? But it does not support on subscription to RabbitMq!
//Should trigger for inherited types
if (handlerEventType.IsAssignableFrom(targetEventType))
{
return true;
}
return handlerFactoryList.ToArray();
}
private static bool ShouldTriggerEventForHandler(Type targetEventType, Type handlerEventType)
{
//Should trigger same type
if (handlerEventType == targetEventType)
{
return true;
}
return false;
//TODO: Support inheritance? But it does not support on subscription to RabbitMq!
//Should trigger for inherited types
if (handlerEventType.IsAssignableFrom(targetEventType))
{
return true;
}
return false;
}
}

6
framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs

@ -38,14 +38,16 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
IOptions<AbpRebusEventBusOptions> abpEventBusRebusOptions,
IRebusSerializer serializer,
IGuidGenerator guidGenerator,
IClock clock) :
IClock clock,
IEventHandlerInvoker eventHandlerInvoker) :
base(
serviceScopeFactory,
currentTenant,
unitOfWorkManager,
abpDistributedEventBusOptions,
guidGenerator,
clock)
clock,
eventHandlerInvoker)
{
Rebus = rebus;
Serializer = serializer;

243
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs

@ -8,162 +8,165 @@ using Volo.Abp.MultiTenancy;
using Volo.Abp.Timing;
using Volo.Abp.Uow;
namespace Volo.Abp.EventBus.Distributed
namespace Volo.Abp.EventBus.Distributed;
public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventBus, ISupportsEventBoxes
{
public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventBus, ISupportsEventBoxes
protected IGuidGenerator GuidGenerator { get; }
protected IClock Clock { get; }
protected AbpDistributedEventBusOptions AbpDistributedEventBusOptions { get; }
protected DistributedEventBusBase(
IServiceScopeFactory serviceScopeFactory,
ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager,
IOptions<AbpDistributedEventBusOptions> abpDistributedEventBusOptions,
IGuidGenerator guidGenerator,
IClock clock,
IEventHandlerInvoker eventHandlerInvoker
) : base(
serviceScopeFactory,
currentTenant,
unitOfWorkManager,
eventHandlerInvoker)
{
protected IGuidGenerator GuidGenerator { get; }
protected IClock Clock { get; }
protected AbpDistributedEventBusOptions AbpDistributedEventBusOptions { get; }
protected DistributedEventBusBase(
IServiceScopeFactory serviceScopeFactory,
ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager,
IOptions<AbpDistributedEventBusOptions> abpDistributedEventBusOptions,
IGuidGenerator guidGenerator,
IClock clock
) : base(
serviceScopeFactory,
currentTenant,
unitOfWorkManager)
{
GuidGenerator = guidGenerator;
Clock = clock;
AbpDistributedEventBusOptions = abpDistributedEventBusOptions.Value;
}
GuidGenerator = guidGenerator;
Clock = clock;
AbpDistributedEventBusOptions = abpDistributedEventBusOptions.Value;
}
public IDisposable Subscribe<TEvent>(IDistributedEventHandler<TEvent> handler) where TEvent : class
{
return Subscribe(typeof(TEvent), handler);
}
public IDisposable Subscribe<TEvent>(IDistributedEventHandler<TEvent> handler) where TEvent : class
{
return Subscribe(typeof(TEvent), handler);
}
public override Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true)
{
return PublishAsync(eventType, eventData, onUnitOfWorkComplete, useOutbox: true);
}
public override Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true)
{
return PublishAsync(eventType, eventData, onUnitOfWorkComplete, useOutbox: true);
}
public Task PublishAsync<TEvent>(
TEvent eventData,
bool onUnitOfWorkComplete = true,
bool useOutbox = true)
where TEvent : class
{
return PublishAsync(typeof(TEvent), eventData, onUnitOfWorkComplete, useOutbox);
}
public Task PublishAsync<TEvent>(
TEvent eventData,
bool onUnitOfWorkComplete = true,
bool useOutbox = true)
where TEvent : class
public async Task PublishAsync(
Type eventType,
object eventData,
bool onUnitOfWorkComplete = true,
bool useOutbox = true)
{
if (onUnitOfWorkComplete && UnitOfWorkManager.Current != null)
{
return PublishAsync(typeof(TEvent), eventData, onUnitOfWorkComplete, useOutbox);
AddToUnitOfWork(
UnitOfWorkManager.Current,
new UnitOfWorkEventRecord(eventType, eventData, EventOrderGenerator.GetNext(), useOutbox)
);
return;
}
public async Task PublishAsync(
Type eventType,
object eventData,
bool onUnitOfWorkComplete = true,
bool useOutbox = true)
if (useOutbox)
{
if (onUnitOfWorkComplete && UnitOfWorkManager.Current != null)
if (await AddToOutboxAsync(eventType, eventData))
{
AddToUnitOfWork(
UnitOfWorkManager.Current,
new UnitOfWorkEventRecord(eventType, eventData, EventOrderGenerator.GetNext(), useOutbox)
);
return;
}
}
if (useOutbox)
{
if (await AddToOutboxAsync(eventType, eventData))
{
return;
}
}
await PublishToEventBusAsync(eventType, eventData);
}
await PublishToEventBusAsync(eventType, eventData);
}
public abstract Task PublishFromOutboxAsync(
OutgoingEventInfo outgoingEvent,
OutboxConfig outboxConfig
);
public abstract Task PublishFromOutboxAsync(
OutgoingEventInfo outgoingEvent,
OutboxConfig outboxConfig
);
public abstract Task<MultipleOutgoingEventPublishResult> PublishManyFromOutboxAsync(
IEnumerable<OutgoingEventInfo> outgoingEvents,
OutboxConfig outboxConfig
);
public abstract Task<MultipleOutgoingEventPublishResult> PublishManyFromOutboxAsync(
IEnumerable<OutgoingEventInfo> outgoingEvents,
OutboxConfig outboxConfig
);
public abstract Task ProcessFromInboxAsync(
IncomingEventInfo incomingEvent,
InboxConfig inboxConfig);
public abstract Task ProcessFromInboxAsync(
IncomingEventInfo incomingEvent,
InboxConfig inboxConfig);
private async Task<bool> AddToOutboxAsync(Type eventType, object eventData)
{
var unitOfWork = UnitOfWorkManager.Current;
if (unitOfWork == null)
{
return false;
}
private async Task<bool> AddToOutboxAsync(Type eventType, object eventData)
foreach (var outboxConfig in AbpDistributedEventBusOptions.Outboxes.Values)
{
var unitOfWork = UnitOfWorkManager.Current;
if (unitOfWork == null)
if (outboxConfig.Selector == null || outboxConfig.Selector(eventType))
{
return false;
var eventOutbox =
(IEventOutbox)unitOfWork.ServiceProvider.GetRequiredService(outboxConfig.ImplementationType);
var eventName = EventNameAttribute.GetNameOrDefault(eventType);
await eventOutbox.EnqueueAsync(
new OutgoingEventInfo(
GuidGenerator.Create(),
eventName,
Serialize(eventData),
Clock.Now
)
);
return true;
}
}
foreach (var outboxConfig in AbpDistributedEventBusOptions.Outboxes.Values)
{
if (outboxConfig.Selector == null || outboxConfig.Selector(eventType))
{
var eventOutbox = (IEventOutbox)unitOfWork.ServiceProvider.GetRequiredService(outboxConfig.ImplementationType);
var eventName = EventNameAttribute.GetNameOrDefault(eventType);
await eventOutbox.EnqueueAsync(
new OutgoingEventInfo(
GuidGenerator.Create(),
eventName,
Serialize(eventData),
Clock.Now
)
);
return true;
}
}
return false;
}
protected async Task<bool> AddToInboxAsync(
string messageId,
string eventName,
Type eventType,
byte[] eventBytes)
{
if (AbpDistributedEventBusOptions.Inboxes.Count <= 0)
{
return false;
}
protected async Task<bool> AddToInboxAsync(
string messageId,
string eventName,
Type eventType,
byte[] eventBytes)
using (var scope = ServiceScopeFactory.CreateScope())
{
if (AbpDistributedEventBusOptions.Inboxes.Count <= 0)
foreach (var inboxConfig in AbpDistributedEventBusOptions.Inboxes.Values)
{
return false;
}
using (var scope = ServiceScopeFactory.CreateScope())
{
foreach (var inboxConfig in AbpDistributedEventBusOptions.Inboxes.Values)
if (inboxConfig.EventSelector == null || inboxConfig.EventSelector(eventType))
{
if (inboxConfig.EventSelector == null || inboxConfig.EventSelector(eventType))
{
var eventInbox = (IEventInbox) scope.ServiceProvider.GetRequiredService(inboxConfig.ImplementationType);
var eventInbox =
(IEventInbox)scope.ServiceProvider.GetRequiredService(inboxConfig.ImplementationType);
if (!messageId.IsNullOrEmpty())
if (!messageId.IsNullOrEmpty())
{
if (await eventInbox.ExistsByMessageIdAsync(messageId))
{
if (await eventInbox.ExistsByMessageIdAsync(messageId))
{
continue;
}
continue;
}
await eventInbox.EnqueueAsync(
new IncomingEventInfo(
GuidGenerator.Create(),
messageId,
eventName,
eventBytes,
Clock.Now
)
);
}
await eventInbox.EnqueueAsync(
new IncomingEventInfo(
GuidGenerator.Create(),
messageId,
eventName,
eventBytes,
Clock.Now
)
);
}
}
return true;
}
protected abstract byte[] Serialize(object eventData);
return true;
}
protected abstract byte[] Serialize(object eventData);
}

33
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs

@ -22,14 +22,18 @@ public abstract class EventBusBase : IEventBus
protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected IEventHandlerInvoker EventHandlerInvoker { get; }
protected EventBusBase(
IServiceScopeFactory serviceScopeFactory,
ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager)
IUnitOfWorkManager unitOfWorkManager,
IEventHandlerInvoker eventHandlerInvoker)
{
ServiceScopeFactory = serviceScopeFactory;
CurrentTenant = currentTenant;
UnitOfWorkManager = unitOfWorkManager;
EventHandlerInvoker = eventHandlerInvoker;
}
/// <inheritdoc/>
@ -210,32 +214,7 @@ public abstract class EventBusBase : IEventBus
using (CurrentTenant.Change(GetEventDataTenantId(eventData)))
{
if (ReflectionHelper.IsAssignableToGenericType(handlerType, typeof(ILocalEventHandler<>)))
{
var method = typeof(ILocalEventHandler<>)
.MakeGenericType(eventType)
.GetMethod(
nameof(ILocalEventHandler<object>.HandleEventAsync),
new[] { eventType }
);
await ((Task)method.Invoke(eventHandlerWrapper.EventHandler, new[] { eventData }));
}
else if (ReflectionHelper.IsAssignableToGenericType(handlerType, typeof(IDistributedEventHandler<>)))
{
var method = typeof(IDistributedEventHandler<>)
.MakeGenericType(eventType)
.GetMethod(
nameof(IDistributedEventHandler<object>.HandleEventAsync),
new[] { eventType }
);
await ((Task)method.Invoke(eventHandlerWrapper.EventHandler, new[] { eventData }));
}
else
{
throw new AbpException("The object instance is not an event handler. Object type: " + handlerType.AssemblyQualifiedName);
}
await EventHandlerInvoker.InvokeAsync(eventHandlerWrapper.EventHandler, eventData, eventType);
}
}
catch (TargetInvocationException ex)

52
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvoker.cs

@ -0,0 +1,52 @@
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
namespace Volo.Abp.EventBus;
public class EventHandlerInvoker : IEventHandlerInvoker, ISingletonDependency
{
private readonly ConcurrentDictionary<string, EventHandlerInvokerCacheItem> _cache;
public EventHandlerInvoker()
{
_cache = new ConcurrentDictionary<string, EventHandlerInvokerCacheItem>();
}
public async Task InvokeAsync(IEventHandler eventHandler, object eventData, Type eventType)
{
var cacheItem = _cache.GetOrAdd($"{eventHandler.GetType().FullName}-{eventType.FullName}", _ =>
{
var item = new EventHandlerInvokerCacheItem();
if (typeof(ILocalEventHandler<>).MakeGenericType(eventType).IsInstanceOfType(eventHandler))
{
item.Local = (IEventHandlerMethodExecutor)Activator.CreateInstance(typeof(LocalEventHandlerMethodExecutor<>).MakeGenericType(eventType));
}
if (typeof(IDistributedEventHandler<>).MakeGenericType(eventType).IsInstanceOfType(eventHandler))
{
item.Distributed = (IEventHandlerMethodExecutor)Activator.CreateInstance(typeof(DistributedEventHandlerMethodExecutor<>).MakeGenericType(eventType));
}
return item;
});
if (cacheItem.Local != null)
{
await cacheItem.Local.ExecutorAsync(eventHandler, eventData);
}
if (cacheItem.Distributed != null)
{
await cacheItem.Distributed.ExecutorAsync(eventHandler, eventData);
}
if (cacheItem.Local == null && cacheItem.Distributed == null)
{
throw new AbpException("The object instance is not an event handler. Object type: " + eventHandler.GetType().AssemblyQualifiedName);
}
}
}

8
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvokerCacheItem.cs

@ -0,0 +1,8 @@
namespace Volo.Abp.EventBus;
public class EventHandlerInvokerCacheItem
{
public IEventHandlerMethodExecutor Local { get; set; }
public IEventHandlerMethodExecutor Distributed { get; set; }
}

34
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerMethodExecutor.cs

@ -0,0 +1,34 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.EventBus.Distributed;
namespace Volo.Abp.EventBus;
public delegate Task EventHandlerMethodExecutorAsync(IEventHandler target, object parameter);
public interface IEventHandlerMethodExecutor
{
EventHandlerMethodExecutorAsync ExecutorAsync { get; }
}
public class LocalEventHandlerMethodExecutor<TEvent> : IEventHandlerMethodExecutor
where TEvent : class
{
public EventHandlerMethodExecutorAsync ExecutorAsync => (target, parameter) => target.As<ILocalEventHandler<TEvent>>().HandleEventAsync(parameter.As<TEvent>());
public Task ExecuteAsync(IEventHandler target, TEvent parameters)
{
return ExecutorAsync(target, parameters);
}
}
public class DistributedEventHandlerMethodExecutor<TEvent> : IEventHandlerMethodExecutor
where TEvent : class
{
public EventHandlerMethodExecutorAsync ExecutorAsync => (target, parameter) => target.As<IDistributedEventHandler<TEvent>>().HandleEventAsync(parameter.As<TEvent>());
public Task ExecuteAsync(IEventHandler target, TEvent parameters)
{
return ExecutorAsync(target, parameters);
}
}

9
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventHandlerInvoker.cs

@ -0,0 +1,9 @@
using System;
using System.Threading.Tasks;
namespace Volo.Abp.EventBus;
public interface IEventHandlerInvoker
{
Task InvokeAsync(IEventHandler eventHandler, object eventData, Type eventType);
}

5
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs

@ -33,8 +33,9 @@ public class LocalEventBus : EventBusBase, ILocalEventBus, ISingletonDependency
IOptions<AbpLocalEventBusOptions> options,
IServiceScopeFactory serviceScopeFactory,
ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager)
: base(serviceScopeFactory, currentTenant, unitOfWorkManager)
IUnitOfWorkManager unitOfWorkManager,
IEventHandlerInvoker eventHandlerInvoker)
: base(serviceScopeFactory, currentTenant, unitOfWorkManager, eventHandlerInvoker)
{
Options = options.Value;
Logger = NullLogger<LocalEventBus>.Instance;

132
framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs

@ -5,7 +5,6 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
@ -114,22 +113,34 @@ public class IdentityModelAuthenticationService : IIdentityModelAuthenticationSe
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
}
protected virtual async Task<string> GetTokenEndpoint(IdentityClientConfiguration configuration)
protected virtual async Task<IdentityModelDiscoveryDocumentCacheItem> GetDiscoveryResponse(IdentityClientConfiguration configuration)
{
//TODO: Can use (configuration.Authority + /connect/token) directly?
var tokenEndpointUrlCacheKey = CalculateDiscoveryDocumentCacheKey(configuration);
var discoveryDocumentCacheItem = await DiscoveryDocumentCache.GetAsync(tokenEndpointUrlCacheKey);
if (discoveryDocumentCacheItem == null)
{
var discoveryResponse = await GetDiscoveryResponse(configuration);
DiscoveryDocumentResponse discoveryResponse;
using (var httpClient = HttpClientFactory.CreateClient(HttpClientName))
{
var request = new DiscoveryDocumentRequest
{
Address = configuration.Authority,
Policy =
{
RequireHttps = configuration.RequireHttps
}
};
IdentityModelHttpRequestMessageOptions.ConfigureHttpRequestMessage?.Invoke(request);
discoveryResponse = await httpClient.GetDiscoveryDocumentAsync(request);
}
if (discoveryResponse.IsError)
{
throw new AbpException($"Could not retrieve the OpenId Connect discovery document! " +
$"ErrorType: {discoveryResponse.ErrorType}. Error: {discoveryResponse.Error}");
}
discoveryDocumentCacheItem = new IdentityModelDiscoveryDocumentCacheItem(discoveryResponse.TokenEndpoint);
discoveryDocumentCacheItem = new IdentityModelDiscoveryDocumentCacheItem(discoveryResponse.TokenEndpoint, discoveryResponse.DeviceAuthorizationEndpoint);
await DiscoveryDocumentCache.SetAsync(tokenEndpointUrlCacheKey, discoveryDocumentCacheItem,
new DistributedCacheEntryOptions
{
@ -137,30 +148,11 @@ public class IdentityModelAuthenticationService : IIdentityModelAuthenticationSe
});
}
return discoveryDocumentCacheItem.TokenEndpoint;
}
protected virtual async Task<DiscoveryDocumentResponse> GetDiscoveryResponse(IdentityClientConfiguration configuration)
{
using (var httpClient = HttpClientFactory.CreateClient(HttpClientName))
{
var request = new DiscoveryDocumentRequest
{
Address = configuration.Authority,
Policy =
{
RequireHttps = configuration.RequireHttps
}
};
IdentityModelHttpRequestMessageOptions.ConfigureHttpRequestMessage?.Invoke(request);
return await httpClient.GetDiscoveryDocumentAsync(request);
}
return discoveryDocumentCacheItem;
}
protected virtual async Task<TokenResponse> GetTokenResponse(IdentityClientConfiguration configuration)
{
var tokenEndpoint = await GetTokenEndpoint(configuration);
using (var httpClient = HttpClientFactory.CreateClient(HttpClientName))
{
AddHeaders(httpClient);
@ -169,25 +161,30 @@ public class IdentityModelAuthenticationService : IIdentityModelAuthenticationSe
{
case OidcConstants.GrantTypes.ClientCredentials:
return await httpClient.RequestClientCredentialsTokenAsync(
await CreateClientCredentialsTokenRequestAsync(tokenEndpoint, configuration),
await CreateClientCredentialsTokenRequestAsync(configuration),
CancellationTokenProvider.Token
);
case OidcConstants.GrantTypes.Password:
return await httpClient.RequestPasswordTokenAsync(
await CreatePasswordTokenRequestAsync(tokenEndpoint, configuration),
await CreatePasswordTokenRequestAsync(configuration),
CancellationTokenProvider.Token
);
case OidcConstants.GrantTypes.DeviceCode:
return await RequestDeviceAuthorizationAsync(httpClient, configuration);
default:
throw new AbpException("Grant type was not implemented: " + configuration.GrantType);
}
}
}
protected virtual Task<PasswordTokenRequest> CreatePasswordTokenRequestAsync(string tokenEndpoint, IdentityClientConfiguration configuration)
protected virtual async Task<PasswordTokenRequest> CreatePasswordTokenRequestAsync(IdentityClientConfiguration configuration)
{
var discoveryResponse = await GetDiscoveryResponse(configuration);
var request = new PasswordTokenRequest
{
Address = tokenEndpoint,
Address = discoveryResponse.TokenEndpoint,
Scope = configuration.Scope,
ClientId = configuration.ClientId,
ClientSecret = configuration.ClientSecret,
@ -197,27 +194,90 @@ public class IdentityModelAuthenticationService : IIdentityModelAuthenticationSe
IdentityModelHttpRequestMessageOptions.ConfigureHttpRequestMessage?.Invoke(request);
AddParametersToRequestAsync(configuration, request);
await AddParametersToRequestAsync(configuration, request);
return Task.FromResult(request);
return request;
}
protected virtual Task<ClientCredentialsTokenRequest> CreateClientCredentialsTokenRequestAsync(string tokenEndpoint, IdentityClientConfiguration configuration)
protected virtual async Task<ClientCredentialsTokenRequest> CreateClientCredentialsTokenRequestAsync(IdentityClientConfiguration configuration)
{
var discoveryResponse = await GetDiscoveryResponse(configuration);
var request = new ClientCredentialsTokenRequest
{
Address = tokenEndpoint,
Address = discoveryResponse.TokenEndpoint,
Scope = configuration.Scope,
ClientId = configuration.ClientId,
ClientSecret = configuration.ClientSecret
};
IdentityModelHttpRequestMessageOptions.ConfigureHttpRequestMessage?.Invoke(request);
AddParametersToRequestAsync(configuration, request);
await AddParametersToRequestAsync(configuration, request);
return request;
}
protected virtual async Task<TokenResponse> RequestDeviceAuthorizationAsync(HttpClient httpClient, IdentityClientConfiguration configuration)
{
var discoveryResponse = await GetDiscoveryResponse(configuration);
var request = new DeviceAuthorizationRequest()
{
Address = discoveryResponse.DeviceAuthorizationEndpoint,
Scope = configuration.Scope,
ClientId = configuration.ClientId,
ClientSecret = configuration.ClientSecret,
};
IdentityModelHttpRequestMessageOptions.ConfigureHttpRequestMessage?.Invoke(request);
await AddParametersToRequestAsync(configuration, request);
var response = await httpClient.RequestDeviceAuthorizationAsync(request);
if (response.IsError)
{
throw new AbpException(response.ErrorDescription);
}
Logger.LogInformation($"First copy your one-time code: {response.UserCode}");
Logger.LogInformation($"Open {response.VerificationUri} in your browser...");
for (var i = 0; i < ((response.ExpiresIn ?? 300) / response.Interval + 1); i++)
{
await Task.Delay(response.Interval * 1000);
var tokenResponse = await httpClient.RequestDeviceTokenAsync(new DeviceTokenRequest
{
Address = discoveryResponse.TokenEndpoint,
ClientId = configuration.ClientId,
ClientSecret = configuration.ClientSecret,
DeviceCode = response.DeviceCode
});
return Task.FromResult(request);
if (tokenResponse.IsError)
{
switch (tokenResponse.Error)
{
case "slow_down":
case "authorization_pending":
break;
case "expired_token":
throw new AbpException("This 'device_code' has expired. (expired_token)");
case "access_denied":
throw new AbpException("User denies the request(access_denied)");
}
}
if (!tokenResponse.IsError)
{
return tokenResponse;
}
}
throw new AbpException("Timeout!");
}
protected virtual Task AddParametersToRequestAsync(IdentityClientConfiguration configuration, ProtocolRequest request)
{
foreach (var pair in configuration.Where(p => p.Key.StartsWith("[o]", StringComparison.OrdinalIgnoreCase)))

5
framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelDiscoveryDocumentCacheItem.cs

@ -9,14 +9,17 @@ public class IdentityModelDiscoveryDocumentCacheItem
{
public string TokenEndpoint { get; set; }
public string DeviceAuthorizationEndpoint { get; set; }
public IdentityModelDiscoveryDocumentCacheItem()
{
}
public IdentityModelDiscoveryDocumentCacheItem(string tokenEndpoint)
public IdentityModelDiscoveryDocumentCacheItem(string tokenEndpoint, string deviceAuthorizationEndpoint)
{
TokenEndpoint = tokenEndpoint;
DeviceAuthorizationEndpoint = deviceAuthorizationEndpoint;
}
public static string CalculateCacheKey(IdentityClientConfiguration configuration)

128
framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventHandlerInvoker_Tests.cs

@ -0,0 +1,128 @@
using System;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local;
using Xunit;
namespace Volo.Abp.EventBus;
public class EventHandlerInvoker_Tests : EventBusTestBase
{
private readonly IEventHandlerInvoker _eventHandlerInvoker;
public EventHandlerInvoker_Tests()
{
_eventHandlerInvoker = GetRequiredService<IEventHandlerInvoker>();
}
[Fact]
public async Task Should_Invoke_LocalEventHandler_With_MyEventData()
{
var localHandler = new MyLocalEventHandler();
var eventData = new MyEventData();
await _eventHandlerInvoker.InvokeAsync(localHandler, eventData, eventData.GetType());
localHandler.MyEventDataCount.ShouldBe(2);
localHandler.EntityChangedEventDataCount.ShouldBe(0);
localHandler.EntityChangedEventDataCount.ShouldBe(0);
}
[Fact]
public async Task Should_Invoke_LocalEventHandler_Created_And_Changed_Once()
{
var localHandler = new MyLocalEventHandler();
var eventData = new EntityCreatedEventData<MyEntity>(new MyEntity());
await _eventHandlerInvoker.InvokeAsync(localHandler, eventData, eventData.GetType());
await _eventHandlerInvoker.InvokeAsync(localHandler, eventData, typeof(EntityChangedEventData<MyEntity>));
localHandler.MyEventDataCount.ShouldBe(0);
localHandler.EntityChangedEventDataCount.ShouldBe(1);
localHandler.EntityChangedEventDataCount.ShouldBe(1);
}
[Fact]
public async Task Should_Invoke_DistributedEventHandler_With_MyEventData()
{
var localHandler = new MyDistributedEventHandler();
var eventData = new MyEventData();
await _eventHandlerInvoker.InvokeAsync(localHandler, eventData, eventData.GetType());
localHandler.MyEventDataCount.ShouldBe(1);
localHandler.EntityCreatedCount.ShouldBe(0);
}
[Fact]
public async Task Should_Invoke_DistributedEventHandler_With_EntityCreatedEto()
{
var localHandler = new MyDistributedEventHandler();
var eventData = new EntityCreatedEto<MyEntity>(new MyEntity());
await _eventHandlerInvoker.InvokeAsync(localHandler, eventData, eventData.GetType());
localHandler.MyEventDataCount.ShouldBe(0);
localHandler.EntityCreatedCount.ShouldBe(1);
}
public class MyEventData
{
}
public class MyEntity : Entity<Guid>
{
}
public class MyDistributedEventHandler : IDistributedEventHandler<MyEventData>,
IDistributedEventHandler<EntityCreatedEto<MyEntity>>
{
public int MyEventDataCount { get; set; }
public int EntityCreatedCount { get; set; }
public Task HandleEventAsync(MyEventData eventData)
{
MyEventDataCount++;
return Task.CompletedTask;
}
public Task HandleEventAsync(EntityCreatedEto<MyEntity> eventData)
{
EntityCreatedCount++;
return Task.CompletedTask;
}
}
public class MyLocalEventHandler : ILocalEventHandler<MyEventData>,
IDistributedEventHandler<MyEventData>,
IDistributedEventHandler<EntityCreatedEventData<MyEntity>>,
IDistributedEventHandler<EntityChangedEventData<MyEntity>>
{
public int MyEventDataCount { get; set; }
public int EntityCreatedEventDataCount { get; set; }
public int EntityChangedEventDataCount { get; set; }
public Task HandleEventAsync(MyEventData eventData)
{
MyEventDataCount++;
return Task.CompletedTask;
}
public Task HandleEventAsync(EntityCreatedEventData<MyEntity> eventData)
{
EntityCreatedEventDataCount++;
return Task.CompletedTask;
}
public Task HandleEventAsync(EntityChangedEventData<MyEntity> eventData)
{
EntityChangedEventDataCount++;
return Task.CompletedTask;
}
}
}

4
modules/account/Volo.Abp.Account.abpmdl.json

@ -37,6 +37,10 @@
"Volo.Abp.Account.Blazor": {
"path": "src/Volo.Abp.Account.Blazor/Volo.Abp.Account.Blazor.abppkg.json",
"folder": "src"
},
"Volo.Abp.Account.Installer": {
"path": "src/Volo.Abp.Account.Installer/Volo.Abp.Account.Installer.abppkg.json",
"folder": "src"
}
}
}

11
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo.Abp.Account.Application.Contracts.abppkg.analyze.json

@ -0,0 +1,11 @@
{
"name": "Volo.Abp.Account.Application.Contracts",
"hash": "eda5b3412f7e1dd8dc07761a04f3a064",
"contents": [
{
"namespace": "Volo.Abp.Account",
"contentType": "abpModule",
"name": "AbpAccountApplicationContractsModule"
}
]
}

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ar.json

@ -1,6 +1,7 @@
{
"culture": "ar",
"texts": {
"Menu:Account": "حساب",
"UserName": "اسم المستخدم",
"EmailAddress": "البريد الإلكتروني",
"UserNameOrEmailAddress": "اسم المستخدم أو البريد الإلكتروني",

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/de-DE.json

@ -1,6 +1,7 @@
{
"culture": "de-DE",
"texts": {
"Menu:Account": "Account",
"UserName": "Benutzername",
"EmailAddress": "E-Mail-Adresse",
"UserNameOrEmailAddress": "Benutzername oder E-Mail-Adresse",

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json

@ -1,6 +1,7 @@
{
"culture": "en",
"texts": {
"Menu:Account": "Account",
"UserName": "Username",
"EmailAddress": "Email address",
"UserNameOrEmailAddress": "Username or email address",

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/es.json

@ -1,6 +1,7 @@
{
"culture": "es",
"texts": {
"Menu:Account": "Cuenta",
"UserName": "Nombre de usuario",
"EmailAddress": "Dirección de correo electrónico",
"UserNameOrEmailAddress": "Nombre de usuario o dirección de correo electrónico",

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fi.json

@ -1,6 +1,7 @@
{
"culture": "fi",
"texts": {
"Menu:Account": "Tili",
"UserName": "Käyttäjätunnus",
"EmailAddress": "Sähköpostiosoite",
"UserNameOrEmailAddress": "Käyttäjänimi tai Sähköpostiosoite",

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fr.json

@ -1,6 +1,7 @@
{
"culture": "fr",
"texts": {
"Menu:Account": "Compte",
"UserName": "Nom d'utilisateur",
"EmailAddress": "Adresse e-mail",
"UserNameOrEmailAddress": "Nom d'utilisateur ou adresse e-mail",

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hi.json

@ -1,6 +1,7 @@
{
"culture": "hi",
"texts": {
"Menu:Account": "लेखा",
"UserName": "उपयोगकर्ता नाम",
"EmailAddress": "ईमेल पता",
"UserNameOrEmailAddress": "उपयोगकर्ता का नाम या ईमेल पता",

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/it.json

@ -1,6 +1,7 @@
{
"culture": "it",
"texts": {
"Menu:Account": "Account",
"UserName": "Nome utente",
"EmailAddress": "Indirizzo e-mail",
"UserNameOrEmailAddress": "Username o Indirizzo e-mail",

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/pt-BR.json

@ -1,6 +1,7 @@
{
"culture": "pt-BR",
"texts": {
"Menu:Account": "Conta",
"UserName": "Usuário",
"EmailAddress": "E-mail",
"UserNameOrEmailAddress": "Usuário ou e-mail",

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sk.json

@ -1,6 +1,7 @@
{
"culture": "sk",
"texts": {
"Menu:Account": "Účet",
"UserName": "Používateľské meno",
"EmailAddress": "Emailová adresa",
"UserNameOrEmailAddress": "Používateľské meno alebo emailová adresa",

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sl.json

@ -1,6 +1,7 @@
{
"culture": "sl",
"texts": {
"Menu:Account": "Račun",
"UserName": "Uporabniško ime",
"EmailAddress": "E-poštni naslov",
"UserNameOrEmailAddress": "Uporabniško ime ali e-poštni naslov",

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/tr.json

@ -1,6 +1,7 @@
{
"culture": "tr",
"texts": {
"Menu:Account": "Hesap",
"UserName": "Kullanıcı adı",
"EmailAddress": "E-posta adresi",
"UserNameOrEmailAddress": "Kullanıcı adı veya e-posta",

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json

@ -1,6 +1,7 @@
{
"culture": "zh-Hans",
"texts": {
"Menu:Account": "账户",
"UserName": "用户名称",
"EmailAddress": "邮箱地址",
"UserNameOrEmailAddress": "用户名称或邮箱地址",

1
modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json

@ -1,6 +1,7 @@
{
"culture": "zh-Hant",
"texts": {
"Menu:Account": "帳號",
"UserName": "使用者名稱",
"EmailAddress": "電子信箱地址",
"UserNameOrEmailAddress": "使用者名稱或電子信箱地址",

49
modules/account/src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.abppkg.analyze.json

@ -0,0 +1,49 @@
{
"name": "Volo.Abp.Account.Application",
"hash": "7fb9c3f35b18f2e9a0577d571fccf9df",
"contents": [
{
"namespace": "Volo.Abp.Account",
"contentType": "abpModule",
"name": "AbpAccountApplicationModule"
},
{
"namespace": "Volo.Abp.Account",
"summary": null,
"implementingInterfaces": [
"Volo.Abp.Account.IAccountAppService"
],
"contentType": "applicationService",
"name": "AccountAppService"
},
{
"namespace": "Volo.Abp.Account",
"summary": null,
"implementingInterfaces": [
"Volo.Abp.Account.IProfileAppService"
],
"contentType": "applicationService",
"name": "ProfileAppService"
},
{
"defaultValue": "true",
"displayName": "Is self-registration enabled",
"description": "Whether a user can register the account by him or herself.",
"isVisibleToClient": true,
"isInherited": true,
"isEncrypted": false,
"contentType": "setting",
"name": "Abp.Account.IsSelfRegistrationEnabled"
},
{
"defaultValue": "true",
"displayName": "Authenticate with a local account",
"description": "Indicates if the server will allow users to authenticate with a local account.",
"isVisibleToClient": true,
"isInherited": true,
"isEncrypted": false,
"contentType": "setting",
"name": "Abp.Account.EnableLocalLogin"
}
]
}

11
modules/account/src/Volo.Abp.Account.HttpApi.Client/Volo.Abp.Account.HttpApi.Client.abppkg.analyze.json

@ -0,0 +1,11 @@
{
"name": "Volo.Abp.Account.HttpApi.Client",
"hash": "ca67872e6cd8c25508461f7d171a8f04",
"contents": [
{
"namespace": "Volo.Abp.Account",
"contentType": "abpModule",
"name": "AbpAccountHttpApiClientModule"
}
]
}

11
modules/account/src/Volo.Abp.Account.HttpApi/Volo.Abp.Account.HttpApi.abppkg.analyze.json

@ -0,0 +1,11 @@
{
"name": "Volo.Abp.Account.HttpApi",
"hash": "b178895fe2a7f470f36c4fd121b7c07a",
"contents": [
{
"namespace": "Volo.Abp.Account",
"contentType": "abpModule",
"name": "AbpAccountHttpApiModule"
}
]
}

1
modules/account/src/Volo.Abp.Account.Installer/Volo.Abp.Account.Installer.abppkg.json

@ -0,0 +1 @@
{}

11
modules/account/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.abppkg.analyze.json

@ -0,0 +1,11 @@
{
"name": "Volo.Abp.Account.Web",
"hash": "5fb2aa05261d4febe7ea7083d80fea74",
"contents": [
{
"namespace": "Volo.Abp.Account.Web",
"contentType": "abpModule",
"name": "AbpAccountWebModule"
}
]
}

4
modules/audit-logging/Volo.Abp.AuditLogging.abpmdl.json

@ -37,6 +37,10 @@
"Volo.Abp.AuditLogging.MongoDB.Tests": {
"path": "test/Volo.Abp.AuditLogging.MongoDB.Tests/Volo.Abp.AuditLogging.MongoDB.Tests.abppkg.json",
"folder": "test"
},
"Volo.Abp.AuditLogging.Installer": {
"path": "src/Volo.Abp.AuditLogging.Installer/Volo.Abp.AuditLogging.Installer.abppkg.json",
"folder": "src"
}
}
}

11
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo.Abp.AuditLogging.Domain.Shared.abppkg.analyze.json

@ -0,0 +1,11 @@
{
"name": "Volo.Abp.AuditLogging.Domain.Shared",
"hash": "91305b5b9fa1cd0a8a9adc6a0e54877b",
"contents": [
{
"namespace": "Volo.Abp.AuditLogging",
"contentType": "abpModule",
"name": "AbpAuditLoggingDomainSharedModule"
}
]
}

41
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo.Abp.AuditLogging.Domain.abppkg.analyze.json

@ -0,0 +1,41 @@
{
"name": "Volo.Abp.AuditLogging.Domain",
"hash": "df19d27b7da103de2da1826c6ba8e161",
"contents": [
{
"namespace": "Volo.Abp.AuditLogging",
"contentType": "abpModule",
"name": "AbpAuditLoggingDomainModule"
},
{
"namespace": "Volo.Abp.AuditLogging",
"primaryKeyType": "Guid",
"summary": null,
"collectionProperties": [
"Volo.Abp.AuditLogging.EntityChange",
"Volo.Abp.AuditLogging.AuditLogAction"
],
"navigationProperties": [],
"contentType": "aggregateRoot",
"name": "AuditLog"
},
{
"namespace": "Volo.Abp.AuditLogging",
"summary": null,
"entityModel": {
"namespace": "Volo.Abp.AuditLogging",
"primaryKeyType": "Guid",
"summary": null,
"collectionProperties": [
"Volo.Abp.AuditLogging.EntityChange",
"Volo.Abp.AuditLogging.AuditLogAction"
],
"navigationProperties": [],
"contentType": "entity",
"name": "AuditLog"
},
"contentType": "repositoryInterface",
"name": "IAuditLogRepository"
}
]
}

39
modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore/Volo.Abp.AuditLogging.EntityFrameworkCore.abppkg.analyze.json

@ -0,0 +1,39 @@
{
"name": "Volo.Abp.AuditLogging.EntityFrameworkCore",
"hash": "0495e8cfba68a55319b3774882939845",
"contents": [
{
"namespace": "Volo.Abp.AuditLogging.EntityFrameworkCore",
"contentType": "abpModule",
"name": "AbpAuditLoggingEntityFrameworkCoreModule"
},
{
"namespace": "Volo.Abp.AuditLogging.EntityFrameworkCore",
"connectionStringName": "AbpAuditLogging",
"databaseTables": [
{
"entityFullName": "Volo.Abp.AuditLogging.AuditLog",
"contentType": "databaseTable",
"name": "AbpAuditLogs"
},
{
"entityFullName": "Volo.Abp.AuditLogging.AuditLogAction",
"contentType": "databaseTable",
"name": "AbpAuditLogActions"
},
{
"entityFullName": "Volo.Abp.AuditLogging.EntityChange",
"contentType": "databaseTable",
"name": "AbpEntityChanges"
},
{
"entityFullName": "Volo.Abp.AuditLogging.EntityPropertyChange",
"contentType": "databaseTable",
"name": "AbpEntityPropertyChanges"
}
],
"contentType": "efCoreDbContext",
"name": "AbpAuditLoggingDbContext"
}
]
}

1
modules/audit-logging/src/Volo.Abp.AuditLogging.Installer/Volo.Abp.AuditLogging.Installer.abppkg.json

@ -0,0 +1 @@
{}

24
modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB/Volo.Abp.AuditLogging.MongoDB.abppkg.analyze.json

@ -0,0 +1,24 @@
{
"name": "Volo.Abp.AuditLogging.MongoDB",
"hash": "e87142d2a7e24741c98d02daa9005ac1",
"contents": [
{
"namespace": "Volo.Abp.AuditLogging.MongoDB",
"contentType": "abpModule",
"name": "AbpAuditLoggingMongoDbModule"
},
{
"namespace": "Volo.Abp.AuditLogging.MongoDB",
"connectionStringName": "AbpAuditLogging",
"databaseCollections": [
{
"entityFullName": "Volo.Abp.AuditLogging.AuditLog",
"contentType": "databaseCollection",
"name": "AbpAuditLogs"
}
],
"contentType": "mongoDbContext",
"name": "AuditLoggingMongoDbContext"
}
]
}

4
modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo.Abp.AuditLogging.TestBase.abppkg.json

@ -1 +1,3 @@
{}
{
"role": "lib.test"
}

4
modules/background-jobs/Volo.Abp.BackgroundJobs.abpmdl.json

@ -58,6 +58,10 @@
"Volo.Abp.BackgroundJobs.DemoApp.Quartz": {
"path": "app/Volo.Abp.BackgroundJobs.DemoApp.Quartz/Volo.Abp.BackgroundJobs.DemoApp.Quartz.abppkg.json",
"folder": "app"
},
"Volo.Abp.BackgroundJobs.Installer": {
"path": "src/Volo.Abp.BackgroundJobs.Installer/Volo.Abp.BackgroundJobs.Installer.abppkg.json",
"folder": "src"
}
}
}

11
modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain.Shared/Volo.Abp.BackgroundJobs.Domain.Shared.abppkg.analyze.json

@ -0,0 +1,11 @@
{
"name": "Volo.Abp.BackgroundJobs.Domain.Shared",
"hash": "d48277ec610b23392edcb12ae3e29175",
"contents": [
{
"namespace": "Volo.Abp.BackgroundJobs",
"contentType": "abpModule",
"name": "AbpBackgroundJobsDomainSharedModule"
}
]
}

35
modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo.Abp.BackgroundJobs.Domain.abppkg.analyze.json

@ -0,0 +1,35 @@
{
"name": "Volo.Abp.BackgroundJobs.Domain",
"hash": "1398bbe3f228b2bfd0baec6a64c03b43",
"contents": [
{
"namespace": "Volo.Abp.BackgroundJobs",
"contentType": "abpModule",
"name": "AbpBackgroundJobsDomainModule"
},
{
"namespace": "Volo.Abp.BackgroundJobs",
"primaryKeyType": "Guid",
"summary": null,
"collectionProperties": [],
"navigationProperties": [],
"contentType": "aggregateRoot",
"name": "BackgroundJobRecord"
},
{
"namespace": "Volo.Abp.BackgroundJobs",
"summary": null,
"entityModel": {
"namespace": "Volo.Abp.BackgroundJobs",
"primaryKeyType": "Guid",
"summary": null,
"collectionProperties": [],
"navigationProperties": [],
"contentType": "entity",
"name": "BackgroundJobRecord"
},
"contentType": "repositoryInterface",
"name": "IBackgroundJobRepository"
}
]
}

24
modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo.Abp.BackgroundJobs.EntityFrameworkCore.abppkg.analyze.json

@ -0,0 +1,24 @@
{
"name": "Volo.Abp.BackgroundJobs.EntityFrameworkCore",
"hash": "f3bf7c7db2ab764d6421df0b88ea535b",
"contents": [
{
"namespace": "Volo.Abp.BackgroundJobs.EntityFrameworkCore",
"contentType": "abpModule",
"name": "AbpBackgroundJobsEntityFrameworkCoreModule"
},
{
"namespace": "Volo.Abp.BackgroundJobs.EntityFrameworkCore",
"connectionStringName": "AbpBackgroundJobs",
"databaseTables": [
{
"entityFullName": "Volo.Abp.BackgroundJobs.BackgroundJobRecord",
"contentType": "databaseTable",
"name": "AbpBackgroundJobs"
}
],
"contentType": "efCoreDbContext",
"name": "BackgroundJobsDbContext"
}
]
}

1
modules/background-jobs/src/Volo.Abp.BackgroundJobs.Installer/Volo.Abp.BackgroundJobs.Installer.abppkg.json

@ -0,0 +1 @@
{}

24
modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo.Abp.BackgroundJobs.MongoDB.abppkg.analyze.json

@ -0,0 +1,24 @@
{
"name": "Volo.Abp.BackgroundJobs.MongoDB",
"hash": "def047f007cc2f8c9a74459f1df01330",
"contents": [
{
"namespace": "Volo.Abp.BackgroundJobs.MongoDB",
"contentType": "abpModule",
"name": "AbpBackgroundJobsMongoDbModule"
},
{
"namespace": "Volo.Abp.BackgroundJobs.MongoDB",
"connectionStringName": "AbpBackgroundJobs",
"databaseCollections": [
{
"entityFullName": "Volo.Abp.BackgroundJobs.BackgroundJobRecord",
"contentType": "databaseCollection",
"name": "AbpBackgroundJobs"
}
],
"contentType": "mongoDbContext",
"name": "BackgroundJobsMongoDbContext"
}
]
}

4
modules/background-jobs/test/Volo.Abp.BackgroundJobs.TestBase/Volo.Abp.BackgroundJobs.TestBase.abppkg.json

@ -1 +1,3 @@
{}
{
"role": "lib.test"
}

4
modules/basic-theme/Volo.Abp.BasicTheme.abpmdl.json

@ -33,6 +33,10 @@
"Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests": {
"path": "test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Tests.abppkg.json",
"folder": "test"
},
"Volo.Abp.BasicTheme.Installer": {
"path": "src/Volo.Abp.BasicTheme.Installer/Volo.Abp.BasicTheme.Installer.abppkg.json",
"folder": "src"
}
}
}

1
modules/basic-theme/src/Volo.Abp.BasicTheme.Installer/Volo.Abp.BasicTheme.Installer.abppkg.json

@ -0,0 +1 @@
{}

4
modules/blob-storing-database/Volo.Abp.BlobStoring.Database.abpmdl.json

@ -50,6 +50,10 @@
"BlobStoring.Database.Host.ConsoleApp.ConsoleApp": {
"path": "host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/BlobStoring.Database.Host.ConsoleApp.ConsoleApp.abppkg.json",
"folder": "host/BlobStoring.Database.Host.ConsoleApp/src"
},
"Volo.Abp.BlobStoring.Database.Installer": {
"path": "src/Volo.Abp.BlobStoring.Database.Installer/Volo.Abp.BlobStoring.Database.Installer.abppkg.json",
"folder": "src"
}
}
}

11
modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared/Volo.Abp.BlobStoring.Database.Domain.Shared.abppkg.analyze.json

@ -0,0 +1,11 @@
{
"name": "Volo.Abp.BlobStoring.Database.Domain.Shared",
"hash": "eed9ff456824aac8ba0fe73baa6cf288",
"contents": [
{
"namespace": "Volo.Abp.BlobStoring.Database",
"contentType": "abpModule",
"name": "BlobStoringDatabaseDomainSharedModule"
}
]
}

59
modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain/Volo.Abp.BlobStoring.Database.Domain.abppkg.analyze.json

@ -0,0 +1,59 @@
{
"name": "Volo.Abp.BlobStoring.Database.Domain",
"hash": "744c78df1c9addf5e9f6657295f0529c",
"contents": [
{
"namespace": "Volo.Abp.BlobStoring.Database",
"contentType": "abpModule",
"name": "BlobStoringDatabaseDomainModule"
},
{
"namespace": "Volo.Abp.BlobStoring.Database",
"primaryKeyType": "Guid",
"summary": null,
"collectionProperties": [],
"navigationProperties": [],
"contentType": "aggregateRoot",
"name": "DatabaseBlob"
},
{
"namespace": "Volo.Abp.BlobStoring.Database",
"primaryKeyType": "Guid",
"summary": null,
"collectionProperties": [],
"navigationProperties": [],
"contentType": "aggregateRoot",
"name": "DatabaseBlobContainer"
},
{
"namespace": "Volo.Abp.BlobStoring.Database",
"summary": null,
"entityModel": {
"namespace": "Volo.Abp.BlobStoring.Database",
"primaryKeyType": "Guid",
"summary": null,
"collectionProperties": [],
"navigationProperties": [],
"contentType": "entity",
"name": "DatabaseBlobContainer"
},
"contentType": "repositoryInterface",
"name": "IDatabaseBlobContainerRepository"
},
{
"namespace": "Volo.Abp.BlobStoring.Database",
"summary": null,
"entityModel": {
"namespace": "Volo.Abp.BlobStoring.Database",
"primaryKeyType": "Guid",
"summary": null,
"collectionProperties": [],
"navigationProperties": [],
"contentType": "entity",
"name": "DatabaseBlob"
},
"contentType": "repositoryInterface",
"name": "IDatabaseBlobRepository"
}
]
}

29
modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo.Abp.BlobStoring.Database.EntityFrameworkCore.abppkg.analyze.json

@ -0,0 +1,29 @@
{
"name": "Volo.Abp.BlobStoring.Database.EntityFrameworkCore",
"hash": "91e3a724f35375f79d9505ca0e950b9e",
"contents": [
{
"namespace": "Volo.Abp.BlobStoring.Database.EntityFrameworkCore",
"contentType": "abpModule",
"name": "BlobStoringDatabaseEntityFrameworkCoreModule"
},
{
"namespace": "Volo.Abp.BlobStoring.Database.EntityFrameworkCore",
"connectionStringName": "AbpBlobStoring",
"databaseTables": [
{
"entityFullName": "Volo.Abp.BlobStoring.Database.DatabaseBlob",
"contentType": "databaseTable",
"name": "AbpBlobs"
},
{
"entityFullName": "Volo.Abp.BlobStoring.Database.DatabaseBlobContainer",
"contentType": "databaseTable",
"name": "AbpBlobContainers"
}
],
"contentType": "efCoreDbContext",
"name": "BlobStoringDbContext"
}
]
}

1
modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Installer/Volo.Abp.BlobStoring.Database.Installer.abppkg.json

@ -0,0 +1 @@
{}

29
modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo.Abp.BlobStoring.Database.MongoDB.abppkg.analyze.json

@ -0,0 +1,29 @@
{
"name": "Volo.Abp.BlobStoring.Database.MongoDB",
"hash": "4c911e5e8a2e8c4630d12f394a157819",
"contents": [
{
"namespace": "Volo.Abp.BlobStoring.Database.MongoDB",
"contentType": "abpModule",
"name": "BlobStoringDatabaseMongoDbModule"
},
{
"namespace": "Volo.Abp.BlobStoring.Database.MongoDB",
"connectionStringName": "AbpBlobStoring",
"databaseCollections": [
{
"entityFullName": "Volo.Abp.BlobStoring.Database.DatabaseBlobContainer",
"contentType": "databaseCollection",
"name": "AbpBlobContainers"
},
{
"entityFullName": "Volo.Abp.BlobStoring.Database.DatabaseBlob",
"contentType": "databaseCollection",
"name": "AbpBlobs"
}
],
"contentType": "mongoDbContext",
"name": "BlobStoringMongoDbContext"
}
]
}

4
modules/blob-storing-database/test/Volo.Abp.BlobStoring.Database.TestBase/Volo.Abp.BlobStoring.Database.TestBase.abppkg.json

@ -1 +1,3 @@
{}
{
"role": "lib.test"
}

103
modules/blogging/Volo.Blogging.abpmdl.json

@ -0,0 +1,103 @@
{
"folders": {
"items": {
"src": {},
"app": {},
"test": {}
}
},
"packages": {
"Volo.Blogging.Domain.Shared": {
"path": "src/Volo.Blogging.Domain.Shared/Volo.Blogging.Domain.Shared.abppkg.json",
"folder": "src"
},
"Volo.Blogging.Domain": {
"path": "src/Volo.Blogging.Domain/Volo.Blogging.Domain.abppkg.json",
"folder": "src"
},
"Volo.Blogging.Application.Contracts": {
"path": "src/Volo.Blogging.Application.Contracts/Volo.Blogging.Application.Contracts.abppkg.json",
"folder": "src"
},
"Volo.Blogging.Application": {
"path": "src/Volo.Blogging.Application/Volo.Blogging.Application.abppkg.json",
"folder": "src"
},
"Volo.Blogging.EntityFrameworkCore": {
"path": "src/Volo.Blogging.EntityFrameworkCore/Volo.Blogging.EntityFrameworkCore.abppkg.json",
"folder": "src"
},
"Volo.Blogging.HttpApi": {
"path": "src/Volo.Blogging.HttpApi/Volo.Blogging.HttpApi.abppkg.json",
"folder": "src"
},
"Volo.Blogging.HttpApi.Client": {
"path": "src/Volo.Blogging.HttpApi.Client/Volo.Blogging.HttpApi.Client.abppkg.json",
"folder": "src"
},
"Volo.Blogging.Web": {
"path": "src/Volo.Blogging.Web/Volo.Blogging.Web.abppkg.json",
"folder": "src"
},
"Volo.BloggingTestApp.EntityFrameworkCore": {
"path": "app/Volo.BloggingTestApp.EntityFrameworkCore/Volo.BloggingTestApp.EntityFrameworkCore.abppkg.json",
"folder": "app"
},
"Volo.BloggingTestApp": {
"path": "app/Volo.BloggingTestApp/Volo.BloggingTestApp.abppkg.json",
"folder": "app"
},
"Volo.Blogging.TestBase": {
"path": "test/Volo.Blogging.TestBase/Volo.Blogging.TestBase.abppkg.json",
"folder": "test"
},
"Volo.Blogging.EntityFrameworkCore.Tests": {
"path": "test/Volo.Blogging.EntityFrameworkCore.Tests/Volo.Blogging.EntityFrameworkCore.Tests.abppkg.json",
"folder": "test"
},
"Volo.Blogging.Application.Tests": {
"path": "test/Volo.Blogging.Application.Tests/Volo.Blogging.Application.Tests.abppkg.json",
"folder": "test"
},
"Volo.Blogging.MongoDB": {
"path": "src/Volo.Blogging.MongoDB/Volo.Blogging.MongoDB.abppkg.json",
"folder": "src"
},
"Volo.BloggingTestApp.MongoDB": {
"path": "app/Volo.BloggingTestApp.MongoDB/Volo.BloggingTestApp.MongoDB.abppkg.json",
"folder": "app"
},
"Volo.Blogging.MongoDB.Tests": {
"path": "test/Volo.Blogging.MongoDB.Tests/Volo.Blogging.MongoDB.Tests.abppkg.json",
"folder": "test"
},
"Volo.Blogging.Domain.Tests": {
"path": "test/Volo.Blogging.Domain.Tests/Volo.Blogging.Domain.Tests.abppkg.json",
"folder": "test"
},
"Volo.Blogging.Admin.Application.Contracts": {
"path": "src/Volo.Blogging.Admin.Application.Contracts/Volo.Blogging.Admin.Application.Contracts.abppkg.json",
"folder": "src"
},
"Volo.Blogging.Admin.Application": {
"path": "src/Volo.Blogging.Admin.Application/Volo.Blogging.Admin.Application.abppkg.json",
"folder": "src"
},
"Volo.Blogging.Admin.HttpApi": {
"path": "src/Volo.Blogging.Admin.HttpApi/Volo.Blogging.Admin.HttpApi.abppkg.json",
"folder": "src"
},
"Volo.Blogging.Admin.HttpApi.Client": {
"path": "src/Volo.Blogging.Admin.HttpApi.Client/Volo.Blogging.Admin.HttpApi.Client.abppkg.json",
"folder": "src"
},
"Volo.Blogging.Admin.Web": {
"path": "src/Volo.Blogging.Admin.Web/Volo.Blogging.Admin.Web.abppkg.json",
"folder": "src"
},
"Volo.Blogging.Application.Contracts.Shared": {
"path": "src/Volo.Blogging.Application.Contracts.Shared/Volo.Blogging.Application.Contracts.Shared.abppkg.json",
"folder": "src"
}
}
}

7
modules/blogging/Volo.Blogging.abpsln.json

@ -0,0 +1,7 @@
{
"modules": {
"Volo.Blogging": {
"path": "Volo.Blogging.abpmdl.json"
}
}
}

3
modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Volo.BloggingTestApp.EntityFrameworkCore.abppkg.json

@ -0,0 +1,3 @@
{
"role": "lib.ef"
}

3
modules/blogging/app/Volo.BloggingTestApp.MongoDb/Volo.BloggingTestApp.MongoDB.abppkg.json

@ -0,0 +1,3 @@
{
"role": "lib.mongodb"
}

3
modules/blogging/app/Volo.BloggingTestApp/Volo.BloggingTestApp.abppkg.json

@ -0,0 +1,3 @@
{
"role": "lib.test"
}

11
modules/blogging/src/Volo.Blogging.Admin.Application.Contracts/Volo.Blogging.Admin.Application.Contracts.abppkg.analyze.json

@ -0,0 +1,11 @@
{
"name": "Volo.Blogging.Admin.Application.Contracts",
"hash": "bc5b2c34e2c42cadb2a10a82348aa2b7",
"contents": [
{
"namespace": "Volo.Blogging.Admin",
"contentType": "abpModule",
"name": "BloggingAdminApplicationContractsModule"
}
]
}

3
modules/blogging/src/Volo.Blogging.Admin.Application.Contracts/Volo.Blogging.Admin.Application.Contracts.abppkg.json

@ -0,0 +1,3 @@
{
"role": "lib.application-contracts"
}

20
modules/blogging/src/Volo.Blogging.Admin.Application/Volo.Blogging.Admin.Application.abppkg.analyze.json

@ -0,0 +1,20 @@
{
"name": "Volo.Blogging.Admin.Application",
"hash": "7b36c95fbcf2605d9ea2614cba9ed2b6",
"contents": [
{
"namespace": "Volo.Blogging.Admin",
"contentType": "abpModule",
"name": "BloggingAdminApplicationModule"
},
{
"namespace": "Volo.Blogging.Admin.Blogs",
"summary": null,
"implementingInterfaces": [
"Volo.Blogging.Admin.Blogs.IBlogManagementAppService"
],
"contentType": "applicationService",
"name": "BlogManagementAppService"
}
]
}

3
modules/blogging/src/Volo.Blogging.Admin.Application/Volo.Blogging.Admin.Application.abppkg.json

@ -0,0 +1,3 @@
{
"role": "lib.application"
}

3
modules/blogging/src/Volo.Blogging.Admin.HttpApi.Client/Volo.Blogging.Admin.HttpApi.Client.abppkg.json

@ -0,0 +1,3 @@
{
"role": "lib.http-api-client"
}

11
modules/blogging/src/Volo.Blogging.Admin.HttpApi/Volo.Blogging.Admin.HttpApi.abppkg.analyze.json

@ -0,0 +1,11 @@
{
"name": "Volo.Blogging.Admin.HttpApi",
"hash": "4397a28b60e20715a0d7559a882c7070",
"contents": [
{
"namespace": "Volo.Blogging.Admin",
"contentType": "abpModule",
"name": "BloggingAdminHttpApiModule"
}
]
}

3
modules/blogging/src/Volo.Blogging.Admin.HttpApi/Volo.Blogging.Admin.HttpApi.abppkg.json

@ -0,0 +1,3 @@
{
"role": "lib.http-api"
}

11
modules/blogging/src/Volo.Blogging.Admin.Web/Volo.Blogging.Admin.Web.abppkg.analyze.json

@ -0,0 +1,11 @@
{
"name": "Volo.Blogging.Admin.Web",
"hash": "faf036383d0b2be635023b8f9627038d",
"contents": [
{
"namespace": "Volo.Blogging.Admin",
"contentType": "abpModule",
"name": "BloggingAdminWebModule"
}
]
}

3
modules/blogging/src/Volo.Blogging.Admin.Web/Volo.Blogging.Admin.Web.abppkg.json

@ -0,0 +1,3 @@
{
"role": "lib.mvc"
}

1
modules/blogging/src/Volo.Blogging.Application.Contracts.Shared/Volo.Blogging.Application.Contracts.Shared.abppkg.json

@ -0,0 +1 @@
{}

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

Loading…
Cancel
Save