Autofac 不解析具有通用类型的服务
Autofac not resolving service with generic type
我有一个使用中介模式处理消息的 .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
方法;但是,如果我在调用 Handle
和 运行 之前放置一个断点,则 Visual Studio 中的立即 window 中的以下内容:
_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);
您无法解析开放式泛型。
你提到的问题是你不能这样做:
container.GetService(typeof(ICommandHandler<TMessage>))
但是 DI 并不神奇,它只是构建东西的另一种方式。你也不能这样做:
new CommandHandler<TMessage>()
也就是说,除非您知道 TMessage
是什么,否则这没有意义。你需要一个具体的类型。
然而,除此之外,很难弄清楚发生了什么。题少了很多
- 它提到对
container. GetService
的调用返回 null 但不是您在返回 null 时要解决的问题。
- 所有示例代码都显示
MessageHandler
,但您在调试器中 运行 的示例是 CommandHandler
。没有足够的信息知道这是错字还是问题的一部分。
无论如何,我希望能给你一些关于要看什么的想法。
我有一个使用中介模式处理消息的 .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
方法;但是,如果我在调用 Handle
和 运行 之前放置一个断点,则 Visual Studio 中的立即 window 中的以下内容:
_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);
您无法解析开放式泛型。
你提到的问题是你不能这样做:
container.GetService(typeof(ICommandHandler<TMessage>))
但是 DI 并不神奇,它只是构建东西的另一种方式。你也不能这样做:
new CommandHandler<TMessage>()
也就是说,除非您知道 TMessage
是什么,否则这没有意义。你需要一个具体的类型。
然而,除此之外,很难弄清楚发生了什么。题少了很多
- 它提到对
container. GetService
的调用返回 null 但不是您在返回 null 时要解决的问题。 - 所有示例代码都显示
MessageHandler
,但您在调试器中 运行 的示例是CommandHandler
。没有足够的信息知道这是错字还是问题的一部分。
无论如何,我希望能给你一些关于要看什么的想法。