Pages

Friday, 11 January 2019

Xamarin Forms Dependency Injection

Calling native platform code in your portable class library (PCL) is achievable via Dependency Injection. It’s a common question for people starting out, who are using a PCL or .NET Standard Library for developing their Xamarin apps. Dependency Injection involves creating an interface that can be commonly applied across all native platforms, then coding the actual implementation, or the native platform code, on each platform. This interface and instance is then given to a container. The PCL or .NET Standard Library, then goes to the container with only the interface known, to retrieve the instance. It doesn’t know where the instance came from, just that it has a specific interface.




Interface

The first thing we must do to enable dependency injection is define an interface. For this example, lets say we have to get a unique identifier for the mobile phone. There are specific calls you can make on a each platform to get this, but its not available in our PCL. Hence we would define this interface to return a string of unique identifier.
public interface IDeviceInfo
{
    string GetUniqueIdentifier();
}
This interface would be placed in your PCL and hence accessible from your PCL and each platform project.

Implementation

Next we need to actually define the implementation of this interface in each platform.

iOS

public class DeviceInfo : IDeviceInfo
{
    public string GetUniqueIdentifier()
    {
        return UIDevice.CurrentDevice.IdentifierForVendor.AsString();
    }
}

Android

public class DeviceInfo : IDeviceInfo
{
    public string GetUniqueIdentifier()
    {
        return Android.Provider.Settings.Secure.GetString(Xamarin.Forms.Forms.Context.ContentResolver,
                                                          Android.Provider.Settings.Secure.AndroidId);
    }
}

UWP

public class DeviceInfo: IDeviceInfo
{
    public string GetUniqueIdentifier()
    {
        var token = HardwareIdentification.GetPackageSpecificToken(null);
        var hardwareId = token.Id;
        var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(hardwareId);

        byte[] bytes = new byte[hardwareId.Length];
        dataReader.ReadBytes(bytes);

        return BitConverter.ToString(bytes);
    }
}

Dependency Injection Container Registration

Next we want to register this implementation with the Dependency Injection Framework. For this example, I will just use Xamarin Forms inbuilt dependency injection container. Place the following above each implementation of the DeviceInfo, above the namespace declaration.
[assembly: Xamarin.Forms.Dependency(typeof(DeviceInfo))]
namespace Mobile.Platform
{
   ...
You can also register it via a line of code, and this is actually need for UWP, as the assembly registration has issues with UWP under Native Compilation.
Xamarin.Forms.DependencyService.Register<DeviceInfo>();

Retrieve Dependency

Lets now retrieve that dependency in code. All we need to do is call this line, referencing the interface we want the implementation of.
DependencyService.Get<IDeviceInfo>().GetUniqueIdentifier();
Now we can call the GetUniqueIdentifier and it will return a string. The PCL or .NET Standard Library doesn’t know anything about the platform, and just interact with the instance via the interface definition.

AutoFac

The Xamarin Forms Dependency Service is a nice simple dependency injection framework, but it lacks many features, including the ability to do constructor injection. Using something more advanced such as AutoFac offers you many more features. There are many other Dependency Injection Frameworks out there, and they all provide very similar functionality.
To create the container, implement the following code.
ContainerBuilder _builder = new ContainerBuilder();
Now you can add dependencies as needed.
_builder.RegisterInstance<IDeviceInfo>(new DeviceInfo()).SingleInstance();
Finally you need to call the Build function to finish the building of the container.
_builder.Build();
The Container should be accessible in the PCL and native platforms, as is the interface. Similar to Xamarin Forms implementation, you can also get the

Constructor Injection

The benefits of using a Dependency Injection Framework such as AutoFac, is you can inject dependencies into a constructor. For example.
public class MyViewModel
{
    private readonly IDeviceInfo _deviceInfo;
    public MyViewModel(IDeviceInfo deviceInfo)
    {
        _deviceInfo = deviceInfo;
    }
}
If you had registered your ViewModel and DeviceInfo, in AutoFac, when AutoFac creates an instance of your ViewModel, it will automatically detect constructors with parameters and try to fill them in as needed. This has immense benefits for readability and unit testing. No longer is a dependency in your class, hidden via a line of code, its clearly apparent, as you can only create the class, if you inject the dependency into it.

Other Frameworks

You might be wondering what other frameworks are out there. First they are some MVVM frameworks that come with one included such as FreshMVVM and MVVMLight. If you prefer to keep your MVVM frameworks and Dependency Injection Framework separate, you can also use Ninject, TinyIoc, Unity, Castle Project, StructureMap and Spring.NET, just to name a few. You can do some research to find the one that best meets your needs. Personally, I prefer AutoFac, as its recent speed improvements, along with powerful interface, features and maturity make it great to work with.

No comments:

Post a Comment