The Dependency Injection pattern is all the rage these days and more and more DI containers are becoming part of how we build .Net applications. I still have a love / hate relationship with Dependency Injection. I love the idea of being able to inject any external dependencies into my classes, thereby breaking those dependencies, but I hate the idea of creating an interface for every class that I need to inject, then maintaining that interface as well as any classes that implement it. Let me show you what I mean.
Dependency Injection on an MVC Controller Base Class With Interfaces
Typical scenario, I have an ASP.Net MVC2 application that needs to get data from a database. All of my data access code is contained in service classes like UserService, SystemService, CompanyService, etc. I don’t want to manually declare and instantiate whatever service classes I need in each of my controller classes, so I created an abstract base class for my controllers called AtsControllerBase which has properties that will provide instances of my service classes using a lazy creation pattern. Here’s an abbreviated version of the base class.
public abstract class AtsControllerBase : Controller
{
//******************************************************
// PROPERTIES
//******************************************************
// StateBox
private HfStateBox _stateBox;
public HfStateBox StateBox
{
get { return NewIfNull(_stateBox); }
set { _stateBox = value; }
}
// AuthToken
public AuthToken AuthToken { get { return StateBox.AuthToken; } }
// ApplicantService
private ApplicantService _applicantService;
public ApplicantService ApplicantService
{
get { return NewIfNull(_applicantService); }
set { _applicantService = value; }
}
// CompanyService
private CompanyService _companyService;
public CompanyService CompanyService
{
get { return NewIfNull(_companyService); }
set { _companyService = value; }
}
// FolderService
private FolderService _folderService;
public FolderService FolderService
{
get { return NewIfNull(_folderService); }
set { _folderService = value; }
}
// JobService
private JobService _jobService;
public JobService JobService
{
get { return NewIfNull(_jobService); }
set { _jobService = value; }
}
// SecurityService
private SecurityService _securityService;
public SecurityService SecurityService
{
get { return NewIfNull(_securityService); }
set { _securityService = value; }
}
// SystemService
private SystemService _systemService;
public SystemService SystemService
{
get { return NewIfNull(_systemService); }
set { _systemService = value; }
}
// ServicePlanService
private ServicePlanService _servicePlanService;
public ServicePlanService ServicePlanService
{
get { return NewIfNull(_servicePlanService); }
set { _servicePlanService = value; }
}
// UserService
private UserService _userService;
public UserService UserService
{
get { return NewIfNull(_userService); }
set { _userService = value; }
}
// WorkflowService
private WorkflowService _workflowService;
public WorkflowService WorkflowService
{
get { return NewIfNull(_workflowService); }
set { _workflowService = value; }
}
//******************************************************
// UTILITY METHODS
//******************************************************
// NewIfNull
public T NewIfNull<T>(T obj) where T:new()
{
if (obj == null) { obj = new T(); }
return obj;
}
}
This pattern works well for me because my concrete controllers never need to instantiate a service, they can just access any of the service properties in the base class. I don’t have the overhead of newing up a bunch of service classes that the concrete controller won’t use because the services aren’t instantiated until the first time the service property is accessed. That’s the lazy creation part. Finally, each property has a public setter, so I can replace any of my services if I need to inject a mock or stub or something.
So this already looks a lot like Dependency Injection. After all we have public setters for each of the services so we could switch them out if needed. There’s one thing missing though. We have no interfaces. Our properties are all using the concrete type of the service class (like FolderService) instead of some public interface (like IFolderService). So we could inject something, but it would have to be another instance of FolderService. That get’s us nowhere. How can we inject something else like a MockFolderService?? Hmmmm, I guess the right way to implement Dependency Injection is to create an IFolderService interface for my FolderService class. At least that’s the pattern that I always see in books and code samples. Let’s try that. Ok, FolderService only has 10 public methods. That’s not too bad so we’ll start with that one. Here’s the service code.
public partial class FolderService : ServiceBase
{
//**************************************************************************************
// FOLDER METHODS
//**************************************************************************************
// GetFolderByFolderGuid
public virtual Folder GetFolderByFolderGuid(Guid folderGuid)
{
string sql = @"SELECT *
FROM [Folder]
WHERE [FolderGuid] = @FolderGuid";
SqlDao dao = SharedSqlDao;
SqlCommand command = dao.GetSqlCommand(sql);
command.Parameters.Add(dao.CreateParameter("@FolderGuid", folderGuid));
return dao.GetSingle<Folder>(command);
}
// GetListOfFolderWithCountsForCompany
public virtual List<FolderWithCount> GetListOfFolderWithCountsForCompany(Guid companyGuid)
{
string sql = @"SELECT f.*, (SELECT COUNT([ApplicantGuid])
FROM [ApplicantInFolder] WHERE [FolderGuid] = f.[FolderGuid]) As ApplicantCount
FROM [Folder] f
WHERE f.[CompanyGuid] = @CompanyGuid";
SqlDao dao = SharedSqlDao;
SqlCommand command = dao.GetSqlCommand(sql);
command.Parameters.Add(dao.CreateParameter("@CompanyGuid", companyGuid));
return (dao.GetList<FolderWithCount>(command));
}
// GetListOfFoldersForCompany
public virtual List<Folder> GetListOfFoldersForCompany(Guid companyGuid)
{
string sql = @"SELECT f.*
FROM [Folder] f
WHERE f.[CompanyGuid] = @CompanyGuid";
SqlDao dao = SharedSqlDao;
SqlCommand command = dao.GetSqlCommand(sql);
command.Parameters.Add(dao.CreateParameter("@CompanyGuid", companyGuid));
return (dao.GetList<Folder>(command));
}
// GetListOfFoldersForApplicant
public virtual List<Folder> GetListOfFoldersForApplicant(Guid applicantGuid)
{
string sql = @"select f.*
from Folder f
join ApplicantInFolder aif on aif.FolderGuid = f.FolderGuid
where aif.ApplicantGuid = @ApplicantGuid";
SqlDao dao = SharedSqlDao;
SqlCommand command = dao.GetSqlCommand(sql);
command.Parameters.Add(dao.CreateParameter("@ApplicantGuid", applicantGuid));
return (dao.GetList<Folder>(command));
}
// GetCachedListOfFoldersForCompany
public virtual List<FolderWithCount> GetCachedListOfFoldersForCompany(Guid companyGuid)
{
if (companyGuid.Equals(NullValues.NullGuid))
{
// return empty list if a null guid was passed
return new List<FolderWithCount>();
}
string key = "__GetCachedListOfFoldersForCompany_" + companyGuid.ToString();
CacheHelper helper = new CacheHelper();
List<FolderWithCount> list = helper.TryGet<List<FolderWithCount>>(key);
if (list == null)
{
RefreshCachedListOfFoldersForCompany(companyGuid);
list = helper.TryGet<List<FolderWithCount>>(key);
}
return list;
}
// RefreshCachedListOfFoldersForCompany
public virtual void RefreshCachedListOfFoldersForCompany(Guid companyGuid)
{
string key = "__GetCachedListOfFoldersForCompany_" + companyGuid.ToString();
CacheHelper helper = new CacheHelper();
List<FolderWithCount> list = helper.TryGet<List<FolderWithCount>>(key);
list = GetListOfFolderWithCountsForCompany(companyGuid);
helper.Add(key, list);
}
// Insert
public virtual void Insert(Folder folder)
{
this.FolderPersister.Insert(folder);
}
// Save
public virtual void Save(Folder folder)
{
this.FolderPersister.Save(folder);
}
// Delete
public virtual void Delete(Folder folder)
{
this.FolderPersister.Delete(folder.FolderGuid);
}
// AddApplicantToFolder
public virtual void AddApplicantToFolder(Guid applicantGuid, Guid companyGuid, Folder folder)
{
this.FolderPersister.SafeInsertApplicantInFolder(applicantGuid, folder.FolderGuid);
RefreshCachedListOfFoldersForCompany(companyGuid);
}
}
We’ve basically got 10 public data access methods. Now I need to create a public interface that defines all of the public methods, so I’m going to create a new IFolderService interface. ReSharper even makes it easy for me with a handy Extract Interface tool. So my interface looks like this.
public interface IFolderService
{
Folder GetFolderByFolderGuid(Guid folderGuid);
List<FolderWithCount> GetListOfFolderWithCountsForCompany(Guid companyGuid);
List<Folder> GetListOfFoldersForCompany(Guid companyGuid);
List<Folder> GetListOfFoldersForApplicant(Guid applicantGuid);
List<FolderWithCount> GetCachedListOfFoldersForCompany(Guid companyGuid);
void RefreshCachedListOfFoldersForCompany(Guid companyGuid);
void Insert(Folder folder);
void Save(Folder folder);
void Delete(Folder folder);
void AddApplicantToFolder(Guid applicantGuid, Guid companyGuid, Folder folder);
SqlDao SharedSqlDao { get; set; }
ApplicantPersister ApplicantPersister { get; set; }
CareerSiteSettingsPersister CareerSiteSettingsPersister { get; set; }
CompanyPersister CompanyPersister { get; set; }
CompanySettingsPersister CompanySettingsPersister { get; set; }
FolderPersister FolderPersister { get; set; }
HistoryItemPersister HistoryItemPersister { get; set; }
JobPersister JobPersister { get; set; }
JobStubPersister JobStubPersister { get; set; }
ResumePersister ResumePersister { get; set; }
UserPersister UserPersister { get; set; }
WorkflowPersister WorkflowPersister { get; set; }
T NewIfNull<T>(T obj) where T : new();
string GetSqlCsv(List<Guid> list);
string GetSqlCsv(List<int> list);
}
There, that wasn’t too bad. Now I just need to change my controller FolderService property to type IFolderService and I have Dependency Injection implemented for the FolderService. I can create new classes that implement IFolderService and inject them into my controller using the public FolderService property like this.
var controller = new FolderController();
IFolderService mock = new MockFolderService();
controller.FolderService = mock;
That’s great! Now I just need to do that for… wait… I’m going to have to do that for every service class in my application. Then I’m going to have to maintain each of those interfaces every time I make a change to a service class. That’s a lot of extra code and a lot of work that’s going to have to be repeated every time I make a change to my service classes. Why am I doing this again? This is starting to feel like the hate part of the love / hate relationship.
Dependency Injection on an MVC Controller Base Class Without Interfaces
So I don’t really want to create an interface for every single dependency in my application and then have to maintain that interface as well as my concrete classes, but what other option do I have? Everybody implements DI using interfaces right? Interfaces are like a badge of honor that demonstrate you know how to architect an application the right way. You haven’t been to architecture land until you have your interface badge. We love interfaces!
Well I don’t love any code that I have to spend extra time maintaining every time I make a change to my application. All that stuff adds up after a while. I call it the death of a thousand cuts. One day you look up and all those little extra tasks like maintaining interfaces add up to a mountain of friction that makes it miserable to make changes to your code. Now there are places for interfaces, but if possible I’m opting for an easier alternative.
So step one in the easier alternative, throw out the interface that I just created and change my FolderService property back to type FolderService (no more IFolderService). Step two…. actually we don’t need a step two we’re done. Lets take a closer look at one of the data access methods in our FolderService class.
// GetFolderByFolderGuidpublic virtual Folder GetFolderByFolderGuid(Guid folderGuid)
{
string sql = @"SELECT *
FROM [Folder]
WHERE [FolderGuid] = @FolderGuid";
SqlDao dao = SharedSqlDao;
SqlCommand command = dao.GetSqlCommand(sql);
command.Parameters.Add(dao.CreateParameter("@FolderGuid", folderGuid));
return dao.GetSingle<Folder>(command);
}
Hmmm, that’s a virtual method. That means that I can create a class that inherits from FolderService and just override the GetFolderByFolderGuid() method. The FolderService class actually functions as my interface in this scenario. So, if I’m writing a unit test where I want to stub out my FolderService I could create the following class.
public class FolderServiceStub: FolderService
{
public override Folder GetFolderByFolderGuid(Guid folderGuid)
{
return new Folder() {FolderGuid = folderGuid, FolderName = "Test Folder"};
}
}
FolderServiceStub inherits from FolderService so I can use that stub class anywhere that an object of type FolderService is expected. The end result is that my testing code (or any other DI code) winds up looking almost exactly like my code did with full on interface based Dependency injection
var controller = new FolderController();FolderService mock = new FolderServiceStub();
controller.FolderService = mock;
Summary
So, make all of your public methods virtual and you can implement a Poor Man’s Dependency Injection that doesn’t require interfaces. It’s not the right solution every situation, but I’ve found that it works most of the time for me. It also has the one quality that I prize most in code. It’s so simple that I forget it’s even there.