dependency injection або don’t call me, i’ll call you
DESCRIPTION
TRANSCRIPT
Dependency Injection with Unity 2.0
Dmytro MindraRnD Tech Lead
Lohika
AGILEBASECAMPLviv, 2011
Goal
• Get DI understanding
Plan
• Inversion of Control (IoC)• Dependency Injection pattern (DI)• Dependency inversion principle• Unity 2.0, StructureMap• Guice, Spring• Live ASP.NET MVC 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.• Code quality ( What’s Bad ) R.Martin 1996
- Rigid (hard to modify)- Fragile ( errors occur on almost every change)- Immobile (not reusable)
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.
OLD SCHOOL (PRE DI STYLE)
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
Better approach
TextEditor
+ CheckSpelling() : bool
SpellCheckerServ ice
+ CheckSpelling() : string
«interface»ISpellCheckerServ ice
+ CheckSpelling() : string
Dependency Inversion
A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend upon details. Details should depend upon abstractions.
Robert C. Martin 1996
Context
Granny
+ Eat() : void
«interface»IAppleProv ider
+ GetApple() : IApple
RedAppleProv ider
+ GetApple() : IApple
GoldenAppleProv ider
+ GetApple() : IApple
«interface»IPillProv ider
ConcretePillProv ider
Context
Ex2:Loose Coupling public class TextEditor { private readonly ISpellCheckerService
_spellCheckerService;
public TextEditor(ISpellCheckerService spellCheckerService)
{ _spellCheckerService = spellCheckerService; }
public string CheckSpelling() { return _spellCheckerService.CheckSpelling(); }
}
Ex2: Unit Testing
// 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 is applicable• Architecture is much better
What’s bad
• We are resolving dependencies manually while creating instances of TextEditor.
Wiring By Hand
Using Factory
FactoryTextEditorFactory
+ GetEnglishTextEditor() : TextEditor+ GetFrenchTextEditor() : TextEditor
TextEditor
FrenchSpellCheckerServ ice
«interface»ISpellCheckerServ ice
EnglishSpellCheckerServ ice
What changed
• Any required combination of Text Editor and Spell Checking Service is created by object factory.
What’s good
• It’s testable• No manual wiring
What’s bad
• You have to maintain factory or service locator• The more combinations the more methods we
have in factory.• Your code knows about the specific factory or
factory interface. This means that infrastructure logic is mixed with business logic.
• Factory may have states.
Service Locator
Unfortunately, being a kind of Factory, Service Locators suffer from the same problemsof testability and shared state.
What are we looking for?
Inversion of Control
• Hollywood Principle:
Don’t call me, I’ll call you
Inversion of Control
• IoC – is a common characteristic of frameworks.
• According to Martin Fowler the etymology of the phrase dates back to 1988.
Dependency Injection
• DI is a kind of 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.
SpellCheckerServ ice
+ CheckSpelling() : bool
TextEditor
+ CheckSpelling() : bool
«interface»ISpellCheckerServ ice
We have alreadyprepared basis.
Loosely coupled structure
It’s time to introducenew role
Injector (sometimes referred to as a provider or container)
Depedndecy Injection
DI in general consists of • a dependent consumers• their service dependencies• and an injector
Unity
Ex3: 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• Business logic and infrastructure are
decoupled.
Injection Types
• Interface injection (by Martin Fowler)• Constructor Injection (by Martin Fowler)• Setter injection (by Martin Fowler)• Method call injection (Unity)• Method decorator injection (Guice)
Unity methods
• RegisterType• RegisterInstance• Resolve
• BuildUp
Ex4: 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>
Ex4: Unity Configuration
using Microsoft.Practices.Unity;using Microsoft.Practices.Unity.Configuration;
UnityContainer container = new UnityContainer();container.LoadConfiguration();TextEditor textEditor = container.Resolve<TextEditor>();
Dependency tree
Ex5: Dependency treepublic interface IAdditionalDependency{}public class AdditionalDependency : IAdditionalDependency{}
public class SpellCheckingService: ISpellCheckerService {
public SpellCheckingService( IAdditionalDependency dependency){} }
Ex5: Dependency Tree
UnityContainer container = new UnityContainer();container.RegisterType<ISpellCheckerService,
SpellCheckingService>();container.RegisterType<IAdditionalDependency,
AdditionalDependency>();TextEditor textEditor = container.Resolve<TextEditor>();
Ex5: Dependency tree
SpellCheckerServ ice
+ CheckSpelling() : bool
TextEditor
+ CheckSpelling() : bool
«interface»ISpellCheckerServ ice
AdditionalDependency
+ CheckSpelling() : bool
«interface»IAditionalDependenct
Ex6: 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; } }
Ex7: 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>();
Ex8: 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.
Ex9: 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.
Performance
Performance
Performance
What DI stands for
For• Wiring framework
components
Not for• Wiring small parts
STRUCTURE MAP
Structure Map Example
// BootstrapContainer container = new Container(x => x.For<ISpellCheckingService>(). Use<FrenchSpellCheckingService>());// UseTextEditor textEditor = container.GetInstance<TextEditor>();
Compared to Unity
// BootstrapUnityContainer container = new UnityContainer();container.RegisterType<ISpellCheckingService,
EnglishSpellCheckingService>();
// Using containerTextEditor textEditor = container.Resolve<TextEditor>();
Unity vs StructureMap
Unity• XML Configuration• In Code configuration• Attributes
• Benefits– Easy code initialization– Good documentation
StructureMap• XML Configuration• In Code configuration• Attributes
• Benefits– Http & Session lifetime
managers out of the box.– Convenient XML
configuration.
.NET DI Frameworks
• Unity 2.0• AutoFac 2.4.3• StructureMap 2.6.1• Castle Windsor 2.5.3• Ninject 2.0
SCOPE, CONTEXT, LIFETIME
Singleton scope
• Singleton scoped objects lifetime is bound to injector lifetime.
Difference
• Singleton scoped object vs. singleton anti pattern
No scope
Connection pool
Web request scope
• HTTP protocol is stateless and web request scope is quite natural for web applications
Session scope
• Session is an abstraction that hides HTTP stateless nature. Such scope should be used carefully.
CIRCULAR REFERENCES
Circular References
• Objects depend on each other forming cycle in dependency graph.
General case
• A depends on B• B depends on A
Introducing proxy
Diagram
• Dynamic proxy is constructed
A B
«interface»A
«interface»B
«interface»Proxy A
Sequence
• 1. Instantiate Proxy A• 2. Instantiate B using Proxy A• 3. Instantiate A using B from step 2• 4. Initialize Proxy A with A• Proxy A passes all requests to concrete A
GRANNY AND APPLESREINJECTION
G&A Diagram
• Granny receives concrete apple via injection.• Granny eats apple
Granny
+ Eat() : void
«interface»IApple
RedApple
GoldenApple
G&A Sequence
• Granny needs apples for proper operation• New apples should be injected runtime
G&A Solution
• Instead of single apple we should inject apple “provider”
Granny
+ Eat() : void
«interface»IApple
RedApple
GoldenApple
«interface»IAppleProv ider
+ GetApple() : IApple
RedAppleProv ider
+ GetApple() : IApple
GoldenAppleProv ider
+ GetApple() : IApple
G&A New Sequence
Drawback
• If you want produced instances to be configured by general injection rules then your factories will depend on concrete injection framework.
• Google Guice has special interface to support such behavior but you’ll depend on google Guice.
• No silver bullet.
GUICE AND SPRING
History
• Spring project brought DI to mainstream.• And thank Spring Guice appeared.• Guice introduced new features and stimulated
further Spring development.• Now Guice and Spring are almost equal in DI
field and which one to use depends on developer.
Spring
• Spring holds a huge DI market share. More than 80%.
• Proven enterprise solution• DI is only a small part of its functionality• Supports all major injection approaches• Current version 3
Guice
• New kid on the block• Introduced new features based on Java 5
support. ( e.g. Provider methods to circumvent type erasure)
• First-class error messaging.• Very fast.• Provides only DI• Current version 2 ( Version 3 RC )
Spring or Guice
• In DI Spring and Guice are almost equal.• Guice provides only DI• DI in Spring is only a part of functionality• Google extensively uses Guice• Guice is trendy and developers just want to
give it a try.• So which framework to use heavily depends
on project and concrete developer ( team)
Where to use Guice
• If you are sure that you do not need full Spring functionality and your project is not a huge enterprise level application then you can give it a try.
• Spring is standard de facto in the industry.
Patterns
• Builder• Wrapper• Adapter• Abstract Factory and Factory method
Additional reading
Additional reading
Live Demo
ASP.NET MVC
QUESTIONS ?
THANK YOU !
References
1. Martin Fowler – Dependency Injectionhttp://martinfowler.com/articles/injection.html2. DI Comixhttp://www.bonkersworld.net/2010/08/11/programmers-only-shaving-who/3. Consultants comixhttp://stuffthathappens.com/blog/2007/09/26/comic-tribute-to-crazy-bob/4. R. Martin - Dependency Inversion principlehttp://www.objectmentor.com/resources/articles/dip.pdf