我有一个工厂,当收到的消息到达时,它会创建消息处理程序。消息处理程序采用多种依赖关系 - 基于传入消息和其他基础结构组件选择的配置对象。
我使用Autofac和委托,我无法避免将MessageHandlerFactory耦合到特定的实现类。
这是我能够将代表注入工厂的唯一方法:
// Handler defines a delegate that Autofac turns into a factory method
public class FtpMessageHandler : IFtpMessageHandler {
public delegate FtpMessageHandler Factory (Configuration configuration);
public FtpMessageHandler(Configuration configuration,
S3Facade s3Facade,
.... other dependencies.....
)
....
}
// In Autofac module..
// This is how I'd like to register the component, but it does NOT
// work - Autofac fails to resolve the delegate
builder.RegisterType<FtpMessageHandler>().As<IFtpMessageHandler>();
// This is what DOES work
builder.RegisterType<FtpMessageHandler>();
public class MessageHandlerFactory {
public FtpMessageHandler.Factory FtpMessageHandlerFactory { get; }
...
public MessageHandlerFactory( FtpMessageHandler.Factory ftpMessageHandlerFactory, ....)
FtpMessageHandlerFactory = ftpMessageHandlerFactory;
)
public IMessageHandler GetMessageHandler(MessageTypeEnum type, Configuration config) {
if (type == MessageTypeEnum.FTP)
return FtpMessageHandlerFactory.Invoke(config);
....
)
}
所以......这是一种时尚之后的作品。
但我不满意必须在MessageHandlerFactory中注入具体类型。例如,这排除了在IMessageHandler上使用装饰器而不修改工厂。
有更好的方法吗?
答案 0 :(得分:0)
我找到了一个解决方案,基于Alex Meyer-Gleaves所描述的方法http://alexmg.com/selectively-resolving-services-at-runtime-with-autofac/
// New class
public class MessageHandlerMetadata
{
public FileTransportTypeEnum TransportType { get; set; }
}
// Registration
builder.Register(c => new FtpMessageHandler( c.Resolve<IS3Facade>(), c.Resolve<IFtpHelper>()))
.As<IMessageHandler>()
.WithMetadata<MessageHandlerMetadata>(m => m.For(am => am.TransportType, FileTransportTypeEnum.FTP));
....
builder.Register(
c => new MessageHandlerFactory(c.Resolve<IConfigurationProvider>(),
c.Resolve<IEnumerable<Lazy<IMessageHandler, MessageHandlerMetadata>>>()))
.As<IMessageHandlerFactory>();
// In the Factory
public MessageHandlerFactory(
IEnumerable<Lazy<IMessageHandler, MessageHandlerMetadata>> messageHandlers) { ... }
private IMessageHandler GetHandlerByConfigurationType(FileTransportTypeEnum fileTransportType,
DestinationConfiguration configuration)
{
var lazy = MessageHandlers.FirstOrDefault(h => h.Metadata.TransportType == fileTransportType);
if (lazy == null)
{
throw new ArgumentException($"No handler is registered with File Transport type {fileTransportType}.");
}
var handler = lazy.Value;
handler.Configure(configuration);
return handler;