Windows Phone 7 Developer Launch - Learn More
kick it on DotNetKicks.com   Shout it  

MVVM with Prism 101 – Part 5b: ServiceLocator vs Dependency Injection

Source Code

Now that we’ve seen the View-Model in Part 5, how do we wire up the View-Model to the View? As any developer worth his salt would say, “it depends” (I’m trying to raise my worth to at least the value of salt ;) ).

Inversion of Control

First, let me define a few things. First, Inversion of Control is a pattern wherein creation of objects is delegated in an effort to simplify instantiation and/or defer it until runtime. Huh? Inversion of Control is a means of programming against interfaces. Your classes reference interfaces at design-time and then delegate the creation of the concrete classes to a single component or service. The result is you now have a only a single dependency – the “Container” – instead of a complex hierarchy of dependencies:

public class ServiceA() {
    public ServiceA(){ //... }
}
public class ServiceB() {
    public ServiceB(ServiceA, ServiceD){ //... }
}
public class ServiceC(ServiceA) {
    public ServiceC(){ //... }
}
public class ServiceD(ServiceA) {
    public ServiceD(){ //... }
}
 
public class Consumer {
    private ServiceB m_ServiceB;
    private ServiceC m_ServiceC;
    
    public Consumer() {
            ServiceA serviceA = new ServiceA();
            ServiceD serviceD = new ServiceD(serviceA);
            
            m_ServiceB = new ServiceB(serviceA, serviceD);
            m_ServiceC = new ServiceC(serviceA);
    }
}

The example above is not uncommon. Not only is it difficult to test, but if any of the classes require a change in constructor parameters or you want to change which service you’re referencing you’ve got to clean up every consumer class which uses the service you just changed. We’re looking at a high level of complexity and a very brittle implementation.

Most often Inversion of Control uses an object called a “Container” which is responsible for building these dependency hierarchies. The Container allows you to defer the creation of concrete classes until runtime. At some point before your class is instantiated, the Container is configured – most often either in your startup process or in a config file – with the mappings between your interfaces and the concrete implementations of your classes. Then when you need to get a reference to the concrete implementation of an interface or just create a new instance of a standard class you use the Container to wire everything up. For example, given the example above you can do either of the following:

   1: ServiceB m_ServiceB = Container.Resolve<ServiceB>();    // Create a new instance of a concrete class
   2: ISomeInterface m_SomeObject = Container.Resolve<ISomeInterface>(); // get a concrete instance of an interface

The first example may have you saying why use Container.Resolve<ServiceB>() instead of new ServiceB()? Well, given the definitions above, you’d actually need to do this:

ServiceA serviceA = new ServiceA;
ServiceD serviceD = new ServiceD;
ServiceB m_ServiceB = new ServiceB(serviceA, serviceD);

Using the Container is much cleaner. As for line 2, you really see the power of IoC where your code isn’t tied to any concrete implementation at all. This makes testing very simple and your code becomes very, very flexible.

Dependency Injection

Here’s a term around which there can be much confusion. It seems at times that it is synonymous with Inversion of Control (IoC), a term I have used some here in this series. It is true you don’t often see one without the other, but they are not the same.

Dependency Injection refers explicitly to the way you use IoC. Constructor Injection is the form of Dependency Injection you will see used in Prism. Other forms of Dependency Injection are Setter Injection and Interface Injection. I really don’t use these and so instead of floundering for when and how to use them I’ll refer you to Martin Fowler for more on these alternative forms of Dependency Injection.

public class ServiceA() : InterfaceA {
    public ServiceA(){ //... }
}
public class ServiceB() : InterfaceB {
    public ServiceB(InterfaceA, InterfaceD){ //... }
}
public class ServiceC(InterfaceA) : InterfaceC {
    public ServiceC(){ //... }
}
public class ServiceD(InterfaceA) : InterfaceD {
    public ServiceD(){ //... }
}
 
public class Consumer {
    private InterfaceB m_ServiceB;
    private InterfaceC m_ServiceC;
    
    public Consumer(InterfaceB, InterfaceC) {
            m_ServiceB = InterfaceB;
            m_ServiceC = InterfaceC;
    }
}

In this last example all the services implement interfaces and our consumer then accepts those interfaces as arguments to the constructor. In order to call Container.Resolve<Consumer>() we need to register our services with the container. You can do this either in your Bootstrapper or an IModule implementation like this:

Container.RegisterType<InterfaceA, ServiceA>();
Container.RegisterType<InterfaceB, ServiceB>();
Container.RegisterType<InterfaceC, ServiceC>();
Container.RegisterType<InterfaceD, ServiceD>();

Now you can create an instance of the Consumer class anywhere in your application with a single line of code. Also, when you test Consumer you can replace the actual implementation of the services with mock versions which allow you to test Consumer in isolation.

Dependency Injection with Prism

So how do we use Dependency Injection in a Prism application? It’s easy, here’s how:

EditorView.xaml.cs (code behind)

using System.Windows.Controls;
using CodeCamp.Common.ViewModel;
 
namespace CodeCamp.Editor
{
    public partial class EditorView : UserControl
    {
        public EditorView(EditorViewModel model)
        {
            InitializeComponent();
 
            this.DataContext = model;
        }
    }
}

EditorModule.cs

using CodeCamp.Common.ViewModel;
using Microsoft.Practices.Composite.Modularity;
using Microsoft.Practices.Composite.Regions;
using Microsoft.Practices.Unity;
 
namespace CodeCamp.Editor
{
    public class EditorModule : IModule
    {
        private IRegionManager m_Manager;
 
        public EditorModule(IRegionManager manager)
        {
            m_Manager = manager;
        }
 
        #region IModule Members
 
        public void Initialize()
        {
            m_Manager.RegisterViewWithRegion("MainRegion", typeof(EditorView));
        }
 
        #endregion
    }
}

You should recognize the code in EditorModule.cs from part 4 of this series. Here we’re not doing anything but telling Prism to load EditorView into the MainRegion region of our Shell. From there Prism takes over by using the Unity IoC Container to create an instance of our EditorViewModel class and pass it to the EditorView constructor during the build process. Then the EditorView class takes the reference to EditorViewModel and sets it as the DataContext for the View. From there all we need to do is declare our bindings in Xaml:

EditorView.xaml

<UserControl x:Class="CodeCamp.Editor.EditorView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:cmd="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation"
    xmlns:controls="clr-namespace:CodeCamp.Common.Controls;assembly=CodeCamp.Common"
    Width="400" Height="25">
 
    <StackPanel Orientation="Horizontal">
        <StackPanel x:Name="LayoutRoot" Background="White" Orientation="Horizontal" DataContext="{Binding Path=CurrentMessage}">
            <TextBlock>Message:</TextBlock>
            <TextBox Width="200" Text="{Binding Path=Content, Mode=TwoWay}" VerticalAlignment="Top" />
            <controls:ErrorStatus PropertyName="Content" />
        </StackPanel>
        <Button Content="Send" VerticalAlignment="Top" Width="100" 
                cmd:Click.Command="{Binding SendMessage}" 
                cmd:Click.CommandParameter="{Binding Path=CurrentMessage.Content}" />
    </StackPanel>
</UserControl>

Nothing to it. You could refactor an interface from EditorViewModel. For me, sometimes I do sometimes I don’t. There isn’t a need for it, since if you’re able to keep your View clear of any logic then there isn’t anything to test. If there’s nothing to test then, in the case of the View there is no need to ever substitute a mock of EditorViewModel for the real thing. In our sample application I use interfaces because it demonstrates the principal of registering types and allowing the IoC Container to resolve those types at runtime, but unless there is a reason you need to be able to substitute concrete objects and mock objects you can keep it simple here.

ServiceLocator

With ServiceLocator you can remove the dependency on the Container. ServiceLocator is a static class with properties which expose your service interfaces. Your ServiceLocator becomes your dependency. It knows about which concrete classes map to which interfaces. When you get the value of a property ServiceLocator will return the concrete implementation:

 
public class ServiceLocator {
    public static InterfaceA { 
        get{ return new ServiceA(); }
    }
    
    public static InterfaceB {
        get{ 
            return new ServiceB(
                ServiceLocator.InterfaceA,
                ServiceLocator.InterfaceD
            );
        }
    }
    
    public static InterfaceC {
        get{
            return new ServiceC(
                ServiceLocator.InterfaceA
            );
        }
    }
 
    public static InterfaceD {
        get{
            return new ServiceC(
                ServiceLocator.InterfaceA
            );
        }
    }
}

You get the same benefits of Dependency Injection, without the dependence on the Container.

In my view Dependency Injection requires less work. With ServiceLocator you need to write the class, then you will also need to maintain a separate version of that class that returns mock objects for testing purposes. For that reason, I prefer Dependency Injection over ServiceLocator. So why bother bringing it up then?

Design-Time Databinding

ServiceLocator is great for providing sample data which can be used during design-time to allow you to be more productive. Without it you will more often than not spend a lot of time in the modify-build-run-modify cycle where every change or tweak you make requires you to run the application to see what it actually looks like. However, Blend (and now the upcoming VS 2010) has a designer which gives you a view of what your view will actually look like without running it. Blend 3 has a sample data feature which allows you to bind to a sample data source when you’re designing your view, but this requires you to maintain sample data for test scenarios as well as for the designer. Using a ServiceLocator to provide a reference to your View-Model which has been provided with mock data means you are designing your view using data that will pass through your actual View-Model. This means your design-time experience is realistic and you can have a single source of mock data that can be used for both testing and designing. \

In the sample project I am using along with this series HistoryView uses this technique.

HistoryViewModel.cs (ctor)
public HistoryViewModel(IMessageServiceAsync messageService)
{
    // store parameters as local member variables
}

MockMessageService.cs

using System;
using System.Collections.Generic;
using CodeCamp.Model;
 
namespace CodeCamp.Common.Utility
{
    public class MockMessageService : IMessageServiceAsync
    {
        #region IMessageServiceAsync Members
 
        public IAsyncResult BeginGetMessages(AsyncCallback callback, 
            object state)
        {
            return new MockAsyncResult { AsyncState = state };
        }
 
        public IList<Message> EndGetMessages(IAsyncResult result)
        {
            return new List<Message> {
                new Message { Content = "Message 1", 
                    Date = new DateTime(2009, 1, 1, 15, 02, 35) },
                new Message { Content = "Message 2", 
                    Date = new DateTime(2009, 1, 1, 15, 08, 21) },
                new Message { Content = "Message 3", 
                    Date = new DateTime(2009, 1, 1, 15, 11, 01) }
            };
        }
 
        public IAsyncResult BeginAddMessage(Message message, 
            AsyncCallback callback, object state)
        {
            return new MockAsyncResult { AsyncState = state };
        }
 
        public void EndAddMessage(IAsyncResult result)
        {
            return;
        }
 
        #endregion
    }
}

ServiceLocator.cs

using System;
using System.Diagnostics;
using CodeCamp.Common;
using CodeCamp.Common.Utility;
using CodeCamp.Common.ViewModel;
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Unity;
using CodeCamp.Model;
using CodeCamp.Common.Services;
 
namespace CodeCamp.History
{
    public class ServiceLocator
    {
        private static IUnityContainer BuildDesignTimeContainer()
        {
            IUnityContainer container = new UnityContainer();
 
            // register view models
            container.RegisterType<IMessageServiceAsync, MockMessageService>();
 
            return container;
        }
 
        private static IUnityContainer _container;
        public static IUnityContainer Container
        {
            get
            {
                if (_container == null)
                {
                    // setup container
                    _container = BuildDesignTimeContainer();
                }
 
                return _container;
            }
            set
            {
                _container = value;
            }
        }
 
        #region ViewModels
 
        public static HistoryViewModel  HistoryViewModel
        {
            get
            {
                try
                {
                    return Container.Resolve<HistoryViewModel >();
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                    return null;
                }
            }
        }
 
        #endregion
    }
 
                
}

HistoryView.xaml

<UserControl x:Class="CodeCamp.History.HistoryView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:History="clr-namespace:CodeCamp.History"
    xmlns:Common="clr-namespace:CodeCamp.Common;assembly=CodeCamp.Common"
    Width="400" Height="300">
    <UserControl.Resources>
        <History:ServiceLocator x:Key="HistoryService" />
        <Common:DateFormatConverter x:Key="DateFormatter" />
    </UserControl.Resources>
    <ScrollViewer DataContext="{Binding Source={StaticResource HistoryService}, 
                                    Path=HistoryViewModel}">
        <ListBox ItemsSource="{Binding History}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Column="0" 
                                   FontWeight="Bold" 
                                   Foreground="Green" 
                                   Text="{Binding Date, 
                                    Converter={StaticResource DateFormatter}, 
                                    ConverterParameter=H:mm:ss tt}" />
                        <TextBlock Grid.Column="1" 
                                   Text="{Binding Content}" />
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </ScrollViewer>
</UserControl>

Going backwards, notice that the ScrollViewer in HistoryView.xaml binds to the HistoryViewModel property from a static resource (defined in our UserControl) named HistoryService which is our ServiceLocator. The ServiceLocator class resolves HistoryViewModel using the Unity IoC container (I’ll explain why in a second) which injects a MockMessageService object into the HistoryViewModel object it returns to the HistoryView.

First, the reason this works is because the Xaml designer can use ServiceLocator’s static properties. The ServiceLocator class doesn’t need to be instantiated and so the designer is able to get the sample data and use it to render the view as it would be seen at runtime with live data.

DesignTimeDatabinding

Second, the reason I’m using an IoC Container when I said ServiceLocator doesn’t need it is because what this allows me to do is set the ServiceLocator.Container property at runtime from the Bootstrapper or duing IModule.Initialize. So at design-time I get a Container with mock objects from the ServiceLocator.BuildDesignTimeContainer method and at runtime I get my container with my real concrete objects and production services without having to change anything. So while ServiceLocator is a little more work, when you need design-time data it is worth the effort.

One last important thing to note with ServiceLocator, you will want to create it in the same project where your View(s) is (are) located. The reason for this is you don’t want to have to create references between different Modules because you want your Modules to be completely independent of one another. Because of this the best way to maintain this clean separation is to have a single ServiceLocator in each project where it is needed. Your mock classes can be located in your Common project and you should have everything you need without creating unnecessary dependencies between Modules.

Conclusion

We’ve covered quite a bit of ground at this point in our series. This last post should help you understand how to wire up your View to your View-Model. If you’re wondering when you’d want to use which technique, or thinking why you wouldn’t want design-time data binding (I know I asked that one when I first discovered this technique) I’ll tell you what I do. If your View requires you to build your project, run it and navigate to the view to see how it looks with a larger font size then you’ll be more productive with ServiceLocator. If you know your View will look the same in the designer as it does at runtime, then save yourself some effort and just use Dependency Injection.

Next I’ll be tackling Commands and along with Commands we’ll be looking at the best way to create a Web Service Client for your application.

Source Code

tags: , , , , , , ,

kick it on DotNetKicks.com   Shout it  

Feedback

# re: MVVM with Prism 101 – Part 5b: ServiceLocator vs Dependency Injection

Gravatar Nice article, again!

I don't like the idea of having to duplicate the ServiceLocator code for every single project though. Luckily DI will do the job for me.

Thanks.

Cheers,
Kevin
11/2/2009 8:37 AM | Kevin

# re: MVVM with Prism 101 – Part 5b: ServiceLocator vs Dependency Injection

Gravatar Kevin, I agree with you about duplication of code - it seems to me there could be a better way. I'd prefer if it didn't take so much code. However, it seems to me that it can still save a considerable amount of time when you compare the time spent to write the ServiceLocator with the time spent to rebuild and run the application so you can see how your changes look when the application runs. The ServiceLocator only need be written once and then unless you need to add new services you never have to touch the Service Locator code. 11/2/2009 1:48 PM | MarkJMiller

# re: MVVM with Prism 101 – Part 5b: ServiceLocator vs Dependency Injection

Gravatar Great post. It seems that discussion of ServiceLocator would benefit from discussion of the factory pattern as well. How are factory and servicelocator alike or different? 11/3/2009 6:47 AM | Jeremy Likness

# re: MVVM with Prism 101 – Part 5b: ServiceLocator vs Dependency Injection

Gravatar Jeremy, thanks for the feedback. But I really don't see where the benefit would be. It would seem to me that the discussion would simply muddy the waters and add confusion to users who are new to the concept of IoC. Even Fowler, when discussing IoC didn't mention factories. I chose to include DI and ServiceLocator because those are the standard patterns developers will see across any MVVM implementation. 11/4/2009 7:50 AM | MarkJMiller

# re: MVVM with Prism 101 – Part 5b: ServiceLocator vs Dependency Injection

Gravatar Excellent post! I always enjoy a solid technical post (and code) It saved me a good week+ - Keep up the good work! 1/4/2010 6:39 AM | Rapid Share

# re: MVVM with Prism 101 – Part 5b: ServiceLocator vs Dependency Injection

Gravatar I am looking at so many samples. Every one pretty much create one view == one project .Do you guys create module(Project) for each view. I feel like at the end of year we may end up with 100's project. If we are not saying each view is a module how do we define a module .Is it some thing like interrelated views together.So please...... 2/5/2010 12:14 AM | bonus de jeux

# re: MVVM with Prism 101 – Part 5b: ServiceLocator vs Dependency Injection

Gravatar Just to reduce the complexity. Inversion of control is simply saying that rather than the object instantiate a dependent object, that object is passed into the object. This 'inverts' the relationship. A container is separate, but when introduced handles the instantiation, creating the corresponding implementation from the injected interface.

It's not putting the dependency on the container. (unless you do something silly like use container.resolve). These classes don't reference or even know a container exists 2/8/2010 5:21 AM | Steve

# re: MVVM with Prism 101 – Part 5b: ServiceLocator vs Dependency Injection

Gravatar "The result is you now have a only a single dependency – the “Container” – instead of a complex hierarchy of dependencies"

Steve, you're right. The above statement is wrong. There is no dependency on the container in the class. What I meant by the statement is that your project now has a dependency on an IoC container. However the class in question (and in the example) does not. 2/8/2010 12:32 PM | MarkJMiller

# re: MVVM with Prism 101 – Part 5b: ServiceLocator vs Dependency Injection

Gravatar bonus de jeux - d'abord, arretes de mettre des liens pour casinos dans les commentaires.

As for the module/view relationship, it is a one-to-many relationship. You can have as many related views together in a single module as you like. The reason you see one-to-one in demos is because they are simplified examples. Look at the prism reference applications that come with the documentation and you'll see you can have multiple views in a module. 2/8/2010 2:23 PM | MarkJMiller

# re: MVVM with Prism 101 – Part 5b: ServiceLocator vs Dependency Injection

Gravatar Hi,
I am developing Application with Prism + Silverlight + WCF.
Can you send me very simple application how to use WCF with Prism in silverlight.

plz email me at
nvintt@gmail.com
nvintt@yahoo.com. 2/10/2010 12:36 PM | Vineet

# re: MVVM with Prism 101 – Part 5b: ServiceLocator vs Dependency Injection

Gravatar Hi Mark Nice article about MVVM Prism, I liked the Controller part it has been really confusing to me.
I am developing a Prism SL App in which i am calling WCF services(Async) from Controller and and publishing the Data(returnvalue such as cusstomer details etc) to VM and attaching this to View (by usin INotify). I think this is not right way to do, instead to use Model at client side and updating it( i am not sure).

Can u give some feed back so that help mee go in right Direction. If possible with some Sample(links, blogs or code).

Thanks
Raghav 4/5/2010 11:22 PM | Raghav

# re: MVVM with Prism 101 – Part 5b: ServiceLocator vs Dependency Injection

Gravatar @Raghav - Read thru the whole series. Or if you're just interested in communicating with WCF look at parts 6 and 6b on commands. If you'd like to look at a sample, all the posts in the series point to sample source code. Download the source code and have a look. 4/6/2010 9:18 AM | MarkJMiller

# www.rebelmouse.com

Gravatar MVVM with Prism 101 - Part 5b: ServiceLocator vs Dependency Injection 10/21/2014 8:42 PM | www.rebelmouse.com

Comments have been closed on this topic.
 

 

Copyright © Mark J. Miller