我有一个使用MediatR和SimpleInjector的ASP.NET Web API。
它们是这样注册的:
_container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
_container.Options.DefaultLifestyle = Lifestyle.Scoped;
_container.Collection.Register(typeof(INotificationHandler<>), typesFound);
我可以通过Controllers
发布事件:
[HttpGet]
public ActionResult<...> Get()
{
_mediator.Publish(new SomeEvent());
}
那很好用!
一个新的要求是侦听来自外部系统(Tibco)的更新。发生更新时,该通知通过另一个线程的C#事件进入。在C#事件处理程序中,我想使用MediatR来Publish
通知:
void callbackFromTibco(object listener, MessageReceivedEventArgs @args)
{
_mediatr.Publish(new SomeEvent();
}
此时SimpleInjector会引发异常:
SomeEventHandler is registered as 'Async Scoped' lifestyle, but the instance is requested outside the context of an active (Async Scoped) scope
。
这是因为调用堆栈源自另一个线程,而在Controller
中,控制器本身由SimpleInjector定义了范围,因此MediatR在相同的范围内创建了处理程序。
是否可以做一些事情以便我可以注册在两种情况下都可以使用的事件处理程序?
我通过创建一个IPublishEvents
接口和一个PublishEvents
类来解决这个问题,其中PublishEvents
类看起来像:
public PublishEvents(Container container, IMediator mediator)
{
_container = container;
_mediator = mediator;
}
public Task Publish(object notification, CancellationToken cancellationToken = default)
{
using (AsyncScopedLifestyle.BeginScope(_container))
{
return _mediator.Publish(notification, cancellationToken);
}
}
抽象是正确的方法吗?它当然符合Don't Marry the Framework
的口头禅,但除此之外,我想知道是否还有更好的方法...
答案 0 :(得分:1)
您基本上有三个选择:
IMediator
实现替换为适用范围的实现IMediator
实现尽管根据Dependency Inversion Principle定义自己的应用程序抽象通常应该具有您的喜好,但这三个选项同样都不错。