SlideShare a Scribd company logo
Tamir Dresher
Senior Software Architect
March 2015
Leveraging Dependency Injection(DI) in
Universal Application
About Me
• Software architect, consultant and instructor
• Software Engineering Lecturer @ Ruppin Academic Center
• Technology addict
• .NET and Native Windows Programming
@tamir_dresher
tamirdr@codevalue.net
http://www.TamirDresher.com.
Where? Everywhere!
3
Class Dependencies
• Class can depend on other classes
– Services
– Entities
– Components
4
How do we get the dependencies
• Instantiating
– I must know the concrete class
– What if that class has dependencies of its own?
• Using a Factory Class
– Now I have a dependency on the Factory
• Using a Singleton
– Now I have a Dependency on the singleton
– Now I must know that it is a singleton
5
Demo
Universal Application
6
Example
7
public MainPageViewModel()
{
_lectureManager = new LectureManager();
var rootFrame = Window.Current.Content as Frame;
_navigationService = new NavigationService(rootFrame);
Lectures = new ObservableCollection<LectureDay>();
}
Example – Deeper in the chain
8
public LectureManager()
{
_mdevconService = new MdevconService.MdevconService();
}
Universal Applications
• Sharing Code is fun
• Sharing Code saves time
• Sharing Code eliminate bugs – NOT!
9
Universal Applications – Sharing is Fun
10
Universal Applications – Sharing is Fun (Sometimes)
11
public void OpenLecture(Lecture lecture)
{
#if WINDOWS_APP
_navigationService.Navigate<LectureInfoPage>(lecture);
#else
_navigationService.Navigate<LecturePage>(lecture);
#endif
}
}
Universal Applications - Issues
• Sharing code between projects
• Using non portable libraries
12
Dependency Inversion Principle
1. “High level modules should not depend on low level modules.
Both should depend on abstractions”
2. “Abstractions should not depend on details. Details should
depend on abstractions”
( The Dependency Inversion Principle, Robert C. Martin, C++ Report, May 1996 )
13
All the dependency resolving methods we discussed breaks DiP
We Broke DiP
14
MainPageViewModel
LectureManager
MdevconService
High
Low
Redesigning with DiP
15
MainPageViewModel
LectureManager
MdevconService
High
Low
IMdevconService
ILectureManager
Dependency Injection and Inversion Of Control
• Instead of Creating or Resolving my dependencies myself
Inject me those dependencies from outside.
• Three primary techniques
– Construction injection
– Property injection
– Parameter injection
16
Redesigning to DI
• Before:
17
public LectureManager(IMdevconService mdevconService)
{
_mdevconService = mdevconService;
}
public LectureManager()
{
_mdevconService = new MdevconService.MdevconService();
}
• After:
Dependency injection/IoC Container
• A class that is responsible to instantiate other classes
• Provide dependencies to created instances
• Manage Instances Lifetime
• Think of it as a big Dictionary from type to instance(s)
18
Known ContainersKernels
• Autofac
• Ninject
• Unity
• MEF
• StractureMap
• Windsor
19
Configuring the Container
• Nuget: Install-Package Autofac
• Register Types
20
// Create the builder with which components/services are registered.
var builder = new ContainerBuilder();
// Register types that expose interfaces...
builder.RegisterType<ConsoleLogger>.As<ILogger>();
// Build the container to finalize registrations
// and prepare for object resolution.
var container = builder.Build();
Demo
Configuring the IoC Container
21
Platform Specific Code
• Open a File
22
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
await openPicker.PickSingleFileAsync();
Platform Specific Code – WP8.1
• Open a File
23
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
openPicker.PickSingleFileAndContinue();
Platform Specific Classes
24
builder.RegisterType<WinFilePickerService>()
.As<IFilePickerService>()
.SingleInstance();
builder.RegisterType<WPFilePickerService>()
.As<IFilePickerService>()
.SingleInstance();
Lifetime Scope
• Per DependencyTransient
• Single instance
25
builder.RegisterType<ConcreteClass>();
// ...is the same as this:
builder.RegisterType<ConcreteClass>().InstancePerDependency();
builder.RegisterType<ConcreteClass>().SingleInstance();
Lifetime Scope – Per LifetimeScope
26
builder.RegisterType<ConcreteClass>().InstancePerLifetimeScope();
using(var scope1 = container.BeginLifetimeScope())
{
var first = scope1.Resolve<ConcreteClass>();
// same instance as first
var second = scope2.Resolve<ConcreteClass>();//Same as first
}
Registering Types
27
builder.RegisterType<DebugLogger>.As<ILogger>();
builder.RegisterInstance(new NavigationService(rootFrame)).As<INavigationService>();
builder.RegisterType<FirstViewModel>().AsSelf();
builder.RegisterType<FirstViewModel>().AsSelf();
builder.RegisterType<SecondViewModel>().AsSelf();
builder.RegisterType<ThirdViewModel>().AsSelf();
:
:
builder.RegisterType<LastViewModel>().AsSelf();
Registering Types – Assembly Scanning
28
builder.RegisterAssemblyTypes(typeof(MainPageViewModel).GetTypeInfo().Assembly)
.Where(t => t.Name.EndsWith("ViewModel"))
.AsSelf();
builder.RegisterAssemblyTypes(typeof(ClassInLibrary).GetTypeInfo().Assembly)
.Except<MyUnwantedType>()
.AsImplementedInterfaces();
Modules
• Separation on Concerns
29
class CommonClassesModule:Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterType<LectureManager>().As<ILectureManager>().SingleInstance();
builder.RegisterType<DummyMdevconService>().As<IMdevconService>().SingleInstance();
}
}
builder.RegisterModule<CommonClassesModule>();
builder.RegisterAssemblyModules(assembly);
DI Traps – Cyclic Dependencies
30
class ErrorReporter:IErrorReporter
{
public ErrorReporter(IMailClient mailer)
{
}
}
class MailClient : IMailClient
{
public MailClient(IErrorReporter reporter)
{
}
}
Cyclic Dependencies – Using Lazy
31
class ErrorReporter:IErrorReporter
{
public ErrorReporter(
Lazy<IMailClient> lazyMailer)
{
_lazyMailer=lazyMailer
}
}
class MailClient : IMailClient
{
public MailClient(
Lazy<IErrorReporter> lazyReporter)
{
_lazyReporter=lazyReporter;
}
}
_lazyMailer.Value.Send(…); _lazyReporter.Value.Report(…);
Cyclic Dependencies – Property Injection
32
class MailClient : IMailClient
{
public MailClient()
{}
public IErrorReporter ErrorReporter
{
get; set;
}
}
class ErrorReporter:IErrorReporter
{
public ErrorReporter()
{}
public IMailClient MailClient
{
get; set;
}
}
builder.RegisterType<MailClient>()
.As<IMailClient>()
.SingleInstance ()
.PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies);
Summary
• Follow the OODP
• There is no replacement for good Architecture
• DI is not a Silver Bullet
• Maintainability
• Speed
• Thank You!
33
Presenter contact details
t: @tamir_dresher
e: tamirdr@codevalue.net
b: TamirDresher.com
w: www.codevalue.net

More Related Content

Leveraging Dependency Injection(DI) in Universal Applications - Tamir Dresher