Dependency injection

Post on 24-May-2015

6.866 views 0 download

Tags:

Transcript of Dependency injection

Embarrassing coupling problem?

Let’s solve that with

Cory House@housecor | bitnative.com

Dependency Injection

Here’s the plan

• Why• Composition root• Injection locations• Poor man’s DI• Contrast IoC containers• Configuration styles• Lifestyles• Anti-patterns• Cross-cutting concerns

Tightly coupled

Loosely coupled

Inversion of Control

Dependency InjectionASP.Net Page Lifecycle

Why DI?Object compositionTestability Maintainability Lifetime ManagementPerformance Late bindingExtensibilityParallel developmentCross-cutting concerns (AOP)

SOLID

Code to an abstraction, not an implementation

Interfaces

Tightly coupled

Loosely coupled

Collaborating classes should rely on infrastructure to provide services.

Demo: Poor man’s DI

Is new evil?

var user = new User()

Watch for Volatility

new StringBuilder()new List<T>()System.Xml

App specificnew User, Product, Order

Non-deterministicDateTime.Now, File, Data

SlowRemote service

Composition Root

• Where the app “starts”• Classes are composed here• Keeps app unaware of the IoC container • Unique techniques for different techs

Composition RootTechnology Composition Root

Console App Main method

ASP.NET MVC Call custom IControllerFactory in Global.asax

WCF ServiceHostFactory and a few other tricks

ASP.NET Web Forms Humble object or Service Locator in each aspx.cs

Register, Resolve, Release

Injection Location

1. Constructor2. Property3. Method

Location Usage Benefits Drawbacks

Constructor When possible SimpleGuarantees injectionExplicit

Tricky (some frameworks)Object graph on startup

Property Good local default Easy to understand Not simple to implement

Method Dependency varies by method call

Caller provides operation specific context

Limited applicability

Config Styles1.XML2.Code (aka fluent)3.Auto-registration

Demo: Config Styles

Config StylesMapping Advantages Disadvantages

Config Late binding

Control

No compile-time checks

VerboseCode Compile-time checks

Control

Intellisense

Must recompile

Rules Late binding

Automatic = Less work

Reinforces conventions

Partial compile-time checks

Less control

Magic

XML

Code

Auto-Registration

Config Style SupportStyle Castle Windsor StructureMap Spring.Net Autofac Unity

XML X X X X X

Code X X X X

Auto-registration X X X

XML Code as Configuration

Late Binding Early Binding

Explicit

Implicit

Auto Registration

LifestylesLifestyle Description Usage

Singleton Once on App startup. Most efficient.

Thread safe, stateless, immutable, circuit breaker, in-memory cache

Transient Per Request. Least efficient. Default (most)

Per Graph One instance of each dependency per thread

Anywhere thread that resolves is the only consumer of the graph. Efficient alt to transient.

Web Request Context

One instance per web request Web app requests when singleton won’t work

Thread Context Per thread

Session Context Per session

Pooled Pool of ready objects Expensive to create

Scoped

Custom

Lifestyle SupportLifestyle Castle

WindsorStructureMap Spring.Net Autofac Unity

Singleton X X X X X

Transient X X X X X

Per Graph X X

Web Request Context

X X (X) X

Thread Context

X X X

Session Context

X (X)

Pooled X

Scoped X X

Custom X X X

Warning

Windsor: SingletonStructureMap: Transient

Release transients or burn all RAM

Demo: Coupling

Control Freak

Control Freak: Solutions

• Factory – moves problem to another class

• Static factory that calls config – No easy way to inject mock for unit testing.

• Constructor or property injection

Service Locator: Anti-pattern?

Service Locator: Ask for

dependencyDI: Consumer

supplies dependency

Demo: Service Locator

Problems with Service Locator

• Hides dependencies• IoC container tightly coupled• Drags in other modules if IoC container is in

separate module

Anti-Patterns: Bastard Injection

ForeignDefault

Bastard Injection

1. Overloaded constructor = ambiguity2. Often introduces foreign dependency3. Hinders parallel development

• Fix– Foreign default: Constructor injection– Local default: Property injection

Other Anti-Patterns

• Factory that references config• Constructor over injection• MVC’s Idependency Resolver• Abstracting away your container• Web Forms

Cross-Cutting Concerns

Presentation

Domain

Data

Auditing,Logging,Security,

Etc.

Cross-cutting concerns

Problems:AuditingLoggingSecurityError handlingPerf MonitoringCachingFault tolerance

Solution: Dynamic Proxies Decorator PatternHonor SRP Honor Open/Closed

Cross-cutting concerns

Two approaches:1. Dynamic Proxies2. IL Weaving

PostSharp

Attributes Normal Compilation

PostSharp Compilation

.Net Assembly

AOP via attributes

1. Modify compilation• PostSharp

2. Custom runtime host • WCF• ASP.Net MVC• Unit testing frameworks

AOP via attributes

• No special design effort• Easy to spot since inline• Explicit since in context

• Code runs different from the code you wrote

• Vendor lock-in • Attributes compiled with

code = Tightly coupled.• Can’t vary the aspect

independently of the implementation

• Can’t use conventions

How do I choose a container?

PerformanceLifetimesDocumentationAPISupportDynamic proxies

Summary

1. Compose at composition root2. Prefer constructor injection, auto-registration3. Volatility? Think smoke detectors vs sockets

Next Steps

@housecor | bitnative.com

Thanks for listening!

To Do

• Remove references to data layer(s) in MVC project. Surprising that ploeh did it in his, but clearly a risky issue since it means others might tightly couple

• Add checks in project to protect from bad refs.