SlideShare a Scribd company logo
http://stackoverflow.com/questions/1638919/how-to-explain-dependency-injection-to-a-5-year-old/1638961#1638961
Dependency Injection, 
the right way 
Thibaud DESODT 
@tsimbalar
This talk 
• What it is about 
– Dependency Injection (DI) patterns 
– Benefits 
– Common pitfalls 
• What it is not about 
– Specific IoC/DI Container implementations 
• Pre-requisites 
– OOP 
– Class-based statically-typed languages 
• Based on examples
Dependency injection - the right way
What ? 
DEPENDENCY INJECTION
Dependency Injection 
Dependency Injection is a set of practices that 
allow to build loosely coupled applications
Dependency Injection 
Dependency Injection is a set of practices that 
allow to build loosely coupled applications 
It’s NOT : 
– A library 
– A framework 
– A tool 
It IS : 
- A way of thinking 
- A way of designing code 
- General guidelines
Dependency Injection 
Dependency Injection is a set of practices that 
allow to build loosely coupled applications 
Small components … 
- Independent 
- Reusable 
- Interchangeable 
… plugged together to 
form a bigger system 
Benefits : 
- Small classes with single 
responsibility 
- Easier maintenance 
- Extensibility 
- Testable
Show me the code ! 
FROM TIGHTLY TO LOOSELY 
COUPLED
Example : Boring Bank™ System 
• Features 
– User can list his 
accounts 
– User can rename his 
accounts 
– User can transfer money 
from an account to the 
other 
• Tech : 
– Web front-end 
– Relational database
Starting from scratch 
public class AccountController : BaseController 
{ 
// GET: Account 
[HttpGet] 
public ActionResult Index() 
{ 
var userId = this.User.AsClaimsPrincipal().UserId(); 
using (var context = new BankingDbContext()) 
{ 
var accounts = context.Accounts 
.Where(a => a.CustomerId == userId) 
.OrderBy(a => a.Title).ToList(); 
return View(accounts); 
} 
} 
[HttpPost] 
public ActionResult TransferPost(int from, int to, decimal amount) 
{ 
var userId = this.User.AsClaimsPrincipal().UserId(); 
using (var context = new BankingDbContext()) 
{ 
var accountFrom = context.Accounts 
.Single(a => a.CustomerId == userId && a.Id == from); 
var accountTo = context.Accounts 
.Single(a => a.CustomerId == userId && a.Id == to); 
accountFrom.Balance -= amount; 
accountTo.Balance += amount; 
context.SaveChanges(); 
return RedirectToAction("Index"); 
} 
} 
data 
business 
presentation
Tightly-coupled code 
• Using another kind of UI ? 
• Using another kind of storage ? 
• Using the business rules somewhere else ?
Separation of Concerns 
• Layered architecture / split assemblies 
– Presentation 
– Business 
– Data-access (Repository) 
• Separated : 
– Persistence Entities 
– Domain Entities 
– View Models
public class AccountController : BaseController 
public Account GetAccountForCustomer(int customerId, int accountId) 
{ 
// GET: Account 
[HttpGet] 
public ActionResult Index() 
{ 
var userId = this.User.AsClaimsPrincipal().UserId(); 
public void Transfer(int userId, int fromAccountId, int toAccountId, decimal amountToTransfer 
var userAccountService = new UserAccountService(); 
var accounts = userAccountService.GetAccountsForCustomer(userId); 
return View(ToViewModel(accounts)); 
} 
[HttpPost] 
public ActionResult TransferPost(int from, int to, decimal amount) 
{ 
var userId = this.User.AsClaimsPrincipal().UserId(); 
var userAccountService = new UserAccountService(); 
userAccountService.Transfer(userId, from, to, amount); 
return RedirectToAction("Index"); 
} 
AccountController.cs (WebPortal) 
UI talks to Business 
{ 
// TODO : validate arguments 
var accountRepository = new AccountRepository(); 
var fromAccount = accountRepository.GetAccountForCustomer(userId, fromAccountId); 
var toAccount = accountRepository.GetAccountForCustomer(userId, toAccountId); 
// TODO : verify that there is enough money 
fromAccount.Balance -= amountToTransfer; 
toAccount.Balance += amountToTransfer; 
accountRepository.Update(fromAccount); 
accountRepository.Update(toAccount); 
} 
UserAccountService.cs (Business) 
Business talks to Data 
{ 
using (var context = new BankingDbContext("BankingDbContext")) 
{ 
var account = context.Accounts 
.Single(a => a.CustomerId == customerId && a.Id == accountId); 
return account; 
} 
} 
public void Update(Account account) 
{ 
using (var context = new BankingDbContext("BankingDbContext")) 
{ 
var accountEf = context.Accounts.Find(account.Id); 
// theoretically, could do "if not changed" 
accountEf.Balance = account.Balance; 
accountEf.Title = account.Title; 
context.SaveChanges(); 
} 
} 
AccountRepository.cs (Data)
That looks fine … but is it ?
anti-pattern : Control Freak 
• Symptoms: 
– Code insists on how the dependencies are built 
– Makes it impossible to use component in isolation 
– Not testable without full stack 
• Easy to spot : new everywhere 
AccountController : BaseController 
Account 
HttpGet] 
ActionResult Index() 
userId = this.User.AsClaimsPrincipal().UserId(); 
userAccountService = new UserAccountService(); 
accounts = userAccountService.GetAccountsForCustomer(userId); 
return View(ToViewModel(accounts)); 
public void Transfer(int userId, int fromAccountId, int toAccountId 
{ 
// TODO : validate arguments 
var accountRepository = new AccountRepository(); 
var fromAccount = accountRepository.GetAccountForCustomer 
var toAccount = accountRepository.GetAccountForCustomer 
// TODO : verify that there is enough money 
fromAccount.Balance -= amountToTransfer; 
toAccount.Balance += amountToTransfer; 
accountRepository.Update(fromAccount); 
accountRepository.Update(toAccount); 
}
Unit tests as a Coupling Detector 
• Unit tests are “just another client” for your 
code 
• If unit tests are hard to write, the code is 
probably too tightly coupled 
-> Let’s make it testable !
Making it testable - Properties 
public class UserAccountService 
{ 
[TestMethod] 
public void RenameAccount_must_UpdateAccountName() 
{ 
public UserAccountService() 
{ 
AccountRepository = new AccountRepository("BankingContext"); 
} 
#region Dependency Management 
public AccountRepository AccountRepository { get; set; } 
#endregion 
Settable property allows 
to “inject” another instance 
// Arrange 
var newName = "someName"; 
var existingAccount = AnAccount(); 
var sut = new UserAccountService(); 
sut.AccountRepository = FAIL FAIL//I want to put a fake here ! 
// Act 
sut.RenameAccount(existingAccount.CustomerId, existingAccount.Id, 
newName); 
// Assert 
// I want to verify what happened .. 
} 
In UserAccountServiceTest.cs , in test project Business.Tests
Programming to an interface 
public class UserAccountService : IUserAccountService 
[TestMethod] 
{ 
public void RenameAccount_must_UpdateAccountName() 
{ 
public UserAccountService() 
{ 
// Arrange 
var newName = "someName"; 
AccountRepository = new AccountRepository("BankingContext"); 
} 
var existingAccount = AnAccount(); 
#region Dependency Management 
var mockRepo = new Mock<IAccountRepository>(); 
mockRepo.Setup(r => r.GetAccountForCustomer(It.IsAny<int>(), It.IsAny<int>())) 
public IAccountRepository AccountRepository { get; set; } 
.Returns(existingAccount); 
var sut = new UserAccountService(); 
sut.AccountRepository = mockRepo.Object; //I want to put a fake here ! 
#endregion Use an interface (or abstract class) instead of concrete class 
// Act 
sut.RenameAccount(existingAccount.CustomerId, existingAccount.Id, newName); 
// Assert 
mockRepo.Verify(r=> r.Update(It.Is<Data.Account>(a=> a.Title == newName))); 
} 
Inject fake instance
pattern : Property Injection 
Expose settable properties to modify dependencies 
Benefits 
• Useful to provide optional extensibility 
• There must be a good “local default” implementation 
Caveats 
• Not very easy to discover point of extension 
• Easy to forget 
• Extra care to avoid NullReferenceExceptions, handle 
thread-safety etc
Making it more explicit - Constructor 
public class UserAccountService : IUserAccountService 
{ 
private readonly IAccountRepository _accountRepository; 
Injection constructor 
used in tests - declare required dependencies as constructor parameters 
public UserAccountService(IAccountRepository accountRepository) 
{ 
public IAccountRepository AccountRepository { get { return _accountRepository; if (accountRepository == null) throw new ArgumentNullException("accountRepository 
_accountRepository = accountRepository; 
} 
public UserAccountService() 
:this(new AccountRepository("BankingContext")) 
{ 
} 
#region Dependency Management 
Default constructor 
used in production code 
[TestMethod] 
public void RenameAccount_must_UpdateAccountName() 
{ 
// Arrange 
var newName = "someName"; 
var existingAccount = AnAccount(); 
var mockRepo = new Mock<IAccountRepository>(); 
mockRepo.Setup(r => r.GetAccountForCustomer(It.IsAny<int>(), It.IsAny<int>())) 
.Returns(existingAccount); 
var sut = new UserAccountService(mockRepo.Object); 
// Act 
sut.RenameAccount(existingAccount.CustomerId, existingAccount.Id, newName); 
// Assert 
mockRepo.Verify(r=> r.Update(It.Is<Data.Account>(a=> a.Title == newName))); 
} 
Inject fake instance
anti-pattern : Bastard Injection 
Enable dependencies for testing, but use hard-code 
implementation in production code 
• Paradox: 
– Lots of efforts to reduce coupling 
– … but forcing a hard-coded value 
• Test-specific code 
• Ambiguity
Cutting the dependency chain 
public class AccountController : BaseController 
{ 
private readonly IUserAccountService _userAccountService; 
public class UserAccountService : IUserAccountService 
Only 1 constructor - dependencies passed as constructor arguments 
{ 
public private AccountController(readonly IAccountRepository IUserAccountService _accountRepository; 
userAccountService) 
{ 
if (userAccountService == null) throw new ArgumentNullException("userAccountService 
_userAccountService = userAccountService; 
} 
public UserAccountService(IAccountRepository accountRepository) 
{ 
if (accountRepository == null) throw new ArgumentNullException("accountRepository 
_accountRepository = accountRepository; 
AccountController (WebPortal) 
} 
UserAccountService.cs (Business)
pattern : Constructor Injection 
Declare required dependencies as constructor 
parameters 
• Declarative 
• Discoverable (Intellisense, Reflection …) 
• Recommended approach in 99.9% of cases 
• Easy to implement 
Need Guard clause because C# does not support non-nullable 
reference types …
Inverted depency
This is great and everything except … 
[InvalidOperationException: An error occurred when trying to create a controller of 'BoringBank.WebPortal.Controllers.AccountController'. Make sure that the controller System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext 
System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext
The chicken and the egg 
IAccountRepository repo = new IAccountRepository(); 
• Ideal world: Programming to interfaces 
vs 
• Real world : applications do not work with only 
interfaces 
• Class instances have to be created and assembled 
(=composed) at some point 
• This happens only in one place in an application
pattern : Composition Root 
Composition of classes into a larger system should 
happen only in one place 
• Create one object-graph 
• As late as possible 
• Only part of the code that can reference concrete types 
Where ? 
• Only applications have a Composition Root 
• There is no Composition Root in a class library 
• Extension point depends on the kind of app
ASP.NET MVC Composition Root 
public class AppCompositionRoot : DefaultControllerFactory 
• IControllerFactory 
• Creates a controller instance based on URL 
• DefaultControllerFactory uses default 
constructor on Controller 
• … but it can be changed ! 
{ 
protected override IController GetControllerInstance(RequestContext requestContext 
Type controllerType) 
{ 
// how to compose an AccountController ? 
if (controllerType == typeof(AccountController)) 
{ 
var connectionString = ConfigurationManager 
.ConnectionStrings["BankingDbContext"].ConnectionString; 
var repo = new AccountRepository(connectionString); 
var service = new UserAccountService(repo); 
return new AccountController(service); 
Controller 
composition 
} 
// standard way in MVC to use default strategy 
return base.GetControllerInstance(requestContext, controllerType); 
} 
} 
public class MvcApplication : System.Web.HttpApplication 
{ 
protected void Application_Start() 
{ 
var factory = new AppCompositionRoot(); 
ControllerBuilder.Current.SetControllerFactory(factory); 
In Global.asax 
tell MVC to use our composition root
Pure DI (aka Poor Man’s DI) 
Manual wiring of dependencies 
• Very explicit (no « magic ») 
• Type-safe 
• … but repetitive and boring 
var connectionString = ConfigurationManager 
.ConnectionStrings["BankingDbContext"].ConnectionString; 
var repo = new AccountRepository(connectionString); 
var service = new UserAccountService(repo); 
return new AccountController(service);
And we did that because … ? 
SO WHAT ?
Benefits of full DI-friendly codebase 
• Testability 
• Maintainability 
• Allows parallel work 
• … and more ! 
• Defined in a centralized location
Reusability / Extensibility 
or CLI 
or WPF 
or Web API 
or WCF 
… 
or files 
or NoSQL 
or Azure 
or Http Client 
…
Extensibility 
public class CachedAccountRepository : IAccountRepository 
{ 
private readonly ICache _cache; 
private readonly IAccountRepository _decorated; 
• Decorator Pattern 
public CachedAccountRepository(ICache cache, IAccountRepository decorated) 
{ 
– Very DI-friendly pattern 
var nakedRepo = new AccountRepository(connectionString); 
if (cache == null) throw new ArgumentNullException("cache"); 
if (decorated == null) throw new ArgumentNullException("decorated"); 
_cache = cache; 
_decorated = decorated; 
// decorate the nakedRepository with caching features 
var • Example longCache = : new caching 
DotNetCache(TimeSpan.FromHours(1)); 
var cachedRepo = new CachedAccountRepository(longCache, nakedRepo); 
var service } 
= new UserAccountService(cachedRepo); 
public IReadOnlyList<Account> GetAccountsForCustomer(int userId) 
{ 
var accounts = _cache.GetOrAdd("accounts_" + userId, 
() => _decorated.GetAccountsForCustomer(userId)); 
return accounts; 
} 
Decorator 
delegate to decorated instance
DI CONTAINERS
DI Container – how they work 
• Mapping Abstraction-> Concrete Type 
– Usually initialized on app start 
– Methods like 
Register<IAbstraction,ConcreteType>() 
• Method Resolve<TRequired>() 
• Recursively resolves dependencies reading 
constructor parameters
public class DependencyConfig 
Example - Unity 
{ 
public static void Configure(IUnityContainer container) 
{ 
var connectionString = ConfigurationManager.ConnectionStrings["BankingDbContext" 
public class MvcApplication : System.Web.HttpApplication 
{ 
public class AppCompositionRoot : DefaultControllerFactory 
protected void Application_Start() 
{ 
private readonly IUnityContainer _unityContainer; 
var container = new UnityContainer(); 
DependencyConfig.Configure(container); 
var compositionRoot = new AppCompositionRoot(container); 
ControllerBuilder.Current.SetControllerFactory(compositionRoot 
{ 
In Global.asax 
.ConnectionString; 
container.RegisterType<IAccountRepository, AccountRepository>( 
new InjectionConstructor(connectionString)); 
container.RegisterType<IUserAccountService, UserAccountService>(); 
} 
} 
public AppCompositionRoot(IUnityContainer unityContainer) 
{ 
In DependencyConfig 
if (unityContainer == null) throw new ArgumentNullException("unityContainer 
_unityContainer = unityContainer; 
} 
protected override IController GetControllerInstance(RequestContext requestContext 
controllerType) 
{ 
return (IController) _unityContainer.Resolve(controllerType); 
} 
} 
In CompositionRoot 
Register / Resolve (/ Release)
Aspects of DI 
• Composition 
• Lifetime Management 
• Interception
Interception 
• ~ Dynamic Decorators 
• Cross-cutting concerns 
– Logging 
– Auditing 
– Profiling … 
• AOP-like !
public class TimingBehavior : IInterceptionBehavior 
{ 
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext 
{ 
var stopwatch = new Stopwatch(); 
// Before invoking the method on the original target. 
Debug.WriteLine("> {0}.{1}", input.MethodBase.DeclaringType, input.MethodBase.Name); 
stopwatch.Start(); 
// Invoke the next behavior in the chain. 
var result = getNext()(input, getNext); 
stopwatch.Stop(); 
// After invoking the method on the original target. 
if (result.Exception != null) 
{ 
Debug.WriteLine( 
Call to decorated instance 
"< {0}.{1} failed - after {3} ms", 
input.MethodBase.DeclaringType, input.MethodBase.Name, result.Exception.GetType(), 
stopwatch.ElapsedMilliseconds); 
} 
else 
{ 
Debug.WriteLine("< {0}.{1} - after {2} ms", 
input.MethodBase.DeclaringType, input.MethodBase.Name, 
stopwatch.ElapsedMilliseconds); 
} 
Before each method call of decorated class 
After each method call 
public class DependencyConfig 
{ 
public static void Configure(IUnityContainer container) 
{ 
container.AddNewExtension<Interception>(); 
var connectionString = ConfigurationManager.ConnectionStrings["BankingDbContext"] 
.ConnectionString; 
container.RegisterType<IAccountRepository, AccountRepository>( 
new InjectionConstructor(connectionString), 
new Interceptor<InterfaceInterceptor>(), 
new InterceptionBehavior<TimingBehavior>()); 
container.RegisterType<IUserAccountService, UserAccountService>( 
new Interceptor<InterfaceInterceptor>(), 
new InterceptionBehavior<TimingBehavior>()); 
} 
}
TO CONCLUDE …
Things to remember 
• DI Patterns … 
– Don’t be a Control Freak 
– Constructor Injection is your friend 
– Compose you object graphs in one place 
– DI Containers are powerful but not magical 
• … can help you achieve loosely coupled code 
– Maintainable 
– Testable
Going further … 
• Mark Seemann’s book 
and blog posts 
– http://blog.ploeh.dk/ 
• Conversation about DI 
in aspnet vNext 
– http://forums.asp.net/t/1989008.aspx?Feedback+ 
on+ASP+NET+vNext+Dependency+Injection 
• SOLID principles
Shoot ! 
Q&A
Contact : @tsimbalar 
THANKS FOR ATTENDING !
You want more ? 
EXTRAS
Late-binding 
• Dynamically decide which implementation to 
protectuedsoeverride IController GetControllerInstance(RequestContext requestContext, 
Type controllerType) 
{ 
// how to compose an AccountController ? 
if (controllerType == typeof(AccountController)) 
{ 
var repo = LoadInstanceFromPluginFolder<IAccountRepository>(); 
Plugin scenarios – scan assemblies in a folder for implementations 
var service = new UserAccountService(repo); 
return new AccountController(service); 
} 
// standard way in MVC to use default strategy 
return base.GetControllerInstance(requestContext, controllerType);
LifeTime Management
anti-pattern : Service Locator
SOLID 
Single Responsibility Principle 
Open Closed Principle 
Liskov Substitution Principle 
Interface Segregation Principle 
Dependency Inversion Principe

More Related Content

Dependency injection - the right way

  • 2. Dependency Injection, the right way Thibaud DESODT @tsimbalar
  • 3. This talk • What it is about – Dependency Injection (DI) patterns – Benefits – Common pitfalls • What it is not about – Specific IoC/DI Container implementations • Pre-requisites – OOP – Class-based statically-typed languages • Based on examples
  • 5. What ? DEPENDENCY INJECTION
  • 6. Dependency Injection Dependency Injection is a set of practices that allow to build loosely coupled applications
  • 7. Dependency Injection Dependency Injection is a set of practices that allow to build loosely coupled applications It’s NOT : – A library – A framework – A tool It IS : - A way of thinking - A way of designing code - General guidelines
  • 8. Dependency Injection Dependency Injection is a set of practices that allow to build loosely coupled applications Small components … - Independent - Reusable - Interchangeable … plugged together to form a bigger system Benefits : - Small classes with single responsibility - Easier maintenance - Extensibility - Testable
  • 9. Show me the code ! FROM TIGHTLY TO LOOSELY COUPLED
  • 10. Example : Boring Bank™ System • Features – User can list his accounts – User can rename his accounts – User can transfer money from an account to the other • Tech : – Web front-end – Relational database
  • 11. Starting from scratch public class AccountController : BaseController { // GET: Account [HttpGet] public ActionResult Index() { var userId = this.User.AsClaimsPrincipal().UserId(); using (var context = new BankingDbContext()) { var accounts = context.Accounts .Where(a => a.CustomerId == userId) .OrderBy(a => a.Title).ToList(); return View(accounts); } } [HttpPost] public ActionResult TransferPost(int from, int to, decimal amount) { var userId = this.User.AsClaimsPrincipal().UserId(); using (var context = new BankingDbContext()) { var accountFrom = context.Accounts .Single(a => a.CustomerId == userId && a.Id == from); var accountTo = context.Accounts .Single(a => a.CustomerId == userId && a.Id == to); accountFrom.Balance -= amount; accountTo.Balance += amount; context.SaveChanges(); return RedirectToAction("Index"); } } data business presentation
  • 12. Tightly-coupled code • Using another kind of UI ? • Using another kind of storage ? • Using the business rules somewhere else ?
  • 13. Separation of Concerns • Layered architecture / split assemblies – Presentation – Business – Data-access (Repository) • Separated : – Persistence Entities – Domain Entities – View Models
  • 14. public class AccountController : BaseController public Account GetAccountForCustomer(int customerId, int accountId) { // GET: Account [HttpGet] public ActionResult Index() { var userId = this.User.AsClaimsPrincipal().UserId(); public void Transfer(int userId, int fromAccountId, int toAccountId, decimal amountToTransfer var userAccountService = new UserAccountService(); var accounts = userAccountService.GetAccountsForCustomer(userId); return View(ToViewModel(accounts)); } [HttpPost] public ActionResult TransferPost(int from, int to, decimal amount) { var userId = this.User.AsClaimsPrincipal().UserId(); var userAccountService = new UserAccountService(); userAccountService.Transfer(userId, from, to, amount); return RedirectToAction("Index"); } AccountController.cs (WebPortal) UI talks to Business { // TODO : validate arguments var accountRepository = new AccountRepository(); var fromAccount = accountRepository.GetAccountForCustomer(userId, fromAccountId); var toAccount = accountRepository.GetAccountForCustomer(userId, toAccountId); // TODO : verify that there is enough money fromAccount.Balance -= amountToTransfer; toAccount.Balance += amountToTransfer; accountRepository.Update(fromAccount); accountRepository.Update(toAccount); } UserAccountService.cs (Business) Business talks to Data { using (var context = new BankingDbContext("BankingDbContext")) { var account = context.Accounts .Single(a => a.CustomerId == customerId && a.Id == accountId); return account; } } public void Update(Account account) { using (var context = new BankingDbContext("BankingDbContext")) { var accountEf = context.Accounts.Find(account.Id); // theoretically, could do "if not changed" accountEf.Balance = account.Balance; accountEf.Title = account.Title; context.SaveChanges(); } } AccountRepository.cs (Data)
  • 15. That looks fine … but is it ?
  • 16. anti-pattern : Control Freak • Symptoms: – Code insists on how the dependencies are built – Makes it impossible to use component in isolation – Not testable without full stack • Easy to spot : new everywhere AccountController : BaseController Account HttpGet] ActionResult Index() userId = this.User.AsClaimsPrincipal().UserId(); userAccountService = new UserAccountService(); accounts = userAccountService.GetAccountsForCustomer(userId); return View(ToViewModel(accounts)); public void Transfer(int userId, int fromAccountId, int toAccountId { // TODO : validate arguments var accountRepository = new AccountRepository(); var fromAccount = accountRepository.GetAccountForCustomer var toAccount = accountRepository.GetAccountForCustomer // TODO : verify that there is enough money fromAccount.Balance -= amountToTransfer; toAccount.Balance += amountToTransfer; accountRepository.Update(fromAccount); accountRepository.Update(toAccount); }
  • 17. Unit tests as a Coupling Detector • Unit tests are “just another client” for your code • If unit tests are hard to write, the code is probably too tightly coupled -> Let’s make it testable !
  • 18. Making it testable - Properties public class UserAccountService { [TestMethod] public void RenameAccount_must_UpdateAccountName() { public UserAccountService() { AccountRepository = new AccountRepository("BankingContext"); } #region Dependency Management public AccountRepository AccountRepository { get; set; } #endregion Settable property allows to “inject” another instance // Arrange var newName = "someName"; var existingAccount = AnAccount(); var sut = new UserAccountService(); sut.AccountRepository = FAIL FAIL//I want to put a fake here ! // Act sut.RenameAccount(existingAccount.CustomerId, existingAccount.Id, newName); // Assert // I want to verify what happened .. } In UserAccountServiceTest.cs , in test project Business.Tests
  • 19. Programming to an interface public class UserAccountService : IUserAccountService [TestMethod] { public void RenameAccount_must_UpdateAccountName() { public UserAccountService() { // Arrange var newName = "someName"; AccountRepository = new AccountRepository("BankingContext"); } var existingAccount = AnAccount(); #region Dependency Management var mockRepo = new Mock<IAccountRepository>(); mockRepo.Setup(r => r.GetAccountForCustomer(It.IsAny<int>(), It.IsAny<int>())) public IAccountRepository AccountRepository { get; set; } .Returns(existingAccount); var sut = new UserAccountService(); sut.AccountRepository = mockRepo.Object; //I want to put a fake here ! #endregion Use an interface (or abstract class) instead of concrete class // Act sut.RenameAccount(existingAccount.CustomerId, existingAccount.Id, newName); // Assert mockRepo.Verify(r=> r.Update(It.Is<Data.Account>(a=> a.Title == newName))); } Inject fake instance
  • 20. pattern : Property Injection Expose settable properties to modify dependencies Benefits • Useful to provide optional extensibility • There must be a good “local default” implementation Caveats • Not very easy to discover point of extension • Easy to forget • Extra care to avoid NullReferenceExceptions, handle thread-safety etc
  • 21. Making it more explicit - Constructor public class UserAccountService : IUserAccountService { private readonly IAccountRepository _accountRepository; Injection constructor used in tests - declare required dependencies as constructor parameters public UserAccountService(IAccountRepository accountRepository) { public IAccountRepository AccountRepository { get { return _accountRepository; if (accountRepository == null) throw new ArgumentNullException("accountRepository _accountRepository = accountRepository; } public UserAccountService() :this(new AccountRepository("BankingContext")) { } #region Dependency Management Default constructor used in production code [TestMethod] public void RenameAccount_must_UpdateAccountName() { // Arrange var newName = "someName"; var existingAccount = AnAccount(); var mockRepo = new Mock<IAccountRepository>(); mockRepo.Setup(r => r.GetAccountForCustomer(It.IsAny<int>(), It.IsAny<int>())) .Returns(existingAccount); var sut = new UserAccountService(mockRepo.Object); // Act sut.RenameAccount(existingAccount.CustomerId, existingAccount.Id, newName); // Assert mockRepo.Verify(r=> r.Update(It.Is<Data.Account>(a=> a.Title == newName))); } Inject fake instance
  • 22. anti-pattern : Bastard Injection Enable dependencies for testing, but use hard-code implementation in production code • Paradox: – Lots of efforts to reduce coupling – … but forcing a hard-coded value • Test-specific code • Ambiguity
  • 23. Cutting the dependency chain public class AccountController : BaseController { private readonly IUserAccountService _userAccountService; public class UserAccountService : IUserAccountService Only 1 constructor - dependencies passed as constructor arguments { public private AccountController(readonly IAccountRepository IUserAccountService _accountRepository; userAccountService) { if (userAccountService == null) throw new ArgumentNullException("userAccountService _userAccountService = userAccountService; } public UserAccountService(IAccountRepository accountRepository) { if (accountRepository == null) throw new ArgumentNullException("accountRepository _accountRepository = accountRepository; AccountController (WebPortal) } UserAccountService.cs (Business)
  • 24. pattern : Constructor Injection Declare required dependencies as constructor parameters • Declarative • Discoverable (Intellisense, Reflection …) • Recommended approach in 99.9% of cases • Easy to implement Need Guard clause because C# does not support non-nullable reference types …
  • 26. This is great and everything except … [InvalidOperationException: An error occurred when trying to create a controller of 'BoringBank.WebPortal.Controllers.AccountController'. Make sure that the controller System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext
  • 27. The chicken and the egg IAccountRepository repo = new IAccountRepository(); • Ideal world: Programming to interfaces vs • Real world : applications do not work with only interfaces • Class instances have to be created and assembled (=composed) at some point • This happens only in one place in an application
  • 28. pattern : Composition Root Composition of classes into a larger system should happen only in one place • Create one object-graph • As late as possible • Only part of the code that can reference concrete types Where ? • Only applications have a Composition Root • There is no Composition Root in a class library • Extension point depends on the kind of app
  • 29. ASP.NET MVC Composition Root public class AppCompositionRoot : DefaultControllerFactory • IControllerFactory • Creates a controller instance based on URL • DefaultControllerFactory uses default constructor on Controller • … but it can be changed ! { protected override IController GetControllerInstance(RequestContext requestContext Type controllerType) { // how to compose an AccountController ? if (controllerType == typeof(AccountController)) { var connectionString = ConfigurationManager .ConnectionStrings["BankingDbContext"].ConnectionString; var repo = new AccountRepository(connectionString); var service = new UserAccountService(repo); return new AccountController(service); Controller composition } // standard way in MVC to use default strategy return base.GetControllerInstance(requestContext, controllerType); } } public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { var factory = new AppCompositionRoot(); ControllerBuilder.Current.SetControllerFactory(factory); In Global.asax tell MVC to use our composition root
  • 30. Pure DI (aka Poor Man’s DI) Manual wiring of dependencies • Very explicit (no « magic ») • Type-safe • … but repetitive and boring var connectionString = ConfigurationManager .ConnectionStrings["BankingDbContext"].ConnectionString; var repo = new AccountRepository(connectionString); var service = new UserAccountService(repo); return new AccountController(service);
  • 31. And we did that because … ? SO WHAT ?
  • 32. Benefits of full DI-friendly codebase • Testability • Maintainability • Allows parallel work • … and more ! • Defined in a centralized location
  • 33. Reusability / Extensibility or CLI or WPF or Web API or WCF … or files or NoSQL or Azure or Http Client …
  • 34. Extensibility public class CachedAccountRepository : IAccountRepository { private readonly ICache _cache; private readonly IAccountRepository _decorated; • Decorator Pattern public CachedAccountRepository(ICache cache, IAccountRepository decorated) { – Very DI-friendly pattern var nakedRepo = new AccountRepository(connectionString); if (cache == null) throw new ArgumentNullException("cache"); if (decorated == null) throw new ArgumentNullException("decorated"); _cache = cache; _decorated = decorated; // decorate the nakedRepository with caching features var • Example longCache = : new caching DotNetCache(TimeSpan.FromHours(1)); var cachedRepo = new CachedAccountRepository(longCache, nakedRepo); var service } = new UserAccountService(cachedRepo); public IReadOnlyList<Account> GetAccountsForCustomer(int userId) { var accounts = _cache.GetOrAdd("accounts_" + userId, () => _decorated.GetAccountsForCustomer(userId)); return accounts; } Decorator delegate to decorated instance
  • 36. DI Container – how they work • Mapping Abstraction-> Concrete Type – Usually initialized on app start – Methods like Register<IAbstraction,ConcreteType>() • Method Resolve<TRequired>() • Recursively resolves dependencies reading constructor parameters
  • 37. public class DependencyConfig Example - Unity { public static void Configure(IUnityContainer container) { var connectionString = ConfigurationManager.ConnectionStrings["BankingDbContext" public class MvcApplication : System.Web.HttpApplication { public class AppCompositionRoot : DefaultControllerFactory protected void Application_Start() { private readonly IUnityContainer _unityContainer; var container = new UnityContainer(); DependencyConfig.Configure(container); var compositionRoot = new AppCompositionRoot(container); ControllerBuilder.Current.SetControllerFactory(compositionRoot { In Global.asax .ConnectionString; container.RegisterType<IAccountRepository, AccountRepository>( new InjectionConstructor(connectionString)); container.RegisterType<IUserAccountService, UserAccountService>(); } } public AppCompositionRoot(IUnityContainer unityContainer) { In DependencyConfig if (unityContainer == null) throw new ArgumentNullException("unityContainer _unityContainer = unityContainer; } protected override IController GetControllerInstance(RequestContext requestContext controllerType) { return (IController) _unityContainer.Resolve(controllerType); } } In CompositionRoot Register / Resolve (/ Release)
  • 38. Aspects of DI • Composition • Lifetime Management • Interception
  • 39. Interception • ~ Dynamic Decorators • Cross-cutting concerns – Logging – Auditing – Profiling … • AOP-like !
  • 40. public class TimingBehavior : IInterceptionBehavior { public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext { var stopwatch = new Stopwatch(); // Before invoking the method on the original target. Debug.WriteLine("> {0}.{1}", input.MethodBase.DeclaringType, input.MethodBase.Name); stopwatch.Start(); // Invoke the next behavior in the chain. var result = getNext()(input, getNext); stopwatch.Stop(); // After invoking the method on the original target. if (result.Exception != null) { Debug.WriteLine( Call to decorated instance "< {0}.{1} failed - after {3} ms", input.MethodBase.DeclaringType, input.MethodBase.Name, result.Exception.GetType(), stopwatch.ElapsedMilliseconds); } else { Debug.WriteLine("< {0}.{1} - after {2} ms", input.MethodBase.DeclaringType, input.MethodBase.Name, stopwatch.ElapsedMilliseconds); } Before each method call of decorated class After each method call public class DependencyConfig { public static void Configure(IUnityContainer container) { container.AddNewExtension<Interception>(); var connectionString = ConfigurationManager.ConnectionStrings["BankingDbContext"] .ConnectionString; container.RegisterType<IAccountRepository, AccountRepository>( new InjectionConstructor(connectionString), new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<TimingBehavior>()); container.RegisterType<IUserAccountService, UserAccountService>( new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<TimingBehavior>()); } }
  • 42. Things to remember • DI Patterns … – Don’t be a Control Freak – Constructor Injection is your friend – Compose you object graphs in one place – DI Containers are powerful but not magical • … can help you achieve loosely coupled code – Maintainable – Testable
  • 43. Going further … • Mark Seemann’s book and blog posts – http://blog.ploeh.dk/ • Conversation about DI in aspnet vNext – http://forums.asp.net/t/1989008.aspx?Feedback+ on+ASP+NET+vNext+Dependency+Injection • SOLID principles
  • 45. Contact : @tsimbalar THANKS FOR ATTENDING !
  • 46. You want more ? EXTRAS
  • 47. Late-binding • Dynamically decide which implementation to protectuedsoeverride IController GetControllerInstance(RequestContext requestContext, Type controllerType) { // how to compose an AccountController ? if (controllerType == typeof(AccountController)) { var repo = LoadInstanceFromPluginFolder<IAccountRepository>(); Plugin scenarios – scan assemblies in a folder for implementations var service = new UserAccountService(repo); return new AccountController(service); } // standard way in MVC to use default strategy return base.GetControllerInstance(requestContext, controllerType);
  • 50. SOLID Single Responsibility Principle Open Closed Principle Liskov Substitution Principle Interface Segregation Principle Dependency Inversion Principe

Editor's Notes

  1. Present you self
  2. Talk about Dependency Injection Dependency Injection patterns You may know about it under a form or another, or ay have used tools Who has ? You must unlearn ! Need to understand the philosophy and concepts in order to use the tools properly It’s easy to misuse the tools and miss some benefits
  3. There is no magic !
  4. Let’s see … Inside a controller Creating a dbcontext (Entity Framework) … imagine if that was ADO .NET Selecting a few things Passing it to the view… Has anybody ever written code like that ? That’s only a read page … imagine action with side effects… Simplified, no error handling whatsoever You may argue that it is loosely coupled … there’s only one class … but what a class !
  5. Turned spaghetti into lasagna 
  6. Business depends on Data layer … it should be an implementation detail Presentation depends on Business which depends on Data … which depends on EF … we’ll see that a bit later But mostly about using components in isolation … this is not testable right now
  7. Comment : First encounter with need for loosely coupled code came from unit tests Who write unit tests here ? Anybody who writes unit tests first ? First encounter where you code MUST BE loosely coupled : unit tests ! Actually consume components out of the scope of the application Tightly coupled code is hard to test or not testable at all … if it’s testable it’s not too tightly coupled
  8. Interface of abstract class …. I can’t do new I….. The closest we can get is this …. Note that even though we introduced interfaces, we still have a hard reference between all projects
  9. Used in default Visual Studio Template for MVC apps until not so long ago
  10. Comment about moving the interface into business Where to put the interface ? Separate project “Abstractions” ? The consumer owns the interface
  11. If you remember one thing, it’s that !
  12. Top down
  13. Can be done with Adapter pattern
  14. Traditionnal approach would be : Modify code Subclass..