DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Data Engineering
  3. Data
  4. Service Locator in MVVM

Service Locator in MVVM

Marlon Grech user avatar by
Marlon Grech
·
Sep. 07, 09 · News
Like (0)
Save
Tweet
Share
7.44K Views

Join the DZone community and get the full member experience.

Join For Free

While doing MVVM one of the common problems to solve is to have the ViewModel consume entities that are “replaceable”. Let me give you an example so that you can better understand what I mean by “replaceable“. Let’s say you have a ViewModel that is using a DataAccess entity to get some data from a data store. You want to be able replace the DataAccess entity so that you can mock this entity for unit testing. Besides this you want to also be able to have some sample data while at design time. And not to forget, when at runtime you want the data access to connects to the database or whatever data store you are using.

In order to do solve this problem I use the ServiceLocator pattern. The Service Locator pattern is very simple. You have a RegisterService method where you register the instance of the service you want to provide and a GetService method which you would use to get the service you want.

Here is the signature of both methods:

public T GetService<T>()

public bool RegisterService<T>(T service)

And here is how to use them in code:

//get the data access service
var dataAccess = GetService<IPeopleDataAccess>();

//Register the data access service
vm.ServiceLocator.RegisterService<IPeopleDataAccess>(new PeopleDataAccess());

So for example to test the the ViewModel I can write a unit test like this:

MainViewModel viewModel = new MainViewModel();
viewModel.ServiceLocator.RegisterService<IPeopleDataAccess>(new PeopleDataAccessMock());

Assert.AreEqual(viewModel.People.Count, PeopleDataAccessMock.PeopleCount, "Invalid number of People returned");
Assert.AreEqual(viewModel.People[0].Name, PeopleDataAccessMock.FirstPersonName, "Invalid item in people list");
Assert.AreEqual(viewModel.People[0].Surname, PeopleDataAccessMock.FirstPersonSurname, "Invalid item in people list");

So basically in this unit test I am just creating a mock object and testing that my ViewModel is exposing the data from the data access (which is mocked so the data returned by this data access is known in the test context)

This is all cool but now how can I use this in WPF and MVVM. So the first question that people ask is how do I create the ViewModel and set it as the DataContext. And also who is responsible of assigning the services that the ViewModel will consume. In order to do this I use AttachedBehaviour and the Factory design pattern.

I created a simple attached property that accepts a type of a Factory that is responsible for creating the ViewModel and register whatever services it needs. The attached property is very simple, here is the code for it:

public class ViewModelLoader
{
#region FactoryType

/// <summary>
/// FactoryType Attached Dependency Property
/// </summary>
public static readonly DependencyProperty FactoryTypeProperty =
DependencyProperty.RegisterAttached("FactoryType", typeof(Type), typeof(ViewModelLoader),
new FrameworkPropertyMetadata((Type)null,
new PropertyChangedCallback(OnFactoryTypeChanged)));

/// <summary>
/// Gets the FactoryType property. This dependency property
/// indicates ....
/// </summary>
public static Type GetFactoryType(DependencyObject d)
{
return (Type)d.GetValue(FactoryTypeProperty);
}

/// <summary>
/// Sets the FactoryType property. This dependency property
/// indicates ....
/// </summary>
public static void SetFactoryType(DependencyObject d, Type value)
{
d.SetValue(FactoryTypeProperty, value);
}

/// <summary>
/// Handles changes to the FactoryType property.
/// </summary>
private static void OnFactoryTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = (FrameworkElement)d;
IFactory factory = Activator.CreateInstance( GetFactoryType(d) ) as IFactory;
if (factory == null)
throw new InvalidOperationException("You have to specify a type that inherits from IFactory");
element.DataContext = factory.CreateViewModel(d);
}

#endregion

}

and you can use this in XAML like so:

<Window x:Class="ServiceLocatorSample.Main"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:MVVMHelper.Factory;assembly=MVVMHelper"
xmlns:fac="clr-namespace:ServiceLocatorSample.ViewModels.Factories"
Title="Main" Height="300" Width="300" vm:ViewModelLoader.FactoryType="{x:Type fac:MainViewModelFactory}">

Usually in the implementation of the factory I would check if the current state is at design time or runtime and accordingly register different services. Something like this:

public class MainViewModelFactory : IFactory
{
public object CreateViewModel(DependencyObject sender)
{
var vm = new MainViewModel();
if (Designer.IsDesignMode)
vm.ServiceLocator.RegisterService<IPeopleDataAccess>(new DesignTimeData.DesignTimePeopleDataAccess());
else
vm.ServiceLocator.RegisterService<IPeopleDataAccess>(new PeopleDataAccess());
return vm;
}
}

So with this factory at design time I would get Design time data showing in my designer but as soon as I run the app the actual data access (the real one that connects to the database) gets injected.

That’s it for today. Download the sample project and you will have a better idea of how all this works. Any questions or comments please let me know, I will be more than happy to answer.

P.S In the sample I have the full MVVMHelper assembly that I use in my everyday work with MVVM so you will also have stuff like Mediator and other things that I will be blogging about very soon.

Download the sample project

 

unit test Data access Data (computing) Database

Published at DZone with permission of Marlon Grech. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How and Why You Should Start Automating DevOps
  • Securing VMs, Hosts, Kubernetes, and Cloud Services
  • Writing a Modern HTTP(S) Tunnel in Rust
  • SAST: How Code Analysis Tools Look for Security Flaws

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: