我应该如何处理MediatR NotificationHandler的SimpleInjector生活方式?

时间:2019-05-03 09:10:03

标签: asp.net ioc-container simple-injector mediatr

我有一个使用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的口头禅,但除此之外,我想知道是否还有更好的方法...

1 个答案:

答案 0 :(得分:1)

您基本上有三个选择:

  • 定义您自己的抽象(如您目前所做的那样)
  • 将默认的IMediator实现替换为适用范围的实现
  • 用适用范围界定的类装饰默认的IMediator实现

尽管根据Dependency Inversion Principle定义自己的应用程序抽象通常应该具有您的喜好,但这三个选项同样都不错。