Layered Dependency Injection

Introduction

In a tiered architecture with Dependency Injection we have the problem that the bootstrapper or initialization section of your main project doesn’t have a reference to every project we need to inject into our container.  Therefore we end up referencing projects for the sole purpose of injecting them into the container. While there is technically no harm in doing this,
it creates the opportunity that you or another developer might reference a lower tiered project, breaking your tiered architecture. In order to ensure we don’t break the tiers I use an approached of layered dependency injection.

layereddependencyinjection

Proxy the Injection Framework

To make this work we don’t want to reference the Dependency Injection Container and Framework through every tier of our project. Instead we can use the Proxy pattern to separate the dependencies. Create an IInjection interface in a project that is referenced by all your other projects, normally I have a Mobile.Abstractions project. Below is a limited view.

public interface IInjection
{
    void RegisterInterface<I, T>() where T : class, I
                                   where I : class;
}

Using AutoFac, though you can use any Dependency Injection framework, we create a proxy for the injection framework. This ensures your application only needs to reference the Dependency Injection framework and not any of your dependencies.

public class Injection : IInjection
{
    private static ContainerBuilder _builder = null;
    public void Init()
    {
        if (_builder == null)
        {
            _builder = new ContainerBuilder();
        }
    }
    public void Complete()
    {
        if (Container == null)
            Container = _builder.Build();
    }

    public void RegisterInterface<I, T>(InstanceType type) where T : class, I
                                                           where I : class
    {
        _builder.RegisterType<T>().As<I>().SingleInstance(); 
    }
}

Register Lower Dependencies

As per the image example above you can see that a dependency is referenced outside the reach of the application. We now create a Register method in the Service, that passes the IInjection reference through. The service is now responsible for handling all of its dependencies.

public class Dependency
{
    public static void Register(IInjection injection)
    {
        injection.RegisterInterface<IDatabase, Database>();
    }
}

Native Platform Injection

We have seen how we go down the dependency chain but we also need to register platform specific dependencies, hence we need to go up. For this purpose we create an IPlatformBootstrapper interface, with a register method that accepts the IInjection reference.

public interface IPlatformBootstrapper
{
    void Register(IInjection injection);
}

Create an instance off this interface in your native application and pass it down in the LoadApplication.

LoadApplication(new App(new PlatformBootstapper));

Bootstrapper

The bootstrapper is a class manually created in your Xamarin Forms project that handles all the registration of services. It is also created as a singleton for easy access later. This class will register everything above and directly call any register call from lower levels.

public class Bootstrapper
{
    private static Bootstrapper _instance = null;
    private static Injection _injection = new Injection(); // This is your proxied Injection class
    public static Bootstrapper GetInstance(IPlatformBootstrapper platformBootstrapper)
    {
        if (_instance == null)
            _instance = new Bootstrapper(platformBootstrapper);

        return _instance;
    }

    private Bootstrapper(IPlatformBootstrapper platformBootstrapper)
    {
        // Register platform specific dependencies.
        platformBootstrapper?.Register(_injection);

        //Register any other dependencies that your app references
        // Get the service layer to register its own dependencies
        Service.Dependency.Register(_injection);

        // Complete the container build (this is an AutoFac thing)
        _injection.Complete();
    }
}

Loading The App

Finally in your App.xaml.cs (or App.cs) you would create the Bootstrapper and register all dependencies.

public partial class App : Application
{    
    public readonly IInjection InjectionContainer;
 
    public App(IPlatformBootstrapper platformBootstrapper)
    {
        InitializeComponent();

        MainPage = new ContentPage();

        InjectionContainer = Bootstrapper.GetInstance(platformBootstrapper).Init();
    }
}

Learn More

XamarinMobileArchitecture is a sample GitHub project that shows this pattern in a Xamarin Forms project.


XAMARIN.FORMS MONTHLY NEWSLETTER

JOIN 1,100+ SUBSCRIBERS

  1. Don't miss out on updates
  2. The latest info from this site, Xamarin and the community
  3. Unsubscribe at any time*

* We use MailChimp, with double opt-in, and instant unsubscribe

Microsoft MVP | Xamarin MVP | Xamarin Certified Developer | Exrin MVVM Framework | Xamarin Forms Developer | Melbourne, Australia

Related Posts