Skip to content

Commit

Permalink
Merge pull request #33 from marcwittke/hotfix/3.2.5
Browse files Browse the repository at this point in the history
Hotfix/3.2.5
  • Loading branch information
marcwittke committed Jun 8, 2018
2 parents c3b7cc7 + 5fc5cc5 commit 7802b55
Show file tree
Hide file tree
Showing 19 changed files with 202 additions and 38 deletions.
9 changes: 5 additions & 4 deletions src/Backend.Fx.Bootstrapping/Modules/DomainModule.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace Backend.Fx.Bootstrapping.Modules
{
using System;
using System.Linq;
using System.Reflection;
using System.Security.Principal;
Expand All @@ -24,7 +25,7 @@ public abstract class DomainModule : SimpleInjectorModule
{
private static readonly ILogger Logger = LogManager.Create<DomainModule>();
private readonly Assembly[] assemblies;
private IDomainEventAggregator domainEventAggregator;
private Func<DomainEventAggregator> domainEventAggregatorFactory;
private readonly string assembliesForLogging;

protected DomainModule(params Assembly[] domainAssemblies)
Expand All @@ -38,7 +39,7 @@ protected DomainModule(params Assembly[] domainAssemblies)

public override void Register(ICompositionRoot compositionRoot)
{
domainEventAggregator = new DomainEventAggregator(compositionRoot);
domainEventAggregatorFactory = ()=>new DomainEventAggregator(compositionRoot);
base.Register(compositionRoot);
}

Expand All @@ -59,8 +60,8 @@ protected override void Register(Container container, ScopedLifestyle scopedLife
// domain event subsystem
Logger.Debug($"Registering domain event handlers from {assembliesForLogging}");
container.Collection.Register(typeof(IDomainEventHandler<>), assemblies);
Logger.Debug("Registering singleton event aggregator instance");
container.RegisterInstance(domainEventAggregator);
Logger.Debug("Registering event aggregator");
container.Register<IDomainEventAggregator>(domainEventAggregatorFactory);

// initial data generation subsystem
Logger.Debug($"Registering initial data generators from {assembliesForLogging}");
Expand Down
6 changes: 4 additions & 2 deletions src/Backend.Fx.EfCorePersistence/EfUnitOfWork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Patterns.DependencyInjection;
using Patterns.EventAggregation.Domain;
using Patterns.EventAggregation.Integration;
using Patterns.UnitOfWork;

public class EfUnitOfWork : UnitOfWork, ICanInterruptTransaction
Expand All @@ -15,8 +17,8 @@ public class EfUnitOfWork : UnitOfWork, ICanInterruptTransaction
private IDisposable transactionLifetimeLogger;
private IDbContextTransaction currentTransaction;

public EfUnitOfWork(IClock clock, ICurrentTHolder<IIdentity> identityHolder, DbContext dbContext)
: base(clock, identityHolder)
public EfUnitOfWork(IClock clock, ICurrentTHolder<IIdentity> identityHolder, IDomainEventAggregator eventAggregator, IEventBusScope eventBusScope, DbContext dbContext)
: base(clock, identityHolder, eventAggregator, eventBusScope)
{
DbContext = dbContext;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
using Environment.Authentication;
using Environment.DateAndTime;
using FakeItEasy;
using Patterns.EventAggregation.Domain;
using Patterns.EventAggregation.Integration;
using Patterns.UnitOfWork;
using SimpleInjector;

Expand Down Expand Up @@ -43,7 +45,11 @@ protected override void Register(Container container, ScopedLifestyle scopedLife
container.Register(typeof(IRepository<>), typeof(InMemoryRepository<>));
container.Register(typeof(IQueryable<>), typeof(InMemoryQueryable<>));

var uowRegistration = Lifestyle.Scoped.CreateRegistration(() => new InMemoryUnitOfWork(new FrozenClock(), CurrentIdentityHolder.CreateSystem()), container);
var uowRegistration = Lifestyle.Scoped.CreateRegistration(
() => new InMemoryUnitOfWork(new FrozenClock(), CurrentIdentityHolder.CreateSystem(),
container.GetInstance<IDomainEventAggregator>(),
container.GetInstance<IEventBusScope>()),
container);
container.AddRegistration(typeof(IUnitOfWork), uowRegistration);
container.AddRegistration(typeof(ICanFlush), uowRegistration);
container.Register(A.Fake<IReadonlyUnitOfWork>);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
using System.Security.Principal;
using Environment.DateAndTime;
using Patterns.DependencyInjection;
using Patterns.EventAggregation.Domain;
using Patterns.EventAggregation.Integration;
using Patterns.UnitOfWork;

public class InMemoryUnitOfWork : UnitOfWork
{
public int CommitCalls { get; private set; }
public int RollbackCalls { get; private set; }

public InMemoryUnitOfWork(IClock clock, ICurrentTHolder<IIdentity> identityHolder) : base(clock, identityHolder)
public InMemoryUnitOfWork(IClock clock, ICurrentTHolder<IIdentity> identityHolder,
IDomainEventAggregator eventAggregator, IEventBusScope eventBusScope)
: base(clock, identityHolder, eventAggregator, eventBusScope)
{ }

protected override void UpdateTrackingProperties(string userId, DateTime utcNow)
Expand Down
13 changes: 13 additions & 0 deletions src/Backend.Fx/Logging/DebugExceptionLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Backend.Fx.Logging
{
using System;
using System.Diagnostics;

public class DebugExceptionLogger : IExceptionLogger
{
public void LogException(Exception exception)
{
Debug.WriteLine(exception);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
namespace Backend.Fx.Patterns.EventAggregation.Domain
{
using System;
using System.Collections.Generic;
using Logging;

public class DomainEventAggregator : IDomainEventAggregator
{
private static readonly ILogger Logger = LogManager.Create<DomainEventAggregator>();
private readonly IDomainEventHandlerProvider domainEventHandlerProvider;
private readonly List<(string, string, Action)> handleActions = new List<(string, string, Action)>();

public DomainEventAggregator(IDomainEventHandlerProvider domainEventHandlerProvider)
{
Expand All @@ -22,14 +24,28 @@ public DomainEventAggregator(IDomainEventHandlerProvider domainEventHandlerProvi
public void PublishDomainEvent<TDomainEvent>(TDomainEvent domainEvent) where TDomainEvent : IDomainEvent
{
foreach (var injectedHandler in domainEventHandlerProvider.GetAllEventHandlers<TDomainEvent>())
{
(string, string, Action) handleAction = (
typeof(TDomainEvent).Name,
injectedHandler.GetType().Name,
() => injectedHandler.Handle(domainEvent));

handleActions.Add(handleAction);
Logger.Debug($"Invocation of {injectedHandler.GetType().Name} for domain event {typeof(TDomainEvent).Name} registered. It will be executed on completion of unit of work");
}
}

public void RaiseEvents()
{
foreach (var handleAction in handleActions)
{
try
{
injectedHandler.Handle(domainEvent);
handleAction.Item3.Invoke();
}
catch (Exception ex)
{
Logger.Error(ex, $"Handling of {typeof(TDomainEvent).Name} by {injectedHandler.GetType().Name} failed.");
Logger.Error(ex, $"Handling of {handleAction.Item1} by {handleAction.Item2} failed.");
throw;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
public interface IDomainEventAggregator
{
void PublishDomainEvent<TDomainEvent>(TDomainEvent domainEvent) where TDomainEvent : IDomainEvent;
void RaiseEvents();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ protected EventBus(IScopeManager scopeManager, IExceptionLogger exceptionLogger)
/// <inheritdoc />
public void Subscribe<THandler, TEvent>() where THandler : IIntegrationEventHandler<TEvent> where TEvent : IIntegrationEvent
{
string eventName = typeof(TEvent).FullName;
string eventName = typeof(TEvent).FullName ?? typeof(TEvent).Name;

Logger.Info($"Subscribing to {eventName}");
var handlerType = typeof(THandler);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace Backend.Fx.Patterns.EventAggregation.Integration
{
using System.Collections.Generic;
using System.Threading.Tasks;
using BuildingBlocks;

public interface IEventBusScope : IDomainService
{
void Publish(IIntegrationEvent integrationEvent);
Task RaiseEvents();
}

public class EventBusScope : IEventBusScope
{
private readonly List<IIntegrationEvent> integrationEvents = new List<IIntegrationEvent>();
private readonly IEventBus eventBus;

public EventBusScope(IEventBus eventBus)
{
this.eventBus = eventBus;
}

void IEventBusScope.Publish(IIntegrationEvent integrationEvent)
{
integrationEvents.Add(integrationEvent);
}

public async Task RaiseEvents()
{
foreach (var integrationEvent in integrationEvents)
{
await eventBus.Publish(integrationEvent);
}
}
}
}

18 changes: 14 additions & 4 deletions src/Backend.Fx/Patterns/UnitOfWork/IUnitOfWork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
using System.Security.Principal;
using DependencyInjection;
using Environment.DateAndTime;
using EventAggregation.Domain;
using EventAggregation.Integration;
using Extensions;
using Logging;

/// <summary>
Expand All @@ -22,13 +25,18 @@ public abstract class UnitOfWork : IUnitOfWork, ICanFlush
private static int index;
private readonly int instanceId = index++;
private readonly IClock clock;
private readonly IDomainEventAggregator eventAggregator;
private readonly IEventBusScope eventBusScope;
private bool? isCompleted;
private IDisposable lifetimeLogger;

protected UnitOfWork(IClock clock, ICurrentTHolder<IIdentity> identityHolder)
protected UnitOfWork(IClock clock, ICurrentTHolder<IIdentity> identityHolder,
IDomainEventAggregator eventAggregator, IEventBusScope eventBusScope)
{
this.clock = clock;
this.IdentityHolder = identityHolder;
this.eventAggregator = eventAggregator;
this.eventBusScope = eventBusScope;
IdentityHolder = identityHolder;
}

public ICurrentTHolder<IIdentity> IdentityHolder { get; }
Expand All @@ -38,7 +46,7 @@ public virtual void Flush()
Logger.Debug("Flushing unit of work #" + instanceId);
UpdateTrackingProperties(IdentityHolder.Current.Name, clock.UtcNow);
}

public virtual void Begin()
{
lifetimeLogger = Logger.DebugDuration($"Beginning unit of work #{instanceId}", $"Disposing unit of work #{instanceId}");
Expand All @@ -48,8 +56,10 @@ public virtual void Begin()
public void Complete()
{
Logger.Debug("Completing unit of work #" + instanceId);
UpdateTrackingProperties(IdentityHolder.Current.Name, clock.UtcNow);
Flush();
eventAggregator.RaiseEvents();
Commit();
AsyncHelper.RunSync(()=>eventBusScope.RaiseEvents());
isCompleted = true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace Backend.Fx.Bootstrapping.Tests
using FakeItEasy;
using Modules;
using Patterns.DependencyInjection;
using Patterns.EventAggregation.Integration;
using Patterns.IdGeneration;
using SimpleInjector;
using Testing.InMemoryPersistence;
Expand All @@ -22,15 +23,16 @@ public class TheSimpleInjectorCompositionRoot : IDisposable
{
private readonly SimpleInjectorCompositionRoot sut;

private class AnDomainModule : DomainModule
private class ADomainModule : DomainModule
{
public AnDomainModule(params Assembly[] domainAssemblies) : base(domainAssemblies)
public ADomainModule(params Assembly[] domainAssemblies) : base(domainAssemblies)
{ }

protected override void Register(Container container, ScopedLifestyle scopedLifestyle)
{
base.Register(container, scopedLifestyle);
container.Register<IClock, FrozenClock>();
container.RegisterInstance(A.Fake<IEventBus>());
}
}

Expand All @@ -45,7 +47,7 @@ public TheSimpleInjectorCompositionRoot()
sut = new SimpleInjectorCompositionRoot();
var domainAssembly = typeof(AnAggregate).GetTypeInfo().Assembly;
sut.RegisterModules(
new AnDomainModule(domainAssembly),
new ADomainModule(domainAssembly),
new InMemoryIdGeneratorsModule(),
new InMemoryPersistenceModule(domainAssembly));

Expand Down
10 changes: 7 additions & 3 deletions tests/Backend.Fx.Bootstrapping.Tests/TheTenantManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
using Environment.Authentication;
using Environment.DateAndTime;
using Environment.MultiTenancy;
using FakeItEasy;
using Modules;
using Patterns.DependencyInjection;
using Patterns.EventAggregation.Integration;
using SimpleInjector;
using Testing.InMemoryPersistence;
using Xunit;
Expand All @@ -18,24 +20,26 @@ public class TheTenantManager
private readonly ITenantManager sut;
private readonly IScopeManager scopeManager;

private class AnDomainModule : DomainModule
private class ADomainModule : DomainModule
{
public AnDomainModule(params Assembly[] domainAssemblies) : base(domainAssemblies)
public ADomainModule(params Assembly[] domainAssemblies) : base(domainAssemblies)
{ }

protected override void Register(Container container, ScopedLifestyle scopedLifestyle)
{
base.Register(container, scopedLifestyle);
container.Register<IClock, FrozenClock>();
container.RegisterInstance(A.Fake<IEventBus>());
}
}

public TheTenantManager()
{
var compositionRoot = new SimpleInjectorCompositionRoot();
var domainAssembly = typeof(AnAggregate).GetTypeInfo().Assembly;
var backendfxAssembly = typeof(Entity).GetTypeInfo().Assembly;
compositionRoot.RegisterModules(
new AnDomainModule(domainAssembly),
new ADomainModule(domainAssembly, backendfxAssembly),
new InMemoryIdGeneratorsModule(),
new InMemoryPersistenceModule(domainAssembly));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
using Environment.Authentication;
using Environment.DateAndTime;
using Environment.MultiTenancy;
using FakeItEasy;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Patterns.EventAggregation.Integration;
using Patterns.UnitOfWork;
using SimpleInjector;
using Xunit;
Expand All @@ -26,15 +28,16 @@ public APersistenceModule(DbContextOptions<TestDbContext> dbContextOptions)
{ }
}

private class AnDomainModule : DomainModule
private class ADomainModule : DomainModule
{
public AnDomainModule(params Assembly[] domainAssemblies) : base(domainAssemblies)
public ADomainModule(params Assembly[] domainAssemblies) : base(domainAssemblies)
{ }

protected override void Register(Container container, ScopedLifestyle scopedLifestyle)
{
base.Register(container, scopedLifestyle);
container.Register<IClock, FrozenClock>();
container.RegisterInstance(A.Fake<IEventBus>());
}
}

Expand All @@ -46,7 +49,7 @@ public TheEfCorePersistenceModule()

sut = new SimpleInjectorCompositionRoot();
sut.RegisterModules(
new AnDomainModule(typeof(Blog).GetTypeInfo().Assembly),
new ADomainModule(typeof(Blog).GetTypeInfo().Assembly),
new APersistenceModule(dbContextOptions));
sut.Verify();
}
Expand Down

0 comments on commit 7802b55

Please sign in to comment.