I am working on a .NET core MVC web app.
I have a domain object method that perform some business logic and return a result object containing variables passed to view models. The result object has some variables that are from an event handler if a target event happened.
I am wondering how to access variables from the event handler with DI container like Simple Injector in sophisticated way.
This is a simplified version of snippet of what I am doing.
Class DomainA (has domain logic)
private DomainB _domainBObj;
/**************
* constructor
***************/
public DomainA(){
_domainBObj = new DomainB();
}
/********************************
* called in Application Service
********************************/
public MyEventResult doSth(string arg){
/************************************************************************
* It did the job
* but I am thinking about if there is any approach
* that DomainA can get access to the event result if the event happened
* without getting the event handler here using DI container in C#
*************************************************************************/
var eventHandler = DIContainer.INSTANCE.getInstance<MyEventHandler>();
_domainBObj.doSth(arg);
return doSthBasedOnEventResult(eventHandler.Result);
}
public MyEventResult doSthBasedOnEventResult(EventResult eventResult){
var ret = new MyEventResult();
// setting variables of MyEventResult
return ret;
}
Class DomainB (Wrapper of 3rd party library object)
/**************
* constructor
***************/
public DomainB(){
// configuration of the 3rd party library object
some3rdPartyLibraryObj.OnSomeEvent(
var event = new MyEvent(); // wrapper of some variables
var eventBus = DIContainer.INSTANCE.getInstance<MyEventBus>();
eventBus.Dispatch(event);
)
}
/***************************
* called in DomainA doSth()
***************************/
public void doSth(string arg){
some3rdPartyLibraryObj.doSth(arg);
}
Event Bus (Singleton scoped)
public interface IEventBus
{
void Dispatch<TEvent>(TEvent @event) where TEvent : IEvent;
}
public class MyEventBus : IEventBus
{
public void Dispatch<TEvent>(TEvent @event) where TEvent : IEvent {
if (@event == null) throw new ArgumentNullException("event");
var handlerType = typeof(IEventHandler<>).MakeGenericType(@event.GetType());
dynamic handlers = DIContainer.INSTANCE.GetAllInstances<IEventHandler<TEvent>>();
foreach (var handler in handlers) {
handler.Handle(@event);
}
}
Ref: Implementing Domain Event Handler pattern in C# with Simple Injector
Event Handler (Request scoped)
public interface IEventHandler<TEvent>
{
void Handle(TEvent @event);
}
public class MyEventHandler : IEventHandler<MyEvent>
{
public EventResult Result { get; private set; }
public void Handle(MyEvent @event) {
var result = new EventResult();
// setting variables of EventResult
Result = result;
}
}
It's hard to answer your question, because there are a lot parts of your chosen design that are unclear. There also seems some inconsistency in your examples. For instance, you show an implementation of a handler that is using a non-generic IEventHandler
, but at the same time resolve a generic IEventHandler<TEvent>
inside the MyEventBus
.
The only thing I can do at this point is to provide some comments and suggestions. Here goes:
IEventBus
to your Domain Methods seems reasonable, because you want to decouple down domain objects from the event handlers.IEventHandler<T>
over the a non-generic IEventHandler
(with a generic Handle<T>
method), because this simplifies registration and use of those handlers enormously, because you make maximal use of the .NET type system.