IoC, factories, and constructor arguments

I am a newbie struggling with IoC and DI. I would like to dynamically allow connection and factory connection using autofac (or any other suitable .NET IoC tool).

The script can change the connection implementation to another with a lot of tracing options, etc.

When I apply DI and IoC to the code below, I get namedParameter clutter in constructors, etc. The factory connection returns a new connection with a unique port (silly example, just to show that I need to save some kind of state in the factory)

I suppose I could use property injection for the IP range and port, but in this case I am not guaranteed that the connections will have an IP or port, which is the constructor point. Also, named parameters make me depend on argument names.

IoC ideas, templates, pointers are greatly appreciated!

Update:

More specifically: how can I change the connection class for injections? Should I go with an injection of property? Or any tricks I could do could get a safer solution with constructor arguments?

public interface IConnection { void Open(); void Close(); string Execute(string command); } public interface IConnectionFactory { IConnection CreateConnection(); } public class Connection : IConnection { ... public Connection(String ip, int port) { _ip = ip; _port = port; } public string Execute() {} public void Open() {} public void Close() {} } public class ConnectionFactory : IConnectionFactory { //How would I resolve this? public ConnectionFactory(string ip, int fromPort) { ... } public IConnection CreateConnection() { //How would I resolve this? return new Connection(ip, fromPort++); } } 

Now use:

 //Register builder.RegisterType<Connection>().As<IConnection>(); builder.RegisterType<ConnectionFactory>().As<IConnectionFactory>().SingleInstance(); ... var connection = container.Resolve<IConnectionFactory>( new NamedParameter("ip", "127.0.0.1"), new NamedParameter("fromPort", 80).CreateConnection()); 
+6
c # inversion-of-control autofac
source share
3 answers

An alternative to passing constructor arguments during resolution is to encode these arguments in the registration function:

 builder .Register(c => new ConnectionFactory("127.0.0.1", 80)) .As<IConnectionFactory>() .SingleInstance(); 

Autofac will use this function whenever it needs to create a factory instance.

Since we configured ConnectionFactory as SingleInstance , it will be shared by all components that depend on IConnectionFactory . This means that ConnectionFactory needs to maintain its own state between calls to CreateConnection :

 public class ConnectionFactory : IConnectionFactory { private int _fromPort; public ConnectionFactory(string ip, int fromPort) { ... _fromPort = fromPort; } public IConnection CreateConnection() { return new Connection(ip, _fromPort++); } } 

If you have a one-time ConnectionFactory that, say, uses a different IP address, you can use named registration:

 builder .Register(c => new ConnectionFactory("192.168.0.1", 80)) .Named<IConnectionFactory>("AlernateConnectionFactory") .SingleInstance(); 

If you want the component to use this particular factory instead of the standard, you can use the ResolveNamed method:

 builder.Register(c => new Foo(c.ResolvedNamed<IConnectionFactory>("AlernateConnectionFactory"))); 

This is a convenient method for setting up a type in several ways and using them in specific places.

+6
source share

I am not familiar with Autofac, but I solved a very similar problem in Unity. Here is a snippet:

When I set up my container, I do something like this (this can even be done in the configuration file):

 string connectionString = ConfigurationManager.ConnectionStrings["XYZ"].ConnectionString; Container.RegisterType<IConnection, Connection>(new PerThreadLifetimeManager(), new InjectionConstructor(connectionString)); 

Later, I can build the connections simply by saying:

 IConnection myConnection = Container.Resolve<IConnection>(); 

or by specifying a dependency property:

 [Dependency] IConnection Connection {get;set;} 

or as an injectable parameter for constructor injection:

 [InjectionConstructor] public SomeClassThatUsesConnections(IConnection connection) { ... } 

I left PerThreadLifetimeManager to indicate that I allow the IoC transaction to ensure that neither of the two threads uses the connection.

Although the difference with your sample in the question is subtle, it removes the parameters from each instance, which allows you to use it as a dependency property or as part of the injection constructor.

Hope this helps.

+2
source share

A flexible approach may be to create an “AppConfigConnectionFactory” (or WebConfig, DBConfig, etc.) and externalize these properties using configuration. I have never felt correctly loading configuration data directly from the DI framework.

+1
source share

All Articles