Post on 24-May-2015
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
Example project on GitPerformance Benchmarks
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.