Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autofac - How to create a generated factory with parameters

Tags:

I am trying to create with Autofac a 'generated' factory that will resolve dependencies in real-time based on an enum parameter.

Given the following interfaces/classes:

public delegate IConnection ConnectionFactory(ConnectionType connectionType);  public enum ConnectionType {     Telnet,     Ssh }  public interface IConnection {     bool Open(); }  public class SshConnection : ConnectionBase, IConnection {     public bool Open()     {         return false;     } }  public class TelnetConnection : ConnectionBase, IConnection {     public bool Open()     {         return true;     } }  public interface IEngine {     string Process(ConnectionType connectionType); }  public class Engine : IEngine {     private ConnectionFactory _connectionFactory;      public Engine(ConnectionFactory connectionFactory)     {         _connectionFactory = connectionFactory;     }      public string Process(ConnectionType connectionType)     {         var connection = _connectionFactory(connectionType);          return connection.Open().ToString();     } } 

I'd like to use Autofac to generate some sort of factory that has a method that receives one parameter: ConnectionType and returns the correct connection object.

I started with the following registrations:

builder.RegisterType<AutoFacConcepts.Engine.Engine>()     .As<IEngine>()     .InstancePerDependency();  builder.RegisterType<SshConnection>()     .As<IConnection>(); builder.RegisterType<TelnetConnection>()     .As<IConnection>(); 

I then continued to play with the TelnetConnection/SshConnection registrations with different options:

  1. Named
  2. Keyed
  3. Metadata

I couldn't find the correct combination of the registrations that will allow me to define a generated factory delegate that will return the correct connection object (SshConnection for ConnectionType.Ssh and TelnetConnection for ConnectionType.Telnet).

like image 268
Elie Avatar asked Oct 22 '15 19:10

Elie


1 Answers

Update the Engine class to take a Func<ConnectionType, IConnection> instead of the delegate. Autofac supports creating delegate factories on the fly via Func<T>.

public class Engine : IEngine {     private Func<ConnectionType, IConnection> _connectionFactory;      public Engine(Func<ConnectionType, IConnection> connectionFactory)     {         _connectionFactory = connectionFactory;     }      public string Process(ConnectionType connectionType)     {         var connection = _connectionFactory(connectionType);          return connection.Open().ToString();     } } 

In your registration use a lambda that grabs up the parameter and returns the correct IConnection instance.

builder.Register<IConnection>((c, p) => {     var type = p.TypedAs<ConnectionType>();     switch (type)     {         case ConnectionType.Ssh:             return new SshConnection();         case ConnectionType.Telnet:             return new TelnetConnection();         default:             throw new ArgumentException("Invalid connection type");     } }) .As<IConnection>(); 

If the connection itself required a dependency you could call Resolve on the c parameter to resolve it from the current call context. For example, new SshConnection(c.Resolve<IDependency>()).

like image 98
Alex Meyer-Gleaves Avatar answered Sep 28 '22 00:09

Alex Meyer-Gleaves