Satisfy your desire to be a better software developer by learning how to implement Dependency Injection (DI) in your application. Dependency Injection is one of the more popular implementations of Inversion of Control (IoC) that helps to increase modularity and extensibility of software. In this lecture, we'll discuss the benefits of DI, methods for implementing and refactoring existing code to use DI, adding unit tests using MSTest and Moq, popular DI frameworks like Unity, Ninject, and Castle Windsor, as well as alternative IoC patterns and anti-patterns.
3. SOLID
• S – Single responsibility
– A class should have only a single responsibility
• O – Open / closed principle
– Classes should be open for extension, but closed for modification
• L – Liskov substitution principle
– Objects of a program should be replaceable with instances of their subtypes
• I – Interface segregation principle
– Many client-specific interfaces are better than one general-purpose interface
• D – Dependency inversion principle
– One should depend on abstractions and not concretions
– Not the same as Dependency Injection but related
3
The 5 commandments of OO design
4. ObjectA
InterfaceB InterfaceC
Method1() Method2()
ObjectB ObjectC
Method1() Method2()
Loose Coupling
ObjectA
ObjectB ObjectC
Method1() Method2()
Tight Coupling
Tight vs. Loose Coupling
4
• Coupling
– Degree to which one component (i.e. dependency) has knowledge of another
• Tight Coupling
– A class has a direct reference to a concrete class.
• Loose Coupling
– A class has a reference to an abstraction which can be implemented by one or more
classes.
5. ObjectA
InterfaceB InterfaceC
Method1() Method2()
ObjectD ObjectE
Method1() Method2()
Loose Coupling
ObjectA
ObjectD ObjectE
Method1() Method2()
Tight Coupling
Tight vs. Loose Coupling
5
• Benefits of Loose Coupling
– Testability – easier to test objects in isolation
– Reuse – dependencies can be swapped without modifying target
– Open / Closed Principle - change behavior without modifying target
– Parallel development – developers can work in parallel more easily
7. Tight Coupling Example
7
How do we test
WidgetDataProvider in isolation
from its dependencies?
How can we reuse or change
WidgetDataProvider?
8. Refactoring Dependencies to Abstractions
• Interfaces
– Every declared method must be implemented by concrete class
• Abstract classes
– Only methods declared abstract must be implemented by concrete class
– Can provide some default implementation for methods not declared abstract
8
14. Inversion of Control (IoC)
• Traditional programming
– Dependencies are instantiated by a class that need them
• Inversion of Control (IoC)
– Dependencies are instantiated by a 3rd party and supplied to a class as needed
14
DependencyA DependencyB
ChildClass
IDependencyA IDependencyB
ChildClass
creates/consumes creates/consumes
ParentClass
creates/consumes
ParentClass
createsconsumes
Traditional Inversion of Control
consumesconsumes
RootContext
consumes
SomeClass creates
SomeClass
creates
SomeClass
creates
SomeClass creates
RootContext
creates/consumes
15. Inversion of Control (IoC)
• Dependency Injection
– Constructor Injection
– Property / Setter Injection
– Method Injection
– Ambient Context
• Factory pattern
– Dependencies created by factory class
– Factories can be injected via DI
• Service locator
– Class uses Service Locator to pull dependencies as needed
– Anti-pattern
• Hides a class’ dependencies
• Dependencies magically appear
• Great way to introduce runtime exceptions
– Caution
• Avoid using DI frameworks as Service Locator
15
Implementations
16. Dependency Injection
16
Constructor Injection
Use readonly fields as
backing store
Inject dependencies via
constructor
Guard against null
arguments
Save dependencies to field
• When to use
– When a dependency is required
• Important considerations
– Use single constructor
– Keep constructors lightweight
– Minimize number of dependencies (1-3)
17. Dependency Injection
17
Property / Setter Injection
Use public get/set to inject
dependencies.
Guard against null
references (if necessary)
• When to use
– When a dependency is optional or changeable at runtime
– When default constructor is required (ASP.NET Pages/Controls)
19. Dependency Injection
19
Ambient Context
Set a default. If no default
then use NullObject pattern
Static get/set allows access
to current logger
Guard against null values
Implement concrete logger
Extract static methods to an
interface
• When to use
– Cross cutting concerns (i.e. Logging, Security, etc.)
– Avoid polluting constructors with global dependencies
• Important considerations
– Thread safety
– Use sparingly
20. Automated Testing
• Unit Testing
– Test a class in isolation from dependencies
– Use mock objects in place of dependencies
• Roll your own
• Framework (i.e. Moq)
– Unit tests should never interact with a database
– Should be extremely fast
• Integration Testing
– Test a class along with its dependencies
– More complex than unit tests
– May include database calls which can be slow and brittle
20
21. TestInitialize
21
Create fields for our mocks
and target for testing
Create mocks and inject as
needed
Create mocks and inject into
target constructor
22. TestMethod
22
GetWidgets() successful path
Configure our mocks to
return test data.
Use Verifiable() to ensure
that these specific methods
were called.
Execute the method we’re
testing
Verify the results are as
expected
24. Object Composition / Lifetime Management
• Object Composition
– How and where do we instantiate and inject dependencies?
• Object Lifetime Management
– How do we manage the lifetime of dependencies?
– How do we manage sharing dependencies?
24
Object creation
Use the data provider
Objects go out of scope and
are garbage collected.
25. Object Composition
• Single place in application where object graph is created
• Nearest the application entry point
• Examples
– Console App = Main method
– Windows Services = Main method
– ASP.NET Web Forms = global.asax
– ASP.NET MVC = IControllerFactory
– WCF = ServiceHostFactory
25
Composition Root
WidgetDataProvider
SqlWidgetDataFeed WidgetDataReader
Simple Object Graph
Composition Root
WidgetDataProvider
SqlWidgetDataFeed WidgetDataReader
More Realistic Object Graph
Composition
Root
26. Dependency Injection Frameworks
• How they make life easier
– Automatically detect and resolve dependencies (Autowiring)
– Manage object lifetime and sharing between objects (Lifetime Management)
– Allow disposing of all registered dependencies
• Lifecycle
– Register
• Perform early in application (application composition root)
• Perform all registrations at the same time
– Resolve
• Typically only resolve at the composition root
• Resolving elsewhere = Service Locator anti-pattern
– Dispose
• Dispose of DI container to ensure registered objects are disposed
• Examples
– Unity (Microsoft), Ninject, Castle Windsor, Autofac, StructureMap, …
26
30. Unity
30
Registration
• Code
– Simplest but requires recompiling when changes made
• XML
– More difficult (no editor) but no recompiling when changes made
• Convention
– Good for large applications
31. Unity
• Transient (default)
– New instance created for each call to Resolve
• Container Controlled (i.e. singleton)
– Shared instance when Resolve or dependency injected
• Externally Controlled
– Similar to Container Controlled (i.e. singleton)
– Weak reference kept so container does not handle disposing
• Per Thread
– One instance created per thread
31
Lifetime Managers
33. Dependency Injection Frameworks
Unity (3.0) Ninject Castle Windsor Autofac StructureMap
License MS-PL Apache 2 Apache 2 MIT Apache 2
Code Configuration Yes Yes Yes Yes Yes
XML Configuration Yes Yes Yes Yes Yes
Auto Configuration Yes Yes Yes Yes Yes
Auto Wiring Yes Yes Yes Yes Yes
Lifetime Managers Yes Yes Yes Yes Yes
Interception Yes Yes Yes Yes Yes
Constructor Injection Yes Yes Yes Yes Yes
Property Injection Yes Yes Yes Yes Yes
33
Feature Comparison
• Same basic features
• Each has advanced features that set them apart
• Be aware of performance
• Research a few before choosing
34. References
• Dependency Injection in .NET (Mark Seemann)
– http://techbus.safaribooksonline.com/book/programming/csharp/9781935182504
• Adaptive Code via C# (Gary McLean Hall)
– http://techbus.safaribooksonline.com/9780133979749/
• Intro to Inversion of Control (IoC)
– http://msdn.microsoft.com/en-us/library/ff921087.aspx
• Service Locator is an Anti-pattern (Mark Seemann)
– http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/
• Developer’s Guide to Dependency Injection Using Unity
– http://msdn.microsoft.com/en-us/library/dn223671(v=pandp.30).aspx
• IOC Framework Comparison
– http://blog.ashmind.com/2008/08/19/comparing-net-di-ioc-frameworks-part-1/
– http://www.palmmedia.de/blog/2011/8/30/ioc-container-benchmark-performance-
comparison
34
Hinweis der Redaktion
Example of Tight Coupling
Cascading effect
Example of Tight Coupling
Cascading effect
A class can implement as many interfaces as it wants
A class can only inherit from one abstract class
Need way of instantiating dependencies without tight coupling.
Important Considerations:
Multiple constructors cause problems with DI containers
Lightweight constructors keep init quick
Too many dependencies code smell violating Single Responsibility
Refactor to classes with SR
Thread safety
Multiple threads can access simultaneously
Use ‘lock’ keyword to lock critical regions
Example of using MSTEST which is built into Visual Studio
Gets run immediately before each unit test
Good place to set up our mocks and target object
Each unit test has 3 parts
Time to wire up to our application
Where do we wire up our objects to the application?