Browse Source

Switch to the tenant before calling the handleevent method.

Resolve #4508
pull/4555/head
maliming 6 years ago
parent
commit
6f1514da88
  1. 14
      framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs
  2. 1
      framework/src/Volo.Abp.EventBus/Volo.Abp.EventBus.csproj
  3. 2
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs
  4. 80
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs
  5. 8
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs
  6. 29
      framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs
  7. 32
      framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/MySimpleDistributedSingleInstanceEventHandler.cs
  8. 64
      framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_MultiTenancy_Test.cs
  9. 12
      framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/MySimpleEventData.cs

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

@ -9,6 +9,7 @@ using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy;
using Volo.Abp.RabbitMQ;
using Volo.Abp.Threading;
@ -26,7 +27,7 @@ namespace Volo.Abp.EventBus.RabbitMq
protected AbpDistributedEventBusOptions AbpDistributedEventBusOptions { 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; }
@ -37,17 +38,18 @@ namespace Volo.Abp.EventBus.RabbitMq
IOptions<AbpRabbitMqEventBusOptions> options,
IConnectionPool connectionPool,
IRabbitMqSerializer serializer,
IServiceScopeFactory serviceScopeFactory,
IServiceScopeFactory serviceScopeFactory,
IOptions<AbpDistributedEventBusOptions> distributedEventBusOptions,
IRabbitMqMessageConsumerFactory messageConsumerFactory)
: base(serviceScopeFactory)
IRabbitMqMessageConsumerFactory messageConsumerFactory,
ICurrentTenant currentTenant)
: base(serviceScopeFactory, currentTenant)
{
ConnectionPool = connectionPool;
Serializer = serializer;
MessageConsumerFactory = messageConsumerFactory;
AbpDistributedEventBusOptions = distributedEventBusOptions.Value;
AbpRabbitMqEventBusOptions = options.Value;
HandlerFactories = new ConcurrentDictionary<Type, List<IEventHandlerFactory>>();
EventTypes = new ConcurrentDictionary<string, Type>();
}
@ -178,7 +180,7 @@ namespace Volo.Abp.EventBus.RabbitMq
"direct",
durable: true
);
var properties = channel.CreateBasicProperties();
properties.DeliveryMode = RabbitMqConsts.DeliveryModes.Persistent;

1
framework/src/Volo.Abp.EventBus/Volo.Abp.EventBus.csproj

@ -16,6 +16,7 @@
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Core\Volo.Abp.Core.csproj" />
<ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" />
</ItemGroup>
</Project>

2
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs

@ -4,10 +4,12 @@ using System.Collections.Generic;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;
namespace Volo.Abp.EventBus
{
[DependsOn(typeof(AbpMultiTenancyModule))]
public class AbpEventBusModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)

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

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Collections;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;
namespace Volo.Abp.EventBus
@ -16,9 +17,12 @@ namespace Volo.Abp.EventBus
{
protected IServiceScopeFactory ServiceScopeFactory { get; }
protected EventBusBase(IServiceScopeFactory serviceScopeFactory)
protected ICurrentTenant CurrentTenant { get; }
protected EventBusBase(IServiceScopeFactory serviceScopeFactory, ICurrentTenant currentTenant)
{
ServiceScopeFactory = serviceScopeFactory;
CurrentTenant = currentTenant;
}
/// <inheritdoc/>
@ -162,31 +166,34 @@ namespace Volo.Abp.EventBus
{
var handlerType = eventHandlerWrapper.EventHandler.GetType();
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
using (CurrentTenant.Change(GetEventDataTenantId(eventData)))
{
throw new AbpException("The object instance is not an event handler. Object type: " + handlerType.AssemblyQualifiedName);
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);
}
}
}
catch (TargetInvocationException ex)
@ -200,6 +207,27 @@ namespace Volo.Abp.EventBus
}
}
protected virtual Guid? GetEventDataTenantId(object eventData)
{
if (eventData is IMultiTenant multiTenantEventData)
{
return multiTenantEventData.TenantId;
}
//TODO: Cache propertyInfo & Use interface or class to get Entity property.
var propertyInfo = eventData.GetType().GetProperty("Entity");
if (propertyInfo != null && propertyInfo.GetGetMethod(true) != null)
{
var entity = propertyInfo.GetValue(eventData);
if (entity != null && entity is IMultiTenant multiTenantEntity)
{
return multiTenantEntity.TenantId;
}
}
return CurrentTenant.Id;
}
protected class EventTypeWithEventHandlerFactories
{
public Type EventType { get; }
@ -246,4 +274,4 @@ namespace Volo.Abp.EventBus
}
}
}
}
}

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

@ -8,6 +8,7 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
namespace Volo.Abp.EventBus.Local
@ -29,8 +30,9 @@ namespace Volo.Abp.EventBus.Local
public LocalEventBus(
IOptions<AbpLocalEventBusOptions> options,
IServiceScopeFactory serviceScopeFactory)
: base(serviceScopeFactory)
IServiceScopeFactory serviceScopeFactory,
ICurrentTenant currentTenant)
: base(serviceScopeFactory, currentTenant)
{
Options = options.Value;
Logger = NullLogger<LocalEventBus>.Instance;
@ -166,4 +168,4 @@ namespace Volo.Abp.EventBus.Local
return false;
}
}
}
}

29
framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs

@ -1,4 +1,7 @@
using System.Threading.Tasks;
using System;
using System.Threading.Tasks;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.MultiTenancy;
using Xunit;
namespace Volo.Abp.EventBus.Distributed
@ -17,5 +20,29 @@ namespace Volo.Abp.EventBus.Distributed
Assert.Equal(3, MySimpleDistributedTransientEventHandler.HandleCount);
Assert.Equal(3, MySimpleDistributedTransientEventHandler.DisposeCount);
}
[Fact]
public async Task Should_Change_TenantId_If_EventData_Is_MultiTenant()
{
var tenantId = Guid.NewGuid();
DistributedEventBus.Subscribe<MySimpleEventData>(GetRequiredService<MySimpleDistributedSingleInstanceEventHandler>());
await DistributedEventBus.PublishAsync(new MySimpleEventData(3, tenantId));
Assert.Equal(tenantId, MySimpleDistributedSingleInstanceEventHandler.TenantId);
}
[Fact]
public async Task Should_Change_TenantId_If_Generic_EventData_Is_MultiTenant()
{
var tenantId = Guid.NewGuid();
DistributedEventBus.Subscribe<EntityCreatedEto<MySimpleEventData>>(GetRequiredService<MySimpleDistributedSingleInstanceEventHandler>());
await DistributedEventBus.PublishAsync(new MySimpleEventData(3, tenantId));
Assert.Equal(tenantId, MySimpleDistributedSingleInstanceEventHandler.TenantId);
}
}
}

32
framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/MySimpleDistributedSingleInstanceEventHandler.cs

@ -0,0 +1,32 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.EventBus.Distributed
{
public class MySimpleDistributedSingleInstanceEventHandler : IDistributedEventHandler<MySimpleEventData>, IDistributedEventHandler<EntityCreatedEto<MySimpleEventData>>, ITransientDependency
{
private readonly ICurrentTenant _currentTenant;
public MySimpleDistributedSingleInstanceEventHandler(ICurrentTenant currentTenant)
{
_currentTenant = currentTenant;
}
public static Guid? TenantId { get; set; }
public Task HandleEventAsync(MySimpleEventData eventData)
{
TenantId = _currentTenant.Id;
return Task.CompletedTask;
}
public Task HandleEventAsync(EntityCreatedEto<MySimpleEventData> eventData)
{
TenantId = _currentTenant.Id;
return Task.CompletedTask;
}
}
}

64
framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Local/EventBus_MultiTenancy_Test.cs

@ -0,0 +1,64 @@
using System;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.MultiTenancy;
using Xunit;
namespace Volo.Abp.EventBus.Local
{
public class EventBus_MultiTenancy_Test : EventBusTestBase
{
[Fact]
public async Task Should_Change_TenantId_If_EventData_Is_MultiTenant()
{
var tenantId = Guid.NewGuid();
var handler = new MyEventHandler(GetRequiredService<ICurrentTenant>());
LocalEventBus.Subscribe<EntityChangedEventData<MyEntity>>(handler);
await LocalEventBus.PublishAsync(new EntityCreatedEventData<MyEntity>(new MyEntity(tenantId)));
handler.TenantId.ShouldBe(tenantId);
}
public class MyEntity : Entity, IMultiTenant
{
public override object[] GetKeys()
{
return new object[0];
}
public MyEntity()
{
}
public MyEntity(Guid? tenantId)
{
TenantId = tenantId;
}
public Guid? TenantId { get; }
}
public class MyEventHandler : ILocalEventHandler<EntityChangedEventData<MyEntity>>
{
private readonly ICurrentTenant _currentTenant;
public MyEventHandler(ICurrentTenant currentTenant)
{
_currentTenant = currentTenant;
}
public Guid? TenantId { get; set; }
public Task HandleEventAsync(EntityChangedEventData<MyEntity> eventData)
{
TenantId = _currentTenant.Id;
return Task.CompletedTask;
}
}
}
}

12
framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/MySimpleEventData.cs

@ -1,12 +1,18 @@
using System;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.EventBus
{
public class MySimpleEventData
public class MySimpleEventData : IMultiTenant
{
public int Value { get; set; }
public MySimpleEventData(int value)
public Guid? TenantId { get; }
public MySimpleEventData(int value, Guid? tenantId = null)
{
Value = value;
TenantId = tenantId;
}
}
}
}

Loading…
Cancel
Save