I’m continuing the series of post related to SignalR with dependency injection.
When having a complicated business you can start to group different functionalities in classes. Because of this you can end up very easily with classes that accept in constructor 4-5 or even 10 parameters.
People would say: “Well, we have dependency injector, the resolver will handle the constructor and resolve all the dependencies”. This is true, the resolver will inject all the dependencies automatically.
In general, because you don’t want to have a direct dependency to a specific dependency injector stack, people tend to create a wrapper over dependency resolver. The same thing was done in SignalR also.
Why is the best approach to this problem?
It cannot say that one is better than another. Using this solution, the constructor itself will be lighter, but in the same time you add dependency to the resolver. In a perfect world you shouldn’t have constructors with 7-10 parameters… but when you have cases like this, this solution could be pretty interesting.
When having a complicated business you can start to group different functionalities in classes. Because of this you can end up very easily with classes that accept in constructor 4-5 or even 10 parameters.
public abstract class PersistentConnection
{
public PersistentConnection(
IMessageBus messageBus, IJsonSerializer jsonSerializer,
ITraceManager traceManager, IPerformanceCounterManager performanceCounterManager,
IAckHandler ackHandler, IProtectedData protectedData,
IConfigurationManager configurationManager, ITransportManager transportManager,
IServerCommandHandler serverCommandHandler, HostContext hostContext)
{
}
...
}
Of course you have a decoupled solution that can be tested very easily, but in the same time you have a fat constructor.People would say: “Well, we have dependency injector, the resolver will handle the constructor and resolve all the dependencies”. This is true, the resolver will inject all the dependencies automatically.
In general, because you don’t want to have a direct dependency to a specific dependency injector stack, people tend to create a wrapper over dependency resolver. The same thing was done in SignalR also.
public interface IDependencyResolver : IDisposable
{
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
void Register(Type serviceType, Func<object> activator);
void Register(Type serviceType, IEnumerable<Func<object>> activators);
}
Additionally, they done something more. In ctor, they don’t send all the dependencies that are already register in the IoC container. They send directly the dependency resolver, which will be used by the class itself to resolve all the external dependencies.public abstract class PersistentConnection
{
public PersistentConnection(IDependencyResolver resolver, HostContext hostContext)
{
Initialize(resolver, hostContext);
}
public virtual void Initialize(IDependencyResolver resolver, HostContext context)
{
...
MessageBus = resolver.Resolve<IMessageBus>();
JsonSerializer = resolver.Resolve<IJsonSerializer>();
TraceManager = resolver.Resolve<ITraceManager>();
Counters = resolver.Resolve<IPerformanceCounterManager>();
AckHandler = resolver.Resolve<IAckHandler>();
ProtectedData = resolver.Resolve<IProtectedData>();
_configurationManager = resolver.Resolve<IConfigurationManager>();
_transportManager = resolver.Resolve<ITransportManager>();
_serverMessageHandler = resolver.Resolve<IServerCommandHandler>();
...
}
...
}
It is important to notify that you don’t need to inject everything through the resolver. You can have specific dependencies injected directly by constructor. For example, HostContext is something specific for each connection. Because of this is more natural to send this context using the constructor. Is something variable that is changing from one connection to another.Why is the best approach to this problem?
It cannot say that one is better than another. Using this solution, the constructor itself will be lighter, but in the same time you add dependency to the resolver. In a perfect world you shouldn’t have constructors with 7-10 parameters… but when you have cases like this, this solution could be pretty interesting.
Comments
Post a Comment