This talk introduces the concepts of factories, strategy pattern, Inversion of Control, dependency injection and several of the available frameworks. We'll also look at common dependency injection patterns and various IoC/DI frameworks, the pros & cons, practical steps and guidance as well some of the real world scenarios with impact to unit testing and application architecture.
First presented at the Ft. Worth .NET Users Group on March 15th, 2016 - http://developingux.com/2016/03/14/code-to-di-for-in-ft-worth/ - Code will be posted to my GitHub soon! https://github.com/calebjenkins/ (Talks.Code-to-DI-For)
6. “The single greatest thing that you can do to make your
code more testable and healthy is to start taking a
Dependency Injection approach to writing software”
- Real World .NET, C# and Silverlight
Wrox Press 2012
Caleb Jenkins
16. public class DoubleOSuperSpy
{
public void StopDrEvilWithSpyWatch()
{
// Stop Dr. Evil
}
public void StopDrEvilWithSpyCar()
{
}
public void SaveQueenWithSecretCrocodile()
{
}
// Etc...
}
17.
18. public interface ISecretAgent
{
void RunMission(ISecretMission Mission);
}
public interface ISpyGadget
{
void UseGadget(string Target);
} public interface ISecretMission
{
}
public class SpyWatch : ISpyGadget
public class StopDrEvilMission : ISecretMission
public class DoubleOSuperSpy : ISecretAgent
19. public class DoubleOSuperSpy : ISecretAgent
{
private ISpyGadget spyWatch;
private IMission stopDrEvil;
public DoubleOSuperSpy()
{
spyWatch = new SpyWatch();
stopDrEvil = new StopDrEvilMission();
}
public void RunMission()
{
spyWatch.UseTo(stopDrEvil);
}
}
Separation of Concerns
+
Grouping of Features
=
Strategy Pattern
20. public class DoubleOSuperSpy : ISecretAgent
{
private ISpyGadget spyWatch;
private IMission stopDrEvil;
public DoubleOSuperSpy()
{
spyWatch = new SpyWatch();
stopDrEvil = new StopDrEvilMission();
}
public void RunMission()
{
spyWatch.UseTo(stopDrEvil);
}
}
Interfaces
=
Looser Coupling
21. public class Factory
{
public static ISecretAgent GetSecretAgent()
{
// Check config
return new DoubleOSuperSpy();
}
public static ISecretGadget GetSpyGadget()
{
// Check config
return new SpyWatch();
}
public static ISecretMission GetSecretMission()
{
// Check Config
return new StopDrEvilMission();
}
}
A Factory
37. <factoryconfig type="Improving.ProviderFactory, ProviderFactory">
<factories>
<factory interface=“ISpyGadget" assembly=“Acme.MI6" class=“LaserSpyWatch“ />
<factory interface=“ISecretAgent" assembly=“Acme.MI6" class=“DoubleOSuperSpy”>
<params>
<param name=“Name" value=“Bond, James” type="System.String"/>
</params>
</factory>
<factory interface=“ISecretMission" assembly=“Acme.MI6" class=“StopDrEvilMission“
lifespan=“singleton”>
</factory>
</factories>
</factoryconfig>
Dependency Injection
Configuration Concepts
* Note: This is a conceptual configuration and not specific to any
IoC / di framework. Some IoC’s don’t use config, like Ninject that
relies on special [attributes] for mappings
38. public class DependencyConfigModule : StandardModule
{
public override void Load()
{
// Factory
Bind<IFactory>().To<factory>().Using<SingletonBehavior>();
// Models
Bind<ISecretAgent>().To<DoubleOSuperSpy>().Using<TransientBehavior>();
Bind<ISecretMission>().To<StopDrEvilMission>().Using<TransientBehavior>();
Bind<ISpyGadget>().To<LaserSpyWatch>().Using<TransientBehavior>();
}
}
Dependency Injection
Configuration Concepts
* Note: This is a conceptual configuration and not specific to any
IoC / di framework. Some IoC’s don’t use config, like Ninject that
relies on special [attributes] for mappings
39. public class DependencyConfigModule : StandardModule
{
public override void Load()
{
// Factory
Bind<IFactory>().To<factory>().Using<SingletonBehavior>();
// Models
Bind<ISecretAgent>().To<DoubleOSuperSpy>().Using<TransientBehavior>();
Bind<ISecretMission>().To<StopDrEvilMission>().Using<TransientBehavior>();
Bind<ISpyGadget>().To<LaserSpyWatch>().Using<TransientBehavior>();
}
}
<factoryconfig type="Improving.ProviderFactory, ProviderFactory">
<factories>
<factory interface=“ISpyGadget" assembly=“Acme.MI6" class=“LaserSpyWatch“ />
<factory interface=“ISecretAgent" assembly=“Acme.MI6" class=“DoubleOSuperSpy”>
<params>
<param name=“Name" value=“Bond, James” type="System.String"/>
</params>
</factory>
<factory interface=“ISecretMission" assembly=“Acme.MI6" class=“StopDrEvilMission“
lifespan=“singleton”>
</factory>
</factories>
</factoryconfig>
Dependency Injection
Configuration Concepts
Implementation Mapping
Simple Property Injection
Property Injection
Constructor Injection
Instantiation Model:
Singelton
Transient
Pool
* Note: This is a conceptual configuration and not specific to any
IoC / di framework. Some IoC’s don’t use config, like Ninject that
relies on special [attributes] for mappings
Interceptors / Listeners
Per Thread
Generics
43. The mission has begun
Dr. Evil has been stopped!
It took :22 seconds!
Interceptors and Listeners
44. Stop Dr. Evil
Dynamic Proxy
Security must be
licensed to kill
(007)
Logging Bond is
about to begin
mission
Interceptors and Listeners (AOP)
Multi-Threading
Invoke UI Thread
45. Longest running “complete stack”
Windsor Container
Dynamic Proxy
Active Record (nHibernate)
ASP.NET Mono Rail
Visual Studio Tooling
Well Established Community
Integrates with ASP.NET MVC
ASP.NET | Sharepoint
Winforms | WPF | WCF | WF |
Console Apps
castleproject.org
46. springframework.net
“Spring Framework” is THE way to
do JAVA development
Spring .NET is the .NET equivalent
Nice bridge for Java Spring
developers moving to .NET
Interface 21
47. ninject.org
DI “gateway drug”
Light weight / super fast to configure
DI (Integrates with Castle for IoC / AOP)
.NET
Silverlight
Windows Mobile/Phone
No XML Config
(Fluent Config)