2016-12-29 48 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;