Sam Debruyn

Cloud Data Solution Architect

Specialized in Microsoft Azure, Fabric & modern data stack. Microsoft Data Platform MVP. Public speaker & meetup organizer. FOSS contributor.

Sam Debruyn

Dependency injection with Autofac and MVVM Light in Xamarin

5 minutes

You gotta have MVVM

A developer and his tools are inseparable. We all like SOLID and every (.NET) developer has his or her favourite dependency injection tool. There is a lot to choose from. I like Autofac because of the way it handles modules, the lifetime of a type and how it registers types.

At the moment I am working on an app for Android, iOS and Windows Phone with Xamarin and when you’re developing an app in C#, you’ll really want to use MVVM. You can either go the hard way and use the built-in classes, you can go the easy way and use a framework like Caliburn Micro or you can go the comfortable way and use MVVM Light . MVVM Light is a toolkit. It comes with everything you need and nothing more. It doesn’t force a pattern upon you, you can use the parts you like and safely ignore everything else. Want to get started with MVVM Light? Make sure to read Nico’s practical guide .

MVVM Light comes with an IoC container called SimpleIoC. And that’s what it is: a dead-simple IoC container. As I said: you don’t have to use the parts you don’t like. So let me replace SimpleIoC with my dependency injector of choice: Autofac.

Architecture

This is an overview of how I usually structure my solution:

 1Legend:
 2* project
 3  - namespace
 4    + class/interface
 5
 6
 7* MyApp (PCL)
 8  - MyApp.Utilities
 9    + MyApp.Utilities.ViewModelLocator
10    + MyApp.Utilities.CrossPlatformModule
11  - MyApp.ViewModels
12  - MyApp.Services
13    + MyApp.Services.ICrossPlatformService
14    + MyApp.Services.IPlatformSpecificService
15    + MyApp.Services.MyCrossPlatformServiceImplementation
16    + ...
17  - ...
18* MyApp.Android
19  - MyApp.Android.Utilities
20    + MyApp.Android.Utilities.PlatformModule
21  - MyApp.Android.Services
22    + MyApp.Android.Services.MyPlatformSpecificServiceImplementation
23    + ...
24  - ...
25  + App
26* MyApp.iOS
27  - MyApp.iOS.Utilities
28    + MyApp.iOS.Utilities.PlatformModule
29  - MyApp.iOS.Services
30    + MyApp.iOS.Services.MyPlatformSpecificServiceImplementation
31    + ...
32  - ...
33  + Main
34* MyApp.WindowsPhone
35  - MyApp.WindowsPhone.Utilities
36    + MyApp.WindowsPhone.Utilities.PlatformModule
37  - MyApp.WindowsPhone.Services
38    + MyApp.WindowsPhone.Services.MyPlatformSpecificServiceImplementation
39    + ...
40  - ...
41  + App
42* MyApp.UnitTests
43  - ...
44    + ...

Where to put what?

How it all ties together

First off, you start by creating interfaces for all the services you need. Next up, you can start defining implementations for the services and put them in the correct namespaces.

When that’s done, it’s time to create our modules. Now, assembly scanning sometimes causes exceptions on certain platforms. Also, PCL’s don’t have the methods you’re used to from ASP.NET or other types of projects for assembly scanning. I know it makes things incredibly easy, but I’d advise against it for Xamarin projects. You’ll have to register type by type in the modules. Usually I create an array of types and throw them in builder.RegisterTypes(types). The platform-specific modules should contain registrations for the platform-specific services. Don’t forget the ones that come with Autofac by default.

Example of a platform-specific service

 1using System;
 2using Autofac;
 3using MyApp.Android.Services;
 4using GalaSoft.MvvmLight.Views;
 5
 6namespace MyApp.Android.Utilities
 7{
 8    public class PlatformModule : Module
 9    {
10        protected override void Load(ContainerBuilder builder)
11        {
12            var navigationService = new NavigationService();
13            // navigationService setup...
14            builder.RegisterInstance(navigationService).AsImplementedInterfaces();
15
16            Type[] types =
17            {
18                typeof (DialogService),
19                typeof (MyPlatformSpecificServiceImplementation)
20            };
21            builder.RegisterTypes(types).AsImplementedInterfaces();
22        }
23    }
24}

I think you get my point. The module in your PCL should contain all the cross-platform services and the ViewModels. Don’t forget to use .SingleInstance() where you think it’s applicable (e.g. where you use HttpClient or with some ViewModels).

When that’s done, it’s time to use a little bit of magic to make sure the right implementations are registered in the right platform. This can be a little bit tricky and it isn’t a very clean solution, but It Does The Job (tm).

Laurent, the creator of MVVM Light, gave a talk at Xamarin Evolve explaining how he makes it work on Android, iOS and Windows Phone. On Android, you make a singleton class called App while you use the Application and App classes on Windows Phone and iOS.

But first, we need to create our ViewModelLocator. Microsoft’s ServiceLocator and Autofac’s extra’s make things easier so all you need is nuget Install-Package Autofac.Extras.CommonServiceLocator.

 1public class ViewModelLocator
 2{
 3    // you only need this if you'd like to use design-time data which is only supported on XAML-based platforms
 4    static ViewModelLocator()
 5    {
 6        if (!ServiceLocator.IsLocationProviderSet)
 7        {
 8            RegisterServices(registerFakes: true);
 9        }
10    }
11
12    public MyViewModel MyViewModel => ServiceLocator.Current.GetInstance<MyViewModel>();
13
14    public static void RegisterServices(ContainerBuilder registrations = null, bool registerFakes = false)
15    {
16        var builder = new ContainerBuilder();
17
18        // you only need this if-clause if you'd like to use design-time data which is only supported on XAML-based platforms
19        if (ViewModelBase.IsInDesignModeStatic || registerFakes)
20        {
21            builder.RegisterModule<FakeServiceModule>();
22        }
23        else
24        {
25            // just use this one if you don't use design-time data
26            builder.RegisterModule<CrossPlatformModule>();
27        }
28
29        var container = builder.Build();
30        registrations?.Update(container);
31
32        ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(container));
33    }
34}

Now in all of the mentioned app initializers mentioned above I have a method that looks like this:

1private static void RegisterServices()
2{
3    var builder = new ContainerBuilder();
4    builder.RegisterModule<PlatformModule>();
5    ViewModelLocator.RegisterServices(builder);
6}

That method is then called at the moment I initialize the ViewModelLocator. Laurent’s talk goes in depth on how to do that so I won’t cover that part.

ServiceLocator

Whenever you need an instance of a registered type, you can use the ServiceLocator like so:

1var myService = ServiceLocator.Current.GetInstance<IMyService>();

You’ll only need this in the (usually empty) code-behind parts like activities (Android), ViewControllers (iOS) or the page classes (Windows Phone).

You can even use factories as long as you register them.

1var myVar = "some required constructor parameter for e.g. a ViewModel";
2var factory = ServiceLocator.Current.GetInstance<MyViewModelRequiringAParameter.Factory>();
3var vm = factory(myVar);

You might also like

If you liked this article, follow me on LinkedIn, Bluesky, or other social media to stay up-to-date with my latest posts. You might also like the following 2 posts about related topics:

Queue for MessageDialog in Windows RT

1 minutes

When I write Windows Store applications, I use MessageDialog a lot. It’s the easiest way to show a quick informative pop-up message or a question to the user. However, when you tend to use this quite often, you’ll probably run into a problem. The Windows Runtime framework doesn’t allow you to stack MessageDialogs, queue them etc.