Forum Xamarin.Forms

Is it possible to inject platform specific dependencies usin Unity?

NwikNwik PTMember ✭✭

Hi guys, I'm currently trying to use Unity for dependency injection in a Xamarin Forms project, mainly because of constructor injection support, and came accross
an issue.
I'll try to be as detailed as I can be without posting thousands of lines of code.
Sorry for the long post but I think this can be usefull for a lot of people.

Let's say I have a three layer application structured in the following solution:

1 - Presentation Layer
Presentation.Common Project (PCL)
Presentation.Android Project
Presentation.iOS Project
Presentation.UWP Project

2 - Application Layer
Services Project (PCL)
Models Project (PCL)

3 - Data Layer
Data.Common Project (PCL)
Data.Android Project (Android Class Library)
Data.iOS Project (iOS Class Library)
Data.UWP Project (Universal Windows Class Library)

On the Presentation Layer we have the standard Xamarin Forms cross platform projects.

The Application Layer has all the application logic (services, models, etc).
I do this mainly too keep my Application Layer independent of the technology being used. There are no references to Xamarin on this layer.

The Data Layer mimics the structure of the Presentation Layer due to the fact that each platform deals with data in a different way.

Now let's say I add references to all PCL projects in my Presentation.Common so that I can setup and configure Unity.
After doing this I can successfully inject services implementation, and corresponding contructor dependencies, in my Presentation.Commom project.
On my Application Layer I can also inject components defined on the Data.Commom project without any issues.

Now comes the interesting part.
Let's say I want my application to communicate with a device through USB port. Each platform deals with serial communication differently, wich means that I have to define
an interface on my Data.Common project, like this:

public interface IUSBClient
{
    bool ConnectToDevice();
}

and then add an specific implementation to each of the platform specific data projects.

public class USBClient : IUSBClient
{
    public bool ConnectToDevice()
    {
        // Do stuff
    }
}

If I try to reference the platform specific Data projects on my Presentation.Commom project, so that I can configure the Unity depndencies, I get an error because the projects have different runtimes (the Presentation.Commom is a PCL the other are platform specific).
The idea was to be able to configure the Unity dependencies like this:

switch(Device.RuntimePlatform)
{
    case Device.iOS : unityContainer.RegisterType<IUSBClient, iOS.USBClient>();
    case Device.Android : unityContainer.RegisterType<IUSBClient, Android.USBClient>();
    case Device.Windows : unityContainer.RegisterType<IUSBClient, Windows.USBClient>();
}

This would allow me to inject the platform specific USBClient as a contructor dependency by simply doing this:

public USBGateway(IUSBClient usbClient)
{
    this.usbClient = usbClient;
}

Using the Xamarin Forms Dependency Service i could simply do this:

public USBGateway()
{
    this.matClient = DependencyService.Get<IMatClient>();
}

But this has three disadvantages.
First I lose the ability to inject the dependency on the constructor.
The second is that, at the date of this post, there's a bug in the dependency annotations in Xamarin Forms, and to get around it I need to go to each of the platform specific Presentation projects and add the dependencies in the startup class, like this:

Xamarin.Forms.DependencyService.Register<Platform.USBClient>();

The third disadvantage is that I would need to use two different dependency injection providers, on for the commom functionalities and another for the platform specific dependencies.

All of this to ask this, does anyone know how I can inject platform specific implementations on a PCL using Unity?

Answers

  • NMackayNMackay GBInsider, University admin
  • BrianLagunasBrianLagunas USInsider ✭✭✭✭

    Prism actually provides a better way to register platform dependencies by using the IPlatformInitializer. You can register your types directly against the container in each project: https://github.com/PrismLibrary/Prism/blob/master/Sandbox/Xamarin/HelloWorld/HelloWorld/HelloWorld.Droid/MainActivity.cs#L32

  • NwikNwik PTMember ✭✭

    Thank you both for answering.
    If i can't find a solution for Unity I'll definitely give Prism a shot.

  • BrianLagunasBrianLagunas USInsider ✭✭✭✭
    edited May 2017

    Just so you know, Prism uses Unity out of the box :)

    If you are getting started with Prism and you're on a Windows machine, use this https://marketplace.visualstudio.com/items?itemName=BrianLagunas.PrismTemplatePack

  • NwikNwik PTMember ✭✭

    Thank you for sharing that.

  • MichaelHferMichaelHfer USMember
    edited June 2017

    Hi Brian,

    might there be an Example for Azure Blob Storage?

    I am trying to implement an easy AzureBlobStorage with Prism Unity. I've already implemented an AzureMobileServiceSQL.
    What would be the best way of implementing the Platformspecific code?
    Now of what I heard I will try registering the PlatformSpeficTypes in the NativePCL .

    I am thinking of needing an IFileHandler or something like that.

    This for each NativeProject in the IPlatformInitializer:
    RegisterType<MyAzurePCL.IFileHandler, MyNativeImplentationAndroid>()
    RegisterType<MyAzurePCL.IFileHandler, MyNativeImplentationIOS>()
    RegisterType<MyAzurePCL.IFileHandler, MyNativeImplentationWIN>()

    then when I call the ViewModel which needs the FileHandler I can just say as normal with constructor injection

    IFileHandler _myNativeImplemtation;
    MyAzureViewModel(IFileHandler myNativeImplementation){
    _myNativeImplemtation = myNativeImplementation;
    }

    and Prism will provide me the the Platformspecific injection or do I have to make some "Resolve" in here to get the right one?

    Thanks in advance!

    I <3 PRISM (and Magic Strings) >:)

  • MichaelHferMichaelHfer USMember

    Hi Brian,

    I've already implemented AzureMobileServiceSQL and now I want to include AzureBlobService.
    For that I need (as I heard) PlatformSpecific code.
    For sure I am using PRISM Unity (I <3 IT) also the MagicStrings...

    So if I register my Types in the PlatformSpecific

    RegisterType<MyAzurePCL.IFileHandler, myAndroidImplement>()
    RegisterType<MyAzurePCL.IFileHandler, myWINImplement>()
    RegisterType<MyAzurePCL.IFileHandler, myIOSImplement>()

    and then in the ViewModel which needs the IFileHandler I say

    IFileHandler _myFileHandler
    MyViewModel(IFileHandler myFileHandler){
    _myFileHandler = myFileHandler
    }

    will _myFileHandler then the PlatFormSpecific IFileHandler or do I have to make some kind of resolve ?!

    Thanks in Advance.

    Maybe there is an AzureBlobStorage Example with Xamarin.Forms & Prism Unity out there? If so please tell me.

    Cheers! ;)

  • BrianLagunasBrianLagunas USInsider ✭✭✭✭

    @MichaelHfer it will work just fine as long as your dependencies are properly registered with the container.

Sign In or Register to comment.