我正忙着在最近的一个项目中实现事件。
我已经验证了structmap正在正确扫描汇编和添加EventHandlers
Scan(cfg =>
{
cfg.TheCallingAssembly();
cfg.IncludeNamespace("ABC.EventHandler");
cfg.ConnectImplementationsToTypesClosing(typeof(IHandle<>));
});
public class StructureMapEventDispatcher : IEventDispatcher
{
public void Dispatch<TEvent>(TEvent eventToDispatch) where TEvent : IDomainEvent
{
foreach (var handler in ObjectFactory.GetAllInstances<IHandle<TEvent>>())
{
handler.Handle(eventToDispatch);
}
}
}
之前我曾经从域中触发事件。像Dispatcher.RaiseEvent(new [domainEvent class](x,y,z));
事件将被激发。我不得不改变我现在在集合中收集事件的设计
_domainEvents = new Collection<IDomainEvent>();
然后在将域保存到存储库
后将其提升 public static void Raise(ICollection<IDomainEvent> domainEvents)
{
foreach (var domainEvent in domainEvents)
{
DomainEventDispatcher.Raise(domainEvent);
}
}
但现在
ObjectFactory.GetAllInstances<IHandle<TEvent>>()
返回0个处理程序数
如果我注意
ObjectFactory.GetAllInstances<IHandle<DomainEventClass>>()
它正确返回处理程序集合(目前我有2个,它显示2个计数)
...我假设这与从IDomainEvent
类型而不是实际类型引发的事件有关,这使得structmap很难解决它。
我该如何解决这个问题?
此致
The Mar
-
编辑1:
我已经确定struturemap容器包含从程序集扫描的所有事件处理程序。
编辑2
我不知道如何让这个问题引起更多关注。我正在为获得所需结果的解决方案添加赏金。如果问题不明确,请询问。
基本上我希望 ObjectFactory.GetAllInstances<IHandle<TEvent>>()
返回TEvent
TEvent
类型为IDomainEvent
的处理程序。要引发的事件存储在IDomainEvent
的集合中,并在保存域(从服务层)之后引发。
我认为应该有一些方法可以让结构图知道引发为IDomainEvent
的事件实际上是 DomainEvent
var eventsToRaise = dealer.EventsToRaise(); 从调试窗口添加信息:
在调度程序窗口中引发事件后
编辑3: 尽管eventToRaise显示为“DealerName Changed”和“DealerCommunicationChanged” typeof(TEvent)将Type指定为Domain.IDomainEvent
我猜是否有可能能够投射到正确的类型(从VS观察窗口获取信息),问题可能得到解决
-----结果---
两种方法都有效。我把两个接近我的团队的其他两个成员,我们觉得没有反思的解决方案被选为正确答案。
今天我们将通过更改实施进行测试,看看解决方案中是否存在此解决方案的任何问题。
我推荐了基于反射的解决方案,因为它也是正确答案。
答案 0 :(得分:4)
正如您所说,问题在于您要求IHandle<IDomainEvent>
的所有实例的结构图,并且它没有这些实例,结构图具有针对具体事件的处理程序。您需要使用事件的实际类型构造类型,然后询问该事件的所有处理程序:
Type genericHandler = typeof(IHandle<>);
Type[] typeArgs = { eventToDispatch.GetType() };
Type neededHandler = genericHandler.MakeGenericType(typeArgs);
var handlers = ObjectFactory.GetAllInstances(neededHandler);
问题是你最终得到一个IList对象,你需要将它们转换为正确的处理程序类型,这有点棘手......一个可能的解决方案是使用反射来调用{{1}方法:
Handle()
答案 1 :(得分:1)
我建议使用记录来保存类型信息,而不是基于反射的方法。像这样:
interface IEventRecord
{
void Dispatch(IEventDispatcher dispatcher);
}
public class EventRecord<TEvent> : IEventRecord where TEvent : IDomainEvent
{
TEvent theEvent;
public EventRecord(TEvent theEvent)
{
this.theEvent = theEvent;
}
public void Dispatch(IEventDispatcher dispatcher)
{
dispatcher.Dispatch(theEvent);
}
}
如果您发现实例化事件记录很麻烦,帮助程序可以推断出类型参数,如下所示:
public static EventRecord<TEvent> CreateEventRecord<TEvent>(TEvent theEvent) where TEvent : IDomainEvent
{
return new EventRecord<TEvent>(theEvent);
}
这将允许您实例化事件记录,如下所示:
var record = CreateEventRecord(myDomainEvent);
然后,不要抓住IDomainEvent
的集合,而是抓住一个IEventRecords
的集合,其中包含必要的类型数据以提升自己:
foreach (var eventRecord in Records)
{
eventRecord.Dispatch(myDispatcher);
}