2016-12-29 33 views
1

我有一个工厂在接收消息到达时创建消息处理程序。消息处理程序需要几个依赖关系 - 一个基于传入消息选择的配置对象和其他基础结构组件。Autofac - 如何实现使用运行时信息的工厂?

我使用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

防止不必运行时间数据注入applicatino组件所描述的方法。这是[反模式](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=99)。 – Steven

+0

好点。在我当前的解决方案中,运行时数据在创建对象后被馈送到方法中。 –

回答

0

我找到了解决方案的基础上,由Alex迈耶-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;