Dependency Injection with Unity 2.0
Dmytro MindraRnD Tech Lead
Lohika
Вторая встреча Microsoft .Net User Group Одесса, 2010
Goal
• Get DI understanding• Get Unity 2.0 understanding• Learn how to add Unity 2.0 to your projects
Plan
• Inversion of Control principle (IoC)• Dependency Injection pattern (DI)• Unity 2.0• Live Demo
Problem
Problem
We live in an age where writing software to a given set of requirements is no longer enough.
We have to maintain and change existing code.
How?
Our solutions should be:• Modular• Testable• Adaptive to change
Terms
• Service —An object that performs a well-defined function when called upon
• Client —Any consumer of a service; an object that calls upon a service to perform a well-understood function
Terms
• Dependency —A specific service that is required by another object to fulfill its function.
• Dependent —A client object that needs a dependency (or dependencies) in order to perform its function.
PRE DI APPROACHES
Ex1:Composition
Ex1:Composition public class SpellCheckerService{}
public class TextEditor
{ private SpellCheckerService _spellCheckerService; public TextEditor() { _spellCheckerService = new SpellCheckerService(); } } class Program { static void Main(string[] args) { TextEditor textEditor = new TextEditor(); } }
TextEditor
SpellChecker
What’s good
• It’s simple
What’s bad
• It’s not testable• It’s hard to maintain/change
Ex2: Factory
Ex2: Factory
public interface ISpellCheckerService { string CheckSpelling(); }
Ex2: Factory
public class SpellCheckerService: ISpellCheckerService
{ public string CheckSpelling()
{ return “Real”; } }
Ex2: Factory public class SpellCheckerFactory { private static ISpellCheckerService
_spellCheckerService = new SpellCheckerService();
public static ISpellCheckerService SpellCheckerService
{ get{ return _spellCheckerService; } set{ _spellCheckerService = value; } } }
Ex2: Factorypublic class TextEditor{ private ISpellCheckerService _spellCheckerService; public TextEditor() { _spellCheckerService =
SpellCheckerFactory.SpellCheckerService; }
public string CheckSpelling() { return _spellCheckerService.CheckSpelling(); }}
Ex2:Factory Unit Testingpublic class SpellCheckerServiceMock: ISpellCheckerService
{ public string CheckSpelling() { return “Mock”; } }
Ex2:Factory Unit Testing [TestFixture] class EmailerFactoryUnitTests { [Test] public void EmailerFactoryTest() {
ISpellCheckerService mockSpellCheckerService = new SpellCheckerServiceMock();
SpellCheckerFactory.SpellCheckerService = mockSpellCheckerService;
TextEditor textEditor = new TextEditor(); Assert.AreEqual(“Mock”,
textEditor.CheckSpelling()); } }
Ex2: Factory
SpellCheckerServ iceFactory
- SpellCheckerService: SpellCheckerService
TextEditor
+ CheckSpelling() : bool
SpellCheckerServ ice
+ CheckSpelling() : string
«interface»ISpellCheckerServ ice
+ CheckSpelling() : string
SpellCheckerServ iceMock
+ CheckSpelling() : string
getSpellCheckerService
What changed
• TextEditor is still looking for its dependencies by itself. But now we can plug in different services without letting him know.
What’s good
• It’s testable• It’s easier to maintain/change
What’s bad
• You have to maintain factory or service locator• Dependent is still looking for Dependencies by
himself.• Dependencies are encapsulated and are not
obvious.
Service Locator
Unfortunately, being a kind of Factory, Service Locators suffer from the same problemsof testability and shared state.
Inversion of Control
Common Flow• TextEditor creates its
dependency by himself.
IoC Flow• TextEditor requests factory
to create dependency for him.
SpellCheckerServ iceFactory
- SpellCheckerService: SpellCheckerService
TextEditor
+ CheckSpelling() : bool
TextEditor
SpellChecker
Inversion of Control
• Hollywood Principle:
Don’t call me, I’ll call you
Inversion of Control
• IoC – is a common characteristic of frameworks.
• Inversion of Control serves as a design guideline.
• According to Martin Fowler the etymology of the phrase dates back to 1988.
Two principles of IOC
• Main classes aggregating other classes should not depend on the direct implementation of the aggregated classes. Both the classes should depend on abstraction.
• Abstraction should not depend on details, details should depend on abstraction.
Inversion of Controlas a Design Guideline
• Without IoC • With IoC
TextEditor
SpellChecker
TextEditor
+ CheckSpelling() : bool
SpellCheckerServ ice
+ CheckSpelling() : string
«interface»ISpellCheckerServ ice
+ CheckSpelling() : string
Loose coupling
TIME TO INJECT !
Ex3:Dependency Injection public class TextEditor { private readonly ISpellCheckerService
_spellCheckerService;
public TextEditor(ISpellCheckerService spellCheckerService)
{ _spellCheckerService = spellCheckerService; }
public string CheckSpelling() { return _spellCheckerService.CheckSpelling(); }
}
Ex3: Unit Testing DI
• Almost same as for Ex2// Mock ISpellCheckerService mock = new SpellCheckerServiceMock();
// InstantiateTextEditor textEditor = new TextEditor(mock);
// CheckAssert.AreEqual(“Mock”, textEditor.CheckSpelling());
What changed
• TextEditor lost its “Sovereignty” and is not able to resolve dependencies by himself.
What’s good
• Dependencies are obvious.• Dependency resolution is not encapsulated.• Unit Testing got little bit easier• Architecture is much better
What’s bad
• We are resolving dependencies manually while creating instances of TextEditor.
Dependency Injection
SpellCheckerServ ice
+ CheckSpelling() : bool
TextEditor
+ CheckSpelling() : bool
«interface»ISpellCheckerServ ice
Dependency Injection
• DI is IoC• Inversion of Control is too generic a term• DI pattern – describes the approach used to
lookup a dependency. • Dependency resolution is moved to
Framework.
Ex4: Unity
Ex4: Unity
using Microsoft.Practices.Unity;
UnityContainer container = new UnityContainer();
container.RegisterType<ISpellCheckerService, SpellCheckingService>();
TextEditor textEditor = container.Resolve<TextEditor>();
What changed
• Unity container now resolves dependencies
What’s good
• Automated dependency resolution
Unity methods
• RegisterType• RegisterInstance• Resolve• BuildUp
Ex5: Unity Configuration <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> </configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <alias alias="ISpellCheckerService" type="Unity.Config.ISpellCheckerService, Unity.Config" /> <alias alias="SpellCheckingService" type="Unity.Config.SpellCheckingService, Unity.Config" /> <namespace name="Unity.Config" /> <assembly name="Unity.Config" />
<container> <register type="ISpellCheckerService" mapTo="SpellCheckingService" /> </container> </unity>
Ex5: Unity Configuration
using Microsoft.Practices.Unity;using Microsoft.Practices.Unity.Configuration;
UnityContainer container = new UnityContainer();container.LoadConfiguration();TextEditor textEditor = container.Resolve<TextEditor>();
Dependency tree
Ex6: Dependency treepublic interface IAdditionalDependency{}public class AdditionalDependency : IAdditionalDependency{}
public class SpellCheckingService: ISpellCheckerService {
public SpellCheckingService( IAdditionalDependency dependency){} }
Ex6: Dependency Tree
UnityContainer container = new UnityContainer();container.RegisterType<ISpellCheckerService,
SpellCheckingService>();container.RegisterType<IAdditionalDependency,
AdditionalDependency>();TextEditor textEditor = container.Resolve<TextEditor>();
Ex6: Dependency tree
SpellCheckerServ ice
+ CheckSpelling() : bool
TextEditor
+ CheckSpelling() : bool
«interface»ISpellCheckerServ ice
AdditionalDependency
+ CheckSpelling() : bool
«interface»IAditionalDependenct
Injection Types
• Constructor Injection• Setter injection• Method call injection
Ex7: Defining Injection Constructor
public class TextEditor { private readonly ISpellCheckerService _spellCheckerService;
[InjectionConstructor] public TextEditor(ISpellCheckerService spellCheckerService) { _spellCheckerService = spellCheckerService; }
public TextEditor(ISpellCheckerService spellCheckerService,string name) { _spellCheckerService = spellCheckerService; } }
Ex8: Property Injection public class TextEditor { public ISpellCheckerService SpellCheckerService {get; set;}
[Dependency] public ISpellCheckerService YetAnotherSpellcheckerService{get;set;} } UnityContainer container = new UnityContainer(); container.RegisterType<TextEditor>(new InjectionProperty("SpellCheckerService")); container.RegisterType<ISpellCheckerService, SpellCheckingService>(); TextEditor textEditor = container.Resolve<TextEditor>();
Ex9: Method call injection public class TextEditor { public ISpellCheckerService SpellcheckerService {get; set;}
[InjectionMethod] public void Initialize (ISpellCheckerService spellcheckerService) { _spellCheckerService = spellcheckerService; } }UnityContainer container = new UnityContainer();//container.RegisterType<TextEditor>(
new InjectionMethod("SpellcheckerService"));container.RegisterType<ISpellCheckerService, SpellCheckingService>();TextEditor textEditor = container.Resolve<TextEditor>();
Lifetime Managers
• TransientLifetimeManagerReturns a new instance of the requested type for each call. (default behavior)
• ContainerControlledLifetimeManagerImplements a singleton behavior for objects. The object is disposed of when you dispose of the container.
Lifetime Managers
• ExternallyControlledLifetimeManagerImplements a singleton behavior but the container doesn't hold a reference to object which will be disposed of when out of scope.
• HierarchicalifetimeManagerImplements a singleton behavior for objects. However, child containers don't share instances with parents.
Lifetime Managers
• PerResolveLifetimeManagerImplements a behavior similar to the transient lifetime manager except that instances are reused across build-ups of the object graph.
• PerThreadLifetimeManagerImplements a singleton behavior for objects but limited to the current thread.
Ex10: Unity Singleton
UnityContainer container = new UnityContainer();container.RegisterType<ISpellCheckerService, SpellCheckingService>(new ContainerControlledLifetimeManager());TextEditor textEditor = container.Resolve<TextEditor>();
Container Hierarchy
Unity Limitations
• When your objects and classes have no dependencies on other objects or classes.
• When your dependencies are very simple and do not require abstraction.
What Unity stands for
For• Wiring framework
components
Not for• Wiring small parts
Performance
Performance
Performance
.NET DI Frameworks
• Unity 2.0• AutoFac 2.3.2• StructureMap 2.6.1• Castle Windsor 2.1• Ninject 2.0
Additional reading
Additional reading
Live Demo
QUESTIONS ?
THANK YOU !