我应该如何处理 MediatR NotificationHandlers 的简单注入器生活方式?

How should I handle Simple Injector Lifestyles for MediatR NotificationHandlers?

我有一个 ASP.NET Web API 使用 MediatR 和 SimpleInjector。

他们是这样注册的:

_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 class 来解决这个问题,其中 PublishEvents class 看起来像:

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

你基本上有三个选择:

  • 定义您自己的抽象(正如您目前所做的那样)
  • 将默认的 IMediator 实现替换为应用范围的实现
  • 用应用范围
  • 的class修饰默认IMediator实现

所有三个选项都同样好,尽管定义您自己的应用程序抽象通常应该有您的偏好,因为这符合 Dependency Inversion Principle