使用Autofac集成Mediatr

3
我正在使用.NET Core(注意:不是Web环境)。我需要集成MediatR和Autofac。 Wiki提供了指南和StructureMap示例。此外,还有一个Autofac示例,我已经简化了它。没有提到生存期范围,但在另一个项目中,我找到了有用的注释并将它们转换为Autofac。有很多不同的代码示例。
到目前为止,我已经做到了这些:
// enables contravariant Resolve() for interfaces with single contravariant ("in") arg
builder
  .RegisterSource(new ContravariantRegistrationSource());

// mediator itself
builder
  .RegisterType<Mediator>()
  .As<IMediator>()
  .InstancePerLifetimeScope();

// request handlers
builder
  .Register<SingleInstanceFactory>(context => {
    var ctx = context.Resolve<IComponentContext>();   // unsure why needed, but it works
    return t => { object o; return ctx.TryResolve(t, out o) ? o : null; };
  })
  .InstancePerLifetimeScope();

// notification handlers
builder
  .Register<MultiInstanceFactory>(context => {
    var ctx = context.Resolve<IComponentContext>();   // unsure why needed, but it works
    return t => (IEnumerable<object>)ctx.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
  })
  .InstancePerLifetimeScope();

然后注册我的自定义内容:

  • 处理程序为瞬态,即InstancePerDependency()
  • 前/后处理器为每个请求,即InstancePerLifetimeScope()
  • 行为为瞬态,即InstancePerDependency()

例如:

builder.RegisterType<EditCommandHandler>().AsImplementedInterfaces().InstancePerDependency();

然而,在我看到的大多数代码示例中,特别是对于StructureMap,还有许多其他的注册(例如:IRequestHandler<,>IRequestHandler<>IAsyncRequestHandler<,>IAsyncRequestHandler<>ICancellableAsyncRequestHandler<,>ICancellableAsyncRequestHandler<>INotificationHandler<>IAsyncNotificationHandler<>ICancellableAsyncNotificationHandler<>),而且ASP.NET Core容器的集成也非常复杂。我没有做过类似的事情。
如果您已经在生产中使用此功能,请问您的配置与我的相比如何?谢谢!
2个回答

10

简述:

我认为你的注册是没有问题的。


详细说明 - 即逐一解答你的问题

你目前的注册情况

MediatR需要你注册SingleInstanceFactoryMultiInstanceFactory,因为它们是Mediator类所需的。

然后你需要注册你的handlers和behaviors,你已经做到了,所以没什么问题。

我唯一可以提出的意见是,从你的示例中看来,似乎你是一个一个地注册你的handlers。虽然这样做没有问题,而且这是最重要的,但这意味着每当你添加一个新的请求/处理程序对时,你都需要在Autofac容器中注册handler。

我建议使用基于约定的注册方式,这种方式Autofac支持开箱即用。假设你的应用程序使用异步请求处理程序和异步通知处理程序,你可以编写如下内容:

var openHandlersTypes = new[] { typeof(IAsyncRequestHandler<,>), typeof(IAsyncNotificationHandler<,>) };
foreach (var openHandlerType in openHandlersTypes)
{
    builder
        .RegisterAssemblyTypes(ThisAssembly)
        .AsClosedTypesOf(openHandlerType)
        .InstancePerDependency();
}

Autofac将扫描ThisAssembly并注册所有关闭openHandlersTypes中的开放泛型类型的类型。

关于所有处理程序类型

您可能担心没有为MediatR公开的所有处理程序类型进行注册。那没关系。如果您不使用可取消的处理程序,则无需注册它们。您可以选择实现哪种类型的处理程序。当您向MediatR发送请求时,它将使用提供的MultiInstanceFactory来确定您的处理程序是同步处理程序、异步处理程序还是可取消的异步处理程序。

另请注意,所有请求处理程序类型都有两种形式。只有一种泛型类型(例如IRequestHandler<TRequest>)的类型不返回值,而具有两个泛型参数(例如IRequestHandler<TRequest, TResponse>)的类型返回一个值。但是,您的注册将由您是否使用它们来驱动。

ASP.NET Core集成部分

您使用Autofac,所以不用担心。该包旨在帮助您为ASP.NET Core DI容器注册处理程序。它确实很复杂,因为它会扫描程序集以找到代码中的所有处理程序并为其注册。但再次强调,因为您使用另一个容器,所以无需担心。


1
像往常一样,Mickaël的回答非常棒,谢谢!我只是需要确认一下,是否有人在生产中使用Autofac,因为Jimmy似乎使用StructureMap,所以所有的示例都是针对它的。 - grokky
顺便问一下,你知道为什么单/多委托注册需要 var ctx = context.Resolve<IComponentContext>() 吗?似乎这是不必要的,因为 context 解析到相同的内容,但如果你将其排除,则无法解析。 - grokky
我知道你必须这样做,因为在你的注册中有一个lambda表达式(t => { object o; return ctx.TryResolve(t, out o) ? o : null; };),而在Register方法中提供的原始IComponentContext实例无法被捕获。虽然它解析到相同的类型,但我认为它不会解析到相同的实例。但是,不幸的是,我无法提供更详细的解释。 - Mickaël Derriey
我也是这么认为的(这是一个闭包问题),所以我记录了它们的.GetHashCode(),结果它们是相同的。所以似乎这是不必要的,但是如果你删除它,它会失败。很奇怪,但我并不在意,因为它可以工作。 - grokky
在我的代码中,我没有看到任何中介服务的范围,例如命令和处理程序。如果我只有AsClosedTypesOf和AsImplementedInterfaces,我该如何检查创建的范围? - kuldeep

6

对于任何看到这篇文章的人:我之前创建了一个NuGet包,作为AutoFac的ContainerBuilder的扩展。

我知道有一个基于Microsoft-DI的扩展,但我的扩展与AutoFac完全集成,并且在ASP.NET Core中也可以完美地工作。

您只需要在容器构建器上调用扩展方法并传入一个或多个程序集即可。

builder.AddMediatR(typeof(Startup).Assembly);

编辑于2023年3月22日

nuget包的注册方式已经更改,请查看README


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接