Dependency Injection або Don’t call me, I’ll call you

Preview:

DESCRIPTION

 

Citation preview

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

Recommended