【发布时间】:2021-09-16 15:45:31
【问题描述】:
我有一个 .NET Core 3.1 通用主机,它使用中介者模式来处理消息:
public interface IMessageDispatcher {
Task Dispatch<TMessage>(TMessage message) where TMessage : Message;
}
public class MessageDispatcher : IMessageDispatcher {
private readonly IServiceProvider _container;
public MessageDispatcher(IServiceProvider container) {
_container = container;
}
public async Task Dispatch<TMessage>(TMessage message) {
var handler = (IMessageHandler<TMessage>) _container.GetService(typeof(IMessageHandler<TMessage>));
await handler.Handle(message);
}
}
public interface IMessageHandler<TMessage> where TMessage : Message {
Task Handle(TMessage message);
}
public class MyMessageHandler : IMessageHandler<MyMessage> {
public Task Handle(MyMessage message) {
// do stuff
}
}
消息处理程序在 Autofac 中注册,如下所示:
private static void AutoRegisterMessageHandlers(ContainerBuilder builder, Assembly domainAssembly) {
builder
.RegisterAssemblyTypes(domainAssembly)
.AsClosedTypesOf(typeof(IMessageHandler<>));
}
如果我按原样运行上述程序,那么当我调用Handle 方法时,对_container.GetService 的调用会返回一个带有明显NullReferenceException 的空值;但是,如果我在调用 Handle 之前设置断点,并在 Visual Studio 的即时窗口中运行以下命令:
_container.GetService(typeof(IMessageHandler<MyMessage>));
然后返回预期的消息处理程序,这表明消息处理程序已正确注册,只是当我尝试使用泛型类型解析消息处理程序时
_container.GetService(typeof(IMessageHandler<TMessage>));
事情出错了。我做错了什么吗?
更新
根据接受的答案,我从消息队列接收消息并反序列化它们,所以我没有具体的类型:
var message = Deserialiser.Deserialise<Message>(rawXmlFromQueue);
await Dispatch(message);
由于message 没有具体类型,Autofac 没有足够的信息来定位注册的消息处理程序,并返回null。然后解决方案是将消息转换为dynamic,并通过 C# 类型系统的魔力,足以将泛型类型转换为其具体实现:
var message = Deserialiser.Deserialise<Message>(rawXmlFromQueue);
await Dispatch((dynamic) message);
【问题讨论】:
-
使用
Service Locators是一种反模式。见docs -
如果你正在做例如它是非常有效的。 CQRS 并且您不想将十几个命令/查询处理程序注入您的控制器;只要您知道通过额外的间接步骤让自己陷入困境。
标签: .net-core dependency-injection autofac