Using a Dependency Injection Container in Xamarin Forms Labs

0 Flares Twitter 0 Facebook 0 StumbleUpon 0 Google+ 0 LinkedIn 0 0 Flares ×

Xamarin Forms Labs - Dependency Injection

Using a dependency injection (DI) container in your Xamarin Forms app can make developing it a lot smoother and your code a lot cleaner. Inversion of control (IOC) is integral (in one form or another) to Xamarin Forms and Xamarin Forms Labs, so implementing it in a standard and recognised ways is a huge benefit.

In this article I’m going to show you how to use a dependency injection container in your app, by building on “Getting Started with Xamarin Forms Labs“, demonstrating a basic usage. I’ll follow this article with several other articles that show how to hook up various DI containers that are supported by Xamarin Forms Labs.

I apologies for the amount of acronyms used in this article! I do my best to keep it to a minimum but this area is riddled with them!

The full sample projects are available on GitHub.

DI Containers and Xamarin Forms Labs

Over the last few years dependency injection containers have become a standard part of most projects, and for good reason. Whilst they can be complicated to manage at first, they can simplify the creating and management of dependencies tremendously. Anyway, I don’t want to get into the DI container debate!

The first thing to understand is that IOC is integral to any Xamarin Forms app. Anywhere that you’re using the Xamarin Forms DependencyService, you’re effectively leveraging an in-built service locator – which is an IOC pattern. Generally speaking DI has become the preferred pattern for IOC, as it requires that all components within your app make it very clear what dependencies they have.

Xamarin Forms Labs has DI throughout its MVVM framework, so it makes sense to make use of it. We actually hooked up the most basic DI container in getting started with xamarin forms labs – the SimpleContainer. In fact the ViewFactory makes use of the underlying container to register its views and viewmodels ViewFactory.Register<MainView,MainViewModel>(); and then create the pages ViewFactory.CreatePage<MainViewModel>().

Abstracting away the DI container with the Resolver

One thing that’s really important to understand is that Xamarin Forms Labs abstracts away the underlying DI container, so the interface is the same when using that container in your main project, regardless of which container you’re using.

The interface is represented by the static Resolver class, which you should recognise from the previous tutorial with the lines:

These lines create a new SimpleContainer, and assign it as the resolver for the project. This means that the SimpleContainer is used to resolve all dependencies throughout the project.

What this means is that outside of your dependency registration code, you should never refer to the SimpleContainer directly. Primarily you should resolve all dependencies using either Resolver.Resolve, or get a reference to the IDependencyContainer (which we’ll come to later).

Using the SimpleContainer

The most basic dependency injection container is the SimpleContainer, which is fine in a lot of cases. As previously mentioned the last article showed how to create the SimpleContainer and assign it as the Resolver in the SetIoc method (which appeared in all 3 projects – Android, iOS and Windows). The code in SetIoc was completely the same in all 3 projects, with the exception of a couple of extra lines in the Windows Phone project:

You may ask why we write the same code for all 3 environments – the answer is that when we come to set-up our container, most of the dependencies will be different for each project. Those dependencies that are the same can be registered in the main app project separately.

Displaying device information

Understanding IDevice

In order to work through an example, I’m going to add something about the device to the message on our previous examples ViewModel. To do this I’ll need access some device specific information, which I can get at using the Xamarin Forms Labs Device object.

Xamarin Forms Labs provides a convenient Device object for each environment represented by AppleDevice.CurrentDevice, AndroidDevice.CurrentDevice and WindowsPhoneDevice.CurrentDevice. Each of these implement the common IDevice interface, but the implementation is within the device specific library.

For example whilst IDevice is in the XLabs.Platform assembly that is shared across all projects, AndroidDevice.CurrentDevice is in the XLabs.Current.Droid assembly, that is only used by the Android project. And this is where IOC and DI come in!

Using IDevice using Dependency Injection

So to get access to the current platforms device object, we must register it in each project and inject it using our DI container.

  1. To registering the IDevice using the SimpleContainer we amend the SetIoc method in each project by adding the following line immediately after creating the container:

    • Android: resolverContainer.Register<IDevice>(r => AndroidDevice.CurrentDevice);
    • iOS: resolverContainer.Register<IDevice>(r => AppleDevice.CurrentDevice);
    • WinPhone: resolverContainer.Register<IDevice>(r => WindowsPhoneDevice.CurrentDevice);
    • The SetIoc should look something like this:

  2. Next we add a constructor parameter to the MainViewModel so it can access the device information:

    • Add a constructor parameter for IDevice
    • Assign that parameter to a private member variable
    • Amend the message to include some device related information
    • The MainViewModel should look something like this

Most DI containers support automatic dependency injection, where the container will automatically attempt to resolve any constructor arguments it knows about. The SimpleContainer doesn’t do this because…well…its simple! So we have to explicitly tell the container how to create the view model.

The simplest way to achieve this is in our SetIoc method. In each platforms SetIoc, immediately after out previous registration we add resolverContainer.Register<MainViewModel>(r => new MainViewModel(r.Resolve<IDevice>()));. The full method should look something like this:

This registration registers the MainViewModel in the container and also uses a lambda expression to tell the container how to construct it (i.e. by resolving the IDevice as the first constructor argument). Once this is complete in each project you should be good to go and you should see something like this:

Genymotion emulator with IDevice dependency working

Wrapping up

The truth is that a lot of the benefit you get from a DI container is the automatic dependency injection, so the SimpleContainer isn’t helping us out as much as we’d like. That said getting up and running with the SimpleContainer is quick, lightweight and simple – so its generally where I start when firing up a new Xamarin Forms project.

In my next post I’ll show you how to hook up some other DI containers such as Ninject and Autofac. These containers offer more features and therefore greater benefit.

Are you using DI in your apps? Which container are you using, if any?

The full sample projects are available on GitHub.

, ,

  • hal9k2

    I am interested navigation between views (pages) and passing object between them on different platforms. Did you try this?

    • Yes, its pretty straight forward once you know how!

      The general approach (I think) is to have an Initialize method on you ViewModel that accepts arguments of the types you want to pass. Then in the navigate method you provide a lambda expression that passes the object through.

      • Miroslav Smukov

        Hi,

        First of all, thank you for your articles, I managed to implement everything successfully by following your guides, however, this parameter passing issue is still bugging me…

        I’m using the following code when navigating between pages from within a ViewModel:
        NavigationService.NavigateTo();

        This is good enough when I don’t have to pass any parameter to ViewModel, but what should I do when I do have to pass it?

        Any other suggestion on how to navigate between pages is welcomed, it doesn’t have to be with NavigationService.NavigateTo as long as my ViewModel doesn’t have to know about any Page(View).

        Thanks,
        Miroslav

        • Hey Miroslav – to pass parameters your viewmodels must inherit from XLabs.Forms.Mvvm.ViewModel. Then I usually set-up an initialise method on the target viewmodel that accepts the parameter. Finally, rather than using NavigationService directly, use the Navigation object available on the view model base.

          For example, my target viewmodel mioght look like this:

          public class OrderDetailViewModel : XLabs.Forms.Mvvm.ViewModel
          {
          public void Init(int orderId){
          //Do something here
          }
          }

          And the source viewmodel like this:

          public class OrderListViewModel : XLabs.Forms.Mvvm.ViewModel
          {
          public Order SelectedOrder {get; set;}

          public void OrderSelected(){
          Navigation.PushAsync((vm, v) => vm.Init(SelectedOrder.Id));
          }
          }

          Then the Navigation object takes care of immediately callijng the Init method when it instantiates the viewmodel.

          Its a simplified example but I hope it makes sense

          • Miroslav Smukov

            This is perfect, thank you!

  • JasonBSteele

    Great article! I have a load of Services in my PCL that I want to register. I want to be DRY so I wouldn’t want to register them in the platform code, I would rather do it in the PCL App constructor.

    However, the Xlabs TinyIoC package isn’t installed to the PCL, don’t have a reference to it, and Resolver doesn’t have a Register method.

    Do I have to do all my registrations in the platform? (That would seem rather restrictive)

    • Hi Jason,

      One option you do have is register your dependency container as an IDependencyResolver, something like this (this might not be 100% correct as I dont have the code in front of me right now):

      You can then resolve this in your PCL project and register things there

  • Sebastian Olaf

    Hi Matt
    Why the 1st example did not have a register ?

    resolverContainer.Register(r => new MainViewModel(r.Resolve()));

    since the 1st example don’t have parameter,
    shouldn’t it be like this ?

    resolverContainer.Register(r => new MainViewModel());

    Sorry am new with this Container thing.

The Essential App Marketing Kit
Subscribe To My Newsletter To Get an Entire Chapter From The Book for FREE
Never display this again
0 Flares Twitter 0 Facebook 0 StumbleUpon 0 Google+ 0 LinkedIn 0 0 Flares ×