Auto register event handlers registered to IOC.

pull/216/head
Halil İbrahim Kalkan 8 years ago
parent 389f9e7996
commit 479f0a08e9

@ -1,13 +1,43 @@
using Microsoft.Extensions.DependencyInjection; using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EventBus.Handlers;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace Volo.Abp.EventBus namespace Volo.Abp.EventBus
{ {
public class AbpEventBusModule : AbpModule public class AbpEventBusModule : AbpModule
{ {
public override void PreConfigureServices(IServiceCollection services)
{
AddEventHandlers(services);
}
public override void ConfigureServices(IServiceCollection services) public override void ConfigureServices(IServiceCollection services)
{ {
services.AddAssemblyOf<AbpEventBusModule>(); services.AddAssemblyOf<AbpEventBusModule>();
} }
private static void AddEventHandlers(IServiceCollection services)
{
var handlers = new List<Type>();
services.OnRegistred(context =>
{
if (context.ImplementationType.GetInterfaces().Any(i => typeof(IEventHandler).IsAssignableFrom(i)))
{
handlers.Add(context.ImplementationType);
}
});
services.Configure<EventBusOptions>(options =>
{
foreach (var handler in handlers)
{
options.Handlers.AddIfNotContains(handler);
}
});
}
} }
} }

@ -8,6 +8,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Factories; using Volo.Abp.EventBus.Factories;
using Volo.Abp.EventBus.Factories.Internals; using Volo.Abp.EventBus.Factories.Internals;
@ -22,11 +23,6 @@ namespace Volo.Abp.EventBus
/// </summary> /// </summary>
public class EventBus : IEventBus, ISingletonDependency public class EventBus : IEventBus, ISingletonDependency
{ {
/// <summary>
/// Gets the default <see cref="EventBus"/> instance.
/// </summary>
public static EventBus Instance { get; } = new EventBus();
/// <summary> /// <summary>
/// Reference to the Logger. /// Reference to the Logger.
/// </summary> /// </summary>
@ -37,16 +33,38 @@ namespace Volo.Abp.EventBus
/// Key: Type of the event /// Key: Type of the event
/// Value: List of handler factories /// Value: List of handler factories
/// </summary> /// </summary>
private readonly ConcurrentDictionary<Type, List<IEventHandlerFactory>> _handlerFactories; protected ConcurrentDictionary<Type, List<IEventHandlerFactory>> HandlerFactories { get; }
/// <summary> protected EventBusOptions Options { get; }
/// Creates a new <see cref="EventBus"/> instance.
/// Instead of creating a new instace, you can use <see cref="Instance"/> to use Global <see cref="EventBus"/>. public EventBus(IOptions<EventBusOptions> options, IServiceProvider serviceProvider)
/// </summary>
public EventBus()
{ {
_handlerFactories = new ConcurrentDictionary<Type, List<IEventHandlerFactory>>(); Options = options.Value;
Logger = NullLogger<EventBus>.Instance; Logger = NullLogger<EventBus>.Instance;
HandlerFactories = new ConcurrentDictionary<Type, List<IEventHandlerFactory>>();
RegisterHandlersInOptions(serviceProvider);
}
protected virtual void RegisterHandlersInOptions(IServiceProvider serviceProvider)
{
foreach (var handler in Options.Handlers)
{
var interfaces = handler.GetInterfaces();
foreach (var @interface in interfaces)
{
if (!typeof(IEventHandler).GetTypeInfo().IsAssignableFrom(@interface))
{
continue;
}
var genericArgs = @interface.GetGenericArguments();
if (genericArgs.Length == 1)
{
Register(genericArgs[0], new IocHandlerFactory(serviceProvider, handler));
}
}
}
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -416,7 +434,7 @@ namespace Volo.Abp.EventBus
{ {
var handlerFactoryList = new List<EventTypeWithEventHandlerFactories>(); var handlerFactoryList = new List<EventTypeWithEventHandlerFactories>();
foreach (var handlerFactory in _handlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key))) foreach (var handlerFactory in HandlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key)))
{ {
handlerFactoryList.Add(new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value)); handlerFactoryList.Add(new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value));
} }
@ -443,7 +461,7 @@ namespace Volo.Abp.EventBus
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType) private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType)
{ {
return _handlerFactories.GetOrAdd(eventType, (type) => new List<IEventHandlerFactory>()); return HandlerFactories.GetOrAdd(eventType, (type) => new List<IEventHandlerFactory>());
} }
private class EventTypeWithEventHandlerFactories private class EventTypeWithEventHandlerFactories

@ -0,0 +1,15 @@
using Volo.Abp.Collections;
using Volo.Abp.EventBus.Handlers;
namespace Volo.Abp.EventBus
{
public class EventBusOptions
{
public ITypeList<IEventHandler> Handlers { get; }
public EventBusOptions()
{
Handlers = new TypeList<IEventHandler>();
}
}
}

@ -10,18 +10,10 @@ namespace Volo.Abp.EventBus.Factories
/// </summary> /// </summary>
public class IocHandlerFactory : IEventHandlerFactory public class IocHandlerFactory : IEventHandlerFactory
{ {
/// <summary>
/// Type of the handler.
/// </summary>
public Type HandlerType { get; } public Type HandlerType { get; }
private readonly IServiceProvider _iocResolver; private readonly IServiceProvider _iocResolver;
/// <summary>
/// Creates a new instance of <see cref="IocHandlerFactory"/> class.
/// </summary>
/// <param name="iocResolver"></param>
/// <param name="handlerType">Type of the handler</param>
public IocHandlerFactory(IServiceProvider iocResolver, Type handlerType) public IocHandlerFactory(IServiceProvider iocResolver, Type handlerType)
{ {
_iocResolver = iocResolver; _iocResolver = iocResolver;
@ -42,10 +34,6 @@ namespace Volo.Abp.EventBus.Factories
return HandlerType; return HandlerType;
} }
/// <summary>
/// Releases handler object using Ioc container.
/// </summary>
/// <param name="handler">Handler to be released</param>
public void ReleaseHandler(IEventHandler handler) public void ReleaseHandler(IEventHandler handler)
{ {
//TODO: Scope!!! //TODO: Scope!!!

@ -13,6 +13,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> <ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Ddd\Volo.Abp.Ddd.csproj" /> <ProjectReference Include="..\..\src\Volo.Abp.Ddd\Volo.Abp.Ddd.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.EventBus\Volo.Abp.EventBus.csproj" /> <ProjectReference Include="..\..\src\Volo.Abp.EventBus\Volo.Abp.EventBus.csproj" />

@ -10,5 +10,10 @@ namespace Volo.Abp.EventBus
{ {
EventBus = GetRequiredService<IEventBus>(); EventBus = GetRequiredService<IEventBus>();
} }
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
} }
} }

@ -0,0 +1,21 @@
using System.Threading.Tasks;
using Shouldly;
using Xunit;
namespace Volo.Abp.EventBus
{
public class EventBus_DI_Services_Test : EventBusTestBase
{
[Fact]
public async Task Should_Automatically_Register_EventHandlers_From_Services()
{
EventBus.Trigger(new MySimpleEventData(1));
await EventBus.TriggerAsync(new MySimpleEventData(2));
EventBus.Trigger(new MySimpleEventData(3));
await EventBus.TriggerAsync(new MySimpleEventData(4));
GetRequiredService<MySimpleEventDataHandler>().TotalData.ShouldBe(10);
GetRequiredService<MySimpleAsyncEventDataHandler>().TotalData.ShouldBe(10);
}
}
}

@ -0,0 +1,17 @@
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Handlers;
namespace Volo.Abp.EventBus
{
public class MySimpleAsyncEventDataHandler : IAsyncEventHandler<MySimpleEventData>, ISingletonDependency
{
public int TotalData { get; private set; }
public Task HandleEventAsync(MySimpleEventData eventData)
{
TotalData += eventData.Value;
return Task.CompletedTask;
}
}
}

@ -0,0 +1,15 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Handlers;
namespace Volo.Abp.EventBus
{
public class MySimpleEventDataHandler : IEventHandler<MySimpleEventData>, ISingletonDependency
{
public int TotalData { get; private set; }
public void HandleEvent(MySimpleEventData eventData)
{
TotalData += eventData.Value;
}
}
}
Loading…
Cancel
Save