diff --git a/.github/workflows/auto-pr.yml b/.github/workflows/auto-pr.yml index 533fbb878e..71b6bea747 100644 --- a/.github/workflows/auto-pr.yml +++ b/.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 }} diff --git a/docs/en/Blog-Posts/2022-01-11 v5_1_Preview/POST.md b/docs/en/Blog-Posts/2022-01-11 v5_1_Preview/POST.md new file mode 100644 index 0000000000..f223a67f74 --- /dev/null +++ b/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! diff --git a/docs/en/Blog-Posts/2022-01-11 v5_1_Preview/abp-community-talks-2022-1.png b/docs/en/Blog-Posts/2022-01-11 v5_1_Preview/abp-community-talks-2022-1.png new file mode 100644 index 0000000000..92a137e5ac Binary files /dev/null and b/docs/en/Blog-Posts/2022-01-11 v5_1_Preview/abp-community-talks-2022-1.png differ diff --git a/docs/zh-Hans/Entities.md b/docs/zh-Hans/Entities.md index 85e1132d2b..e54258d61f 100644 --- a/docs/zh-Hans/Entities.md +++ b/docs/zh-Hans/Entities.md @@ -26,7 +26,7 @@ public class Book : Entity 如果你的实体Id类型为 `Guid`,有一些好的实践可以实现: * 创建一个构造函数,获取ID作为参数传递给基类. - * 如果没有为GUID Id斌值,**ABP框架会在保存时设置它**,但是在将实体保存到数据库之前最好在实体上有一个有效的Id. + * 如果没有为GUID Id赋值,**ABP框架会在保存时设置它**,但是在将实体保存到数据库之前最好在实体上有一个有效的Id. * 如果使用带参数的构造函数创建实体,那么还要创建一个 `private` 或 `protected` 构造函数. 当数据库提供程序从数据库读取你的实体时(反序列化时)将使用它. * 不要使用 `Guid.NewGuid()` 来设置Id! 在创建实体的代码中**使用[`IGuidGenerator`服务](Guid-Generation.md)**传递Id参数. `IGuidGenerator`经过优化可以产生连续的GUID.这对于关系数据库中的聚集索引非常重要. diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js index fcdaca076d..51c7db5cd9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/sweetalert2/abp-sweetalert2.js +++ b/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; }); diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index e20a24bbda..1f55bce770 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -486,7 +486,7 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, entry.Reload(); entry.Entity.As().IsDeleted = true; - entry.State = EntityState.Modified; + SetDeletionAuditProperties(entry); } protected virtual bool IsHardDeleted(EntityEntry entry) diff --git a/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs index 3bc51216e6..d8a3d1341a 100644 --- a/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs @@ -39,13 +39,15 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen IOptions 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; diff --git a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs index ec1901161a..a19b01311c 100644 --- a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs +++ b/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; diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs index 1564cfd213..38f8e4eea5 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs @@ -44,14 +44,16 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe ICurrentTenant currentTenant, IUnitOfWorkManager unitOfWorkManager, IGuidGenerator guidGenerator, - IClock clock) + IClock clock, + IEventHandlerInvoker eventHandlerInvoker) : base( serviceScopeFactory, currentTenant, unitOfWorkManager, distributedEventBusOptions, guidGenerator, - clock) + clock, + eventHandlerInvoker) { ConnectionPool = connectionPool; Serializer = serializer; diff --git a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs index 0542a705eb..d637f3fe89 100644 --- a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs @@ -38,14 +38,16 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen IOptions abpEventBusRebusOptions, IRebusSerializer serializer, IGuidGenerator guidGenerator, - IClock clock) : + IClock clock, + IEventHandlerInvoker eventHandlerInvoker) : base( serviceScopeFactory, currentTenant, unitOfWorkManager, abpDistributedEventBusOptions, guidGenerator, - clock) + clock, + eventHandlerInvoker) { Rebus = rebus; Serializer = serializer; diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs index dee9d1f7d3..6547c1686c 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs @@ -22,11 +22,13 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB IUnitOfWorkManager unitOfWorkManager, IOptions abpDistributedEventBusOptions, IGuidGenerator guidGenerator, - IClock clock + IClock clock, + IEventHandlerInvoker eventHandlerInvoker ) : base( serviceScopeFactory, currentTenant, - unitOfWorkManager) + unitOfWorkManager, + eventHandlerInvoker) { GuidGenerator = guidGenerator; Clock = clock; diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs index 15b597da30..6e48b27e5f 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs +++ b/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; } /// @@ -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.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.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) diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvoker.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvoker.cs new file mode 100644 index 0000000000..5c7517cfe1 --- /dev/null +++ b/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 _cache; + + public EventHandlerInvoker() + { + _cache = new ConcurrentDictionary(); + } + + 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); + } + } +} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvokerCacheItem.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvokerCacheItem.cs new file mode 100644 index 0000000000..0ec617afca --- /dev/null +++ b/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; } +} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerMethodExecutor.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerMethodExecutor.cs new file mode 100644 index 0000000000..accbe513b2 --- /dev/null +++ b/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 : IEventHandlerMethodExecutor + where TEvent : class +{ + public EventHandlerMethodExecutorAsync ExecutorAsync => (target, parameter) => target.As>().HandleEventAsync(parameter.As()); + + public Task ExecuteAsync(IEventHandler target, TEvent parameters) + { + return ExecutorAsync(target, parameters); + } +} + +public class DistributedEventHandlerMethodExecutor : IEventHandlerMethodExecutor + where TEvent : class +{ + public EventHandlerMethodExecutorAsync ExecutorAsync => (target, parameter) => target.As>().HandleEventAsync(parameter.As()); + + public Task ExecuteAsync(IEventHandler target, TEvent parameters) + { + return ExecutorAsync(target, parameters); + } +} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventHandlerInvoker.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventHandlerInvoker.cs new file mode 100644 index 0000000000..71c2bb552c --- /dev/null +++ b/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); +} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs index 800c4a61df..3f7dbbc851 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs @@ -33,8 +33,9 @@ public class LocalEventBus : EventBusBase, ILocalEventBus, ISingletonDependency IOptions 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.Instance; diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventHandlerInvoker_Tests.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventHandlerInvoker_Tests.cs new file mode 100644 index 0000000000..294debbb09 --- /dev/null +++ b/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(); + } + + [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(new MyEntity()); + + await _eventHandlerInvoker.InvokeAsync(localHandler, eventData, eventData.GetType()); + await _eventHandlerInvoker.InvokeAsync(localHandler, eventData, typeof(EntityChangedEventData)); + + 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(new MyEntity()); + + await _eventHandlerInvoker.InvokeAsync(localHandler, eventData, eventData.GetType()); + + localHandler.MyEventDataCount.ShouldBe(0); + localHandler.EntityCreatedCount.ShouldBe(1); + } + + public class MyEventData + { + } + + public class MyEntity : Entity + { + + } + + public class MyDistributedEventHandler : IDistributedEventHandler, + IDistributedEventHandler> + { + public int MyEventDataCount { get; set; } + public int EntityCreatedCount { get; set; } + + public Task HandleEventAsync(MyEventData eventData) + { + MyEventDataCount++; + return Task.CompletedTask; + } + + public Task HandleEventAsync(EntityCreatedEto eventData) + { + EntityCreatedCount++; + return Task.CompletedTask; + } + } + + public class MyLocalEventHandler : ILocalEventHandler, + IDistributedEventHandler, + IDistributedEventHandler>, + IDistributedEventHandler> + { + 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 eventData) + { + EntityCreatedEventDataCount++; + return Task.CompletedTask; + } + + public Task HandleEventAsync(EntityChangedEventData eventData) + { + EntityChangedEventDataCount++; + return Task.CompletedTask; + } + } +} diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ar.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ar.json index dee0ecd00c..b9840ed207 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ar.json +++ b/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": "اسم المستخدم أو البريد الإلكتروني", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/de-DE.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/de-DE.json index 8e2aa2fa43..02eae9240d 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/de-DE.json +++ b/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", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json index 246466193e..17f05fe29b 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/en.json +++ b/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", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/es.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/es.json index 8b28c50579..9632dc91f2 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/es.json +++ b/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", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fi.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fi.json index a4e55494eb..42dfb59005 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fi.json +++ b/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", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fr.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fr.json index 6c943322cc..afce5f6bdd 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/fr.json +++ b/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", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hi.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hi.json index e1605b14e2..d406e3f6d5 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/hi.json +++ b/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": "उपयोगकर्ता का नाम या ईमेल पता", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/it.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/it.json index a6ed1f5f6c..5c3dfb77ac 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/it.json +++ b/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", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/pt-BR.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/pt-BR.json index d3cd0e9184..b590b50d8a 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/pt-BR.json +++ b/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", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sk.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sk.json index 9975558eee..c0467110ae 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sk.json +++ b/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", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sl.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sl.json index 43253eba78..5298b8d968 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/sl.json +++ b/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", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/tr.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/tr.json index f9b545b021..6edaf2c1c4 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/tr.json +++ b/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", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json index ffb6730e22..1c51fb1fa9 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hans.json +++ b/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": "用户名称或邮箱地址", diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json index ec80cba8ea..dc0f6a94b9 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json +++ b/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": "使用者名稱或電子信箱地址",