Inversion of Control – Best Practises

Always Create an Interface

Every class that defines operations must have an interface.  The interface should serve as a contract and is particularly useful when mocking the behaviour during unit testing. The interface will also be used for registration with the container.

public class MyService : <strong>IMyService</strong>
{
    public void ProcessBatch(DateTime reportingDate)
    {
        var processor = new BatchProcessor(reportingDate);
        processor.Process();
    }
}

public interface IMyService
{
    void ProcessBatch(DateTime reportingDate);
}

Avoid Instantiating Objects Directly

For example we have the following implementation

public class MyService
{
    public MyService()
    {
    }

    public void ProcessBatch(DateTime reportingDate)
    {
        var processor = <strong>new BatchProcessor(reportingDate);</strong>
        processor.Process();
    }
}

The above code cannot be unit tested in isolation, by testing MyService we inadvertently end up testing BatchProcessor as well. The code could be rewritten as:

public class MyService : IMyService
{
    private readonly IBatchProcessorFactory _batchProcessorFactory;
    public MyService(<strong>IBatchProcessorFactory</strong> <strong>batchProcessorFactory</strong>)
    {
        _batchProcessorFactory = batchProcessorFactory;
    }

    public void ProcessBatch(DateTime reportingDate)
    {
        var processor <strong>= _batchProcessorFactory.Create(reportingDate);</strong>
        processor.Process();
    }
}

public interface IBatchProcessorFactory
{
    void IBatchProcessor Create(DateTime reportingDate);
}

public class BatchProcessorFactory : IBatchProcessorFactory
{
    public IBatchProcessor Create(DateTime reportingDate)
    {
        return new BatchProcessor(reportingDate);
    }
}

Now, in order to test the logic of MyService, we can mock IBatchProcessor and just test that the Process method is called on the instance!

Avoid Passing Primitives in Constructor

public class MyService : IMyService
{
    private readonly string _connectionString;
    public MyService(<strong>string connectionString</strong>)
    {
        _connectionString = connectionString;
    }

    public void Save()
    {
        using(var connection = <strong>new SqlConnection(_connectionString))</strong>
        {
            // Do some work
        }
    }
}

We should change it to:

public class MyService : IMyService
{
    private readonly IConnectionStringProvider _connectionStringProvider;
    public MyService(<strong>IConnectionStringProvider connectionStringProvider</strong>)
    {
        _connectionFactory = connectionFactory;
    }

    public void Save()
    {
        using(var connection <strong>= new SqlConnection(_connectionStringProvider.GetConnectionString()))</strong>
        {
            // Do some work
        }
    }
}

* Alternatively we could use a Factory pattern to get a connection instance

Don’t Pass Container in the Constructor

public class MyService : IMyService
{
    private readonly ISqlConnectionFactory _connectionFactory;
    public MyService(<strong>IUnityContainer container</strong>)
    {
        _connectionFactory = <strong>container.Resolve<ISqlConnectionFactory>();</strong>
    }
}

Instead pass the interface into the constructor:

public class MyService : IMyService
{
    private readonly ISqlConnectionFactory _connectionFactory;
    public MyService(<strong>ISqlConnectionFactory connectionFactory</strong>)
    {
        _connectionFactory = connectionFactory;
    }
}

The IoC container will resolve the references automatically:

var container = new UnityContainer();
container.Register<ISqlConnectionFactory, SqlConnectionFactory>();
container.Register<IMyService, MyService>();
//…
var myService = container.Resolve<IMyService>();

Avoid Named Instances

public class RiskDbSqlConnectionFactory : ISqlConnectionFactory
{
}
public class StaticDataSqlConnectionFactory : ISqlConnectionFactory
{
}

container.Register<ISqlConnectionFactory, RiskDbSqlConnectionFactory>(“RiskDB”);
container.Register<ISqlConnectionFactory, StaticDataSqlConnectionFactory>(“StaticDB”);

Instead use different interfaces to differentiate:


public class RiskDbSqlConnectionFactory : ISqlConnectionFactory, IRiskDbSqlConnectionFactory
{
}

public class StaticDataSqlConnectionFactory : ISqlConnectionFactory, IStaticDataSqlConnectionFactory
{
}

container.Register<IRiskDbSqlConnectionFactory, RiskDbSqlConnectionFactory>();
container.Register<IStaticDataSqlConnectionFactory, StaticDataSqlConnectionFactory>();

Avoid Static References

public class MyService : IMyService
{
    public void DoSomething()
    {
        SaveData(<strong>DateTime.Now</strong>);
    }
}

If you have to use a static property or a method in the code write a wrapper. For example:

public interface IDateTimeProvider
{
     DateTime GetCurrentTime();
}

public class DatetimeProvider : IDateTimeProvider
{
    public DateTime GetCurrentTime()
    {
        return DateTime.Now;
    }
}

public class MyService : IMyService
{
    private readonly IDateTimeProvider _dateTimeProvider;
    public MyService(IDateTimeProvider dateTimeProvider)
    {
        _dateTimeProvider = dateTimeProvider;
    }

    public void DoSomething()
    {
        SaveData(_dateTimeProvider.GetCurrentTime());
    }
}

This technique gives you an opportunity to mock DateTime to any value during unit testing

Interface Segregation (Liskov Principle)

Consider splitting large interfaces into smaller ones

public class Repository : IRepository
{
    public Item Load()
    {
    }

    public void Update(Item item)
    {
    }
}

This could be converted to 2 interfaces IItemLoader and IItemUpdater . The class definition would look like this:

public class Repository : IRepository, IItemLoader, IItemUpdater

Lifetime Management

If you need to make sure there is only going to be one instance of a particular type you have to register you class with ContainerControlledLifetimeManager instance.

container.Register<IMyService, MyService>(new ContainerControlledLifetimeManager())

Then the resolve method would return 1 instance of the class. If nothing is specified then a new instance will be created each time.

If you need to register an already existing instance then do the following:

var myService = new MyService();
container.RegisterInstance(typeof(IMyService), myService, new ContainerControlledLifetimeManager());

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: