Skip to main content

Digging through SignalR - Dependency Resolver

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.
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

Popular posts from this blog

ADO.NET provider with invariant name 'System.Data.SqlClient' could not be loaded

Today blog post will be started with the following error when running DB tests on the CI machine:
threw exception: System.InvalidOperationException: The Entity Framework provider type 'System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer' registered in the application config file for the ADO.NET provider with invariant name 'System.Data.SqlClient' could not be loaded. Make sure that the assembly-qualified name is used and that the assembly is available to the running application. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information. at System.Data.Entity.Infrastructure.DependencyResolution.ProviderServicesFactory.GetInstance(String providerTypeName, String providerInvariantName) This error happened only on the Continuous Integration machine. On the devs machines, everything has fine. The classic problem – on my machine it’s working. The CI has the following configuration:

TeamCity.NET 4.51EF 6.0.2VS2013
It seems that there …

Entity Framework (EF) TransactionScope vs Database.BeginTransaction

In today blog post we will talk a little about a new feature that is available on EF6+ related to Transactions.
Until now, when we had to use transaction we used ‘TransactionScope’. It works great and I would say that is something that is now in our blood.
using (var scope = new TransactionScope(TransactionScopeOption.Required)) { using (SqlConnection conn = new SqlConnection("...")) { conn.Open(); SqlCommand sqlCommand = new SqlCommand(); sqlCommand.Connection = conn; sqlCommand.CommandText = ... sqlCommand.ExecuteNonQuery(); ... } scope.Complete(); } Starting with EF6.0 we have a new way to work with transactions. The new approach is based on Database.BeginTransaction(), Database.Rollback(), Database.Commit(). Yes, no more TransactionScope.
In the followi…

GET call of REST API that contains '/'-slash character in the value of a parameter

Let’s assume that we have the following scenario: I have a public HTTP endpoint and I need to post some content using GET command. One of the parameters contains special characters like “\” and “/”. If the endpoint is an ApiController than you may have problems if you encode the parameter using the http encoder.
using (var httpClient = new HttpClient()) { httpClient.BaseAddress = baseUrl; Task<HttpResponseMessage> response = httpClient.GetAsync(string.Format("api/foo/{0}", "qwert/qwerqwer"))); response.Wait(); response.Result.EnsureSuccessStatusCode(); } One possible solution would be to encode the query parameter using UrlTokenEncode method of HttpServerUtility class and GetBytes method ofUTF8. In this way you would get the array of bytes of the parameter and encode them as a url token.
The following code show to you how you could write the encode and decode methods.
publ…