当实体在不同的项目中时,为啥 Mediator 不解析方法?
Posted
技术标签:
【中文标题】当实体在不同的项目中时,为啥 Mediator 不解析方法?【英文标题】:Why doesn't Mediatr resolve method when entites are in different projects?当实体在不同的项目中时,为什么 Mediator 不解析方法? 【发布时间】:2019-08-15 15:53:49 【问题描述】:我有一个简单的项目来尝试 Mediatr 问题。当我的处理程序的具体类在我的 API 的 SAME 项目中时,它可以工作。但是,当我将该处理程序类放入另一个项目(并且 API 引用该项目的 c)时,它不会解析注册表。
我收到此错误:
找不到请求类型的处理程序 MediatR.IRequestHandler`2[MyBiz.GetTokenModelRequest,MyBiz.TokenModel]。 向容器注册您的处理程序。查看 GitHub 中的示例 例如。
我的项目中有这个结构,并且还显示了它在哪里工作,哪里不工作:
为了更清楚,这里是代码:
MyApi2 -> Startup.cs:
namespace MyApi2
public class Startup
public Startup(IConfiguration configuration)
Configuration = configuration;
public IConfiguration Configuration get;
public void ConfigureServices(IServiceCollection services)
services.AddMvc();
services.AddMediatR();
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
app.UseMvc();
MyApi2 -> ValuesController:
namespace MyApi2.Controllers
[Route("api/[controller]")]
public class ValuesController : Controller
private readonly IMediator _mediator;
public ValuesController(IMediator mediator)
_mediator = mediator;
[HttpGet]
public async Task<IEnumerable<string>> Get()
try
var rr = await _mediator.Send(new GetTokenModelRequest());
catch (Exception ex)
throw;
return new string[] "value1", "value2" ;
MyBiz -> GetTokenModelRequest
namespace MyBiz
public class GetTokenModelRequest : LoginModel, IRequest<TokenModel>
public class LoginModel
public string Username get; set;
public string Password get; set;
public class TokenModel
#region Properties
public Guid Id get; set;
public string Username get; set;
public string Token get; set;
public DateTime Expiration get; set;
#endregion
MyInftra -> TokenQueryHandler
namespace MyInfra
public class TokenQueryHandler : ITokenQueryHandler
public Task<TokenModel> Handle(GetTokenModelRequest request, CancellationToken cancellationToken)
return Task.FromResult(new TokenModel());
所以,如果我 MOVE TokenQueryHandler
从 MyInfra
到 MyApi
它可以工作,但我应该可以把它作为参考项目,对吧?
【问题讨论】:
如何在启动文件中将 Mediatr 添加到 DI? 在 Startup.cs 我在ConfigureServices(IServiceCollection services)
中使用 services.AddMediatR();
【参考方案1】:
更新
从MediatR.Extensions.Microsoft.DependencyInjection 包的7.0.0 版本开始,在调用AddMediatR()
扩展方法时,不再自动扫描AppDomain
以查找包含要注册的MediatR 基类型的加载程序集。
实际上,该函数的无参数重载已经完全从包中移除,需要用户传入程序集(或类型)来代替扫描。
这使得在每个引用的程序集中注册 MediatR 基本类型(IRequestHandler
、INotificationHandler
、IRequestPreProcessor
和 IRequestPostProcessor
),由用户明确控制和酌情决定。
因此,如果我们想在 MediatR 容器中注册的假想程序集 Assembly1
和 Assembly2
中有一些 MediatR 基类型:
而不是这样做:services.AddMediatR();
您需要这样做:services.AddMediatR(typeof(Assembly1), typeof(Assembly2));
这使得我的原始答案(如下)对于使用此软件包版本 7(可能更高版本)的任何人来说都是多余的,但我会将其保留在这里以供那些使用旧版本的人使用。
原答案
注意:以下答案仅与 MediatR.Extensions.Microsoft.DependencyInjection 包的
对startup.cs
文件中的AddMediatR()
扩展方法的调用会做很多事情来初始化MediatR:
IRequestHandler
、INotificationHandler
、IRequestPreProcessor
和 IRequestPostProcessor
)继承的每个类
它将这些 MediatR 基类型中的每一个注册到容器中以供以后使用
考虑到以上几点,了解 .NET CLR 如何加载引用的程序集非常重要。 Rick Strahl 有一个非常有趣的blog post 进行了详细介绍,但我将在此引用一段话来总结:
简而言之,引用的程序集不会立即加载 - 它们会根据需要即时加载。因此,无论您在***项目中是否有程序集引用,或者依赖程序集程序集通常会根据需要加载,除非用户代码显式加载。依赖程序集也是如此。
为什么知道这一点很重要?
好吧,在您的MyApi2
项目中,您引用了MyInfra
项目,但您实际上并没有以任何方式使用它。这意味着程序集不会被 CLR 加载,因此 MediatR 将无法在应用程序域当前加载的程序集中找到它。因此,您的 IRequestHandler
将不会被注册(也不会在该项目中注册任何其他 MediatR 基类型)。
此问题的解决方案是确保在调用AddMediatR()
之前加载包含您希望注册到 MediatR 容器的类型的程序集。
您可以执行以下任一操作:
Manually load您引用的程序集 从MyApi2
项目中引用位于 MyInfra
项目中的类型/函数
后一个选项是最典型的,因为您将通常在您想要调用的引用程序集中拥有一些功能(而不是仅仅拥有一个包含类型的程序集)。
无论您选择哪个选项,请确保在添加 MediatR 之前执行此操作。否则你会遇到同样的问题。
【讨论】:
以上是关于当实体在不同的项目中时,为啥 Mediator 不解析方法?的主要内容,如果未能解决你的问题,请参考以下文章
当 Recyclerview 在 NestedScrollview 中时,如何避免绑定所有项目?
当元素存在于数组中时,为啥 index = -1? [复制]
Javascript:当元素存在于数组中时,为啥 indexOf 函数返回 -1?