使用ASP.NET Core DI的MediatR

39

我正在尝试新的ASP.NET Core,并正在创建一个API,我希望从JavaScript前端调用它。

我想使用中介者模式来减少耦合,并且我找到了Jimmy Bogard的库MediatR

我的问题在于如何使用内置DI进行连接,我已经尝试查看示例,但是无法理解它如何绑定到启动类中的ConfigureServices方法。

有没有人有任何见解?

更新:我让它工作了,来自我的ConfigureService方法:

services.AddScoped<SingleInstanceFactory>(p => t => p.GetRequiredService(t));

services.Scan(scan => scan
        .FromAssembliesOf(typeof(IMediator), typeof(MyHandler.Handler))
        .AddClasses()
        .AsImplementedInterfaces());

1
看起来对我来说很简单,但是对于程序集扫描,您需要使用这个Scrutor包(ASP.NET Core的DI不带程序集扫描,并且没有计划进行发布) - Tseng
你会如何将它添加到ConfigureService方法中呢? services.AddTransient(typeof (IMediator), BuildMediator().GetType()); - Nyegaard
1
你不想以那种方式进行注册,Transient 意味着每次解析依赖项时都会创建它。services.AddScoped<SingleInstanceFactory>(p => t => p.GetRequiredService(t));services.AddScoped<MultiInstanceFactory>(p => t => p.GetRequiredServices(t)); 是工厂方法,注入到中介器中并解析通知(多)或请求(单)。 - Tseng
1
IMediator 本身可以注册为 services.AddScoped<IMediator, Mediator>() ,因为它具有公共构造函数,而委托在前一步中已注册。在示例中,最后一个步骤是通过 Scrutor 扫描自动执行的。 - Tseng
@Tseng,我的答案是否与您的相符? - Nyegaard
6个回答

75

针对最新的 MediatR 版本 12.x,发布于2023年2月:

从版本12开始,Mediatr提供了直接在Mediatr命名空间中使用Microsoft依赖注入框架注册处理程序的支持,因此可以通过在服务集合上调用AddMediatR来实现。

services.AddMediatR(cfg =>
     cfg.RegisterServicesFromAssembly(typeof(Ping).Assembly));

Ping 是一种类型,包含在应该扫描以注册处理程序等的程序集中。

注意:以前版本的 MediatR 中创建的支持此注册的其他 NuGet 包(如下所述)不再需要;有关此更改和其他重大更改的详细信息,请参见 GitHub 上的 迁移指南

对于早期的 Mediatr 版本,包括 11.x:

2016 年 7 月,MediatR 的作者 Jimmy Bogard 发布了一个包,用于将 MediatR 和处理程序与 ASP.Net Core DI 服务(实际上是接口 IServiceCollection,实现在 Microsoft.Extensions.DependencyInjection 中,并不限于仅在 ASP.Net Core 中使用)注册。

MediatR.Extensions.Microsoft.DependencyInjection

GitHub项目链接

NuGet包信息链接

介绍该包及其功能的博客文章可以在这里找到。

以下是从(非常简短的)博客文章中直接复制的示例注册:

public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc();

  services.AddMediatR(typeof(Startup));
}

这个包执行几个功能,以使MediatR能够正常工作,其中包括对处理程序进行必要的程序集扫描:

您可以传递处理程序所在的程序集,也可以传递来自包含这些处理程序的程序集的Type对象。扩展将向您的服务添加IMediator接口、所有处理程序和正确的委托工厂以加载处理程序。

注意:从Mediatr版本12开始,不再需要此软件包。

对于所有版本

一旦使用上述描述的相关方法指定了依赖项注册,则在控制器中,您只需使用IMediator依赖项即可:

public class HomeController : Controller
{
  private readonly IMediator _mediator;

  public HomeController(IMediator mediator)
  {
    _mediator = mediator;
  }
  public IActionResult Index()
  {
    var pong = _mediator.Send(new Ping {Value = "Ping"});
    return View(pong);
  }
}

5
这应该是正确的答案。它不仅更加优雅简洁,而且这正是 Mediatr 的创建者推荐的方法。 - Reydel Leon
2
看起来从 MediatR 的 v12 开始,MediatR.Extensions.Microsoft.DependencyInjection 已经被弃用了。 - Giedrius
1
@Giedrius 我已经更新了我的答案,以使其适应MediatR版本12中包的弃用。 - dmcquiggin

5

有一个很好的教程,来自https://dotnetcoretutorials.com/。这是正确安装和配置MediatR的示例代码。

安装MediatR

首先,我们需要安装MediatR nuget包。因此,请从您的程序包管理器控制台运行以下命令:

Install-Package MediatR

我们还需要安装一个包,使我们能够充分利用.NET Core内置的IOC容器(稍后我们将看到更多)。因此,也请安装以下包:

Install-Package MediatR.Extensions.Microsoft.DependencyInjection

最后,我们打开startup.cs文件。在ConfigureServices方法中,我们需要添加调用以注册所有MediatR依赖项的内容。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMediatR(Assembly.GetExecutingAssembly());
    //Other injected services. 
}

这是链接:https://dotnetcoretutorials.com/2019/04/30/the-mediator-pattern-part-3-mediatr-library/。希望对你有所帮助。

4
我搞定了,这是我的代码:
public void ConfigureServices(IServiceCollection services)
{
      services.AddScoped<SingleInstanceFactory>(p => t => p.GetRequiredService(t));
      services.AddScoped<MultiInstanceFactory>(p => t => p.GetRequiredServices(t));
      services.Scan(scan => scan
              .FromAssembliesOf(typeof(IMediator), typeof(MyHandlerOne.Handler))
              .FromAssembliesOf(typeof(IMediator), typeof(MyHandlerTwo.Handler))
             .AddClasses()
             .AsImplementedInterfaces());
}

我有一个实现了GetRequiredService方法的类,MultiInstanceFactory需要使用它:

public static class GetServices
{
    public static IEnumerable<object> GetRequiredServices(this IServiceProvider provider, Type serviceType)
    {
        return (IEnumerable<object>)provider.GetRequiredService(typeof(IEnumerable<>).MakeGenericType(serviceType));
    }
}

4
根据MediatR文档,要注册MediatR服务和所有处理程序,您应该以以下方式使用AddMediatR方法:
public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc();

  services.AddMediatR(typeof(Startup));
}

这很容易,也很方便,但如果你想替换其中一个处理程序怎么办?那么你应该在你的.cs文件中找到旧的处理程序,并从中删除接口,这样在多个实现中ID就不会产生冲突。

为了避免这种情况,我的建议是手动注册每个处理程序。

     public void ConfigureServices(IServiceCollection services)
    {
      services.AddMvc();
    
      services.AddMediatR(typeof(Mediator)); //registering MediatR and all required dependencies
      //registering handlers
      services.AddScoped<IRequestHandler<CreateProductCommand, int>,CreateProductCommandHandler>(); 
      services.AddScoped<IRequestHandler<DeleteProductCommand, int>,DeleteProductCommandHandler>();     

    }

这个解决方案允许您为同一命令拥有多个处理程序实现,并控制使用哪个实现


0

我创建了一个ASP.NET Core RC2的DI助手,您可以将其添加到启动项中。它提供基本的约定映射,因此如果您有一个类似于以下内容的类:

MyClass : IMyClass

它将在IOC容器中映射IMyClass,从而使其可供注入。

我还添加了MediatR的映射。

要使用它,只需将该类添加到您的项目中,然后在startup.cs类中将所需的行添加到ConfigureServices()方法中:

public void ConfigureServices(IServiceCollection services)
{
    //Other Code here......

    var ioc = new PearIoc(services);

    //ioc.AddTransient<IEmailSender, AuthMessageSender>();
    //ioc.AddTransient<ISmsSender, AuthMessageSender>();

    ioc.WithStandardConvention();
    ioc.WithMediatR();
    ioc.RunConfigurations();
}

我只是为了方便添加了AddTransient()方法(你也可以使用services.AddTransient()),但它还公开了IServiceCollection,以防需要进行更多操作。

你也可以像我一样使用.WithMediatR()扩展来扩展它,并编写自己的自定义映射。


0

注册所有命令的另一种方式

public void ConfigureServices(IServiceCollection services)
{
    services.AddMediatR(Assembly.GetAssembly(typeof(YouClass)));
}

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