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());