我正在使用Autofac,并希望有多个接口实现。如何配置Autofac以便根据当前类型解析依赖关系?
更具体地说,我有一个接口和多个应该链接在一起的实现。
让我解释一下(虚拟课程):
public interface IMessageHandler
{
void Handle(Message message);
}
public class LoggingMessageHandler : IMessageHandler
{
private IMessageHandler _messageHandler;
public LoggingMessageHandler(IMessageHandler messageHandler)
{
_messageHandler = messageHandler;
}
public void Handle(Message message)
{
// log something
_messageHandler.Handle(message);
}
}
public class DoSomethingMessageHandler : IMessageHandler
{
private IMessageHandler _messageHandler;
public DoSomethingMessageHandler (IMessageHandler messageHandler)
{
_messageHandler = messageHandler;
}
public void Handle(Message message)
{
// do something
_messageHandler.Handle(message);
}
}
链的底部可能是IMessageHandler
,它不会将消息传递给下一个消息。
如果我想要以下链:
TopLevelClass -> LoggingMessageHandler -> DoSomethingMessageHandler -> FinalHandler
如何告知Autofac
LoggingMessageHandler
传递给TopLevelClass
(以实现对IMessageHandler
的依赖)DoSomethingMessageHandler
传递给LoggingMessageHandler
(以实现对IMessageHandler
的依赖)LoggingMessageHandler
传递给FinalHandler
(以实现对IMessageHandler
的依赖)是否可能(我已阅读implicit support for IEnumerable)?或者我是否必须在中间使用额外的课程(工厂或其他)?
答案 0 :(得分:17)
对于任何其他搜索,我只是碰到了这个。您可以对IEnumerable使用隐式支持。 I wrote it up for future use
基本上,您可以按名称(或其他条件)将程序集类型注册为IEnumerable,以后可以使用。我最喜欢的方法是你可以继续添加消息处理程序,只要你坚持相同的标准,你就不必再接触标准了。
builder.RegisterAssemblyTypes(typeof (LoggingMessageHandler).Assembly)
.Where(x => x.Name.EndsWith("MessageHandler"))
.AsImplementedInterfaces();
public class Foo
{
private readonly IEnumerable<IMessageHandler> _messageHandlers
public Foo(IEnumerable<IMessageHandler> messageHandlers)
{
_messageHandlers = messageHandlers;
}
public void Bar(message)
{
foreach(var handler in _messageHandlers)
{
handler.Handle(message)
}
}
}
答案 1 :(得分:6)
Autofac支持Decorators。
答案 2 :(得分:2)
此处有4个选项:https://autofaccn.readthedocs.io/en/latest/faq/select-by-context.html
选项1:重新设计界面
ILoggingMessageHandler , IDoSomethingMessageHandler
选项2:更改注册
builder.Register(ctx => new FinalHandler(ctx.Resolve<LoggingMessageHandler >()));
or
builder.Register(ctx => new FinalHandler(ctx.Resolve<IDoSomethingMessageHandler >()));
选项3:使用密钥服务
builder.RegisterType<FinalHandler>()
.WithParameter(
new ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof(IMessageHandler),
(pi, ctx) => ctx.ResolveKeyed<ISender>("something")));
选项4:使用元数据
public class FinalHandler
{
public FinalHandler([WithMetadata("sendBy", "something")] IMessageHandler messageHandler) { ... }
}
答案 3 :(得分:0)
不太难。您可以将具体类型注册为self并在进行时解决它。然后可以为接口注册顶级消息处理程序(在您的示例中为LoggingMessageHandler),TopLevelClass将使用该接口
以下是您正在查看的内容(假设您有一个FinalHandler的默认构造函数)
var builder = new ContainerBuilder();
builder.RegisterType<FinalHandler>().AsSelf().SingleInstance();
builder.Register(c => new DoSomethingMessageHandler(c.Resolve<FinalHandler>())).AsSelf().SingleInstance();
builder.Register(c => new LoggingMessageHandler(c.Resolve<DoSomethingMessageHandler>())).As<IMessageHandler>().SingleInstance();
//now finally your top level class - this will automatically pick your LoggingMessageHandler since the others have been registered onto their concreteTypes only
builder.RegisterType<TopLevelClass>().As<ITopLevelClass>().InstancePerOwned();