I’m a beginner struggling with IoC and DI. I’d like to be able to resolve the connection and connection factory dynamically using autofac (or any other suitable .NET IoC tool).
A scenario could be changing the connection implementation to another one with more facilities for tracing etc.
When I apply DI and IoC to the code below, I get a mess of namedParameter in constructors etc. The connection factory returns a new connection with a unique port (silly example, just to show I need to keep some sort of state in the factory)
I figure I could use property injection for the IP and port range, but that way, I wouldn’t be guaranteed that the connections would have an IP or port, which is the point of a constructor.
Also, the named parameters make me dependent on the names of the arguments as well.
Ideas, patterns, IoC pointers are much appreciated!
Update:
More specific: How could I change the connection class to be injectable? Should I go with property injection? Or any tricks I could do get a more type-safe resolving 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, the usage:
//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());
An alternative to passing the constructor arguments at resolve-time is to encode those arguments in the registration function:
Autofac will use that function whenever it needs to create the connection factory instance.
Since we configured
ConnectionFactoryasSingleInstance, it will be shared amongst all components which depend onIConnectionFactory. This meansConnectionFactoryneeds to keep its own state between calls toCreateConnection:If you have a one-off
ConnectionFactorywhich, say, uses a different IP, you can use a named registration:When you want a component to use that particular factory instead of the default one, you can use the
ResolveNamedmethod:This is a handy technique to configure a type in multiple ways and use them in specific places.