locked
Is it possible to inject platform specific dependencies usin Unity? RRS feed

  • Question

  • User326332 posted

    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();

    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?

    Thursday, May 25, 2017 4:22 PM

All replies

  • User76049 posted

    Yes,

    Prism will do that for you I believe.

    http://prismlibrary.readthedocs.io/en/latest/Xamarin-Forms/5-Dependency-Service/

    Thursday, May 25, 2017 4:28 PM
  • User116727 posted

    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

    Thursday, May 25, 2017 5:10 PM
  • User326332 posted

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

    Thursday, May 25, 2017 10:07 PM
  • User116727 posted

    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

    Thursday, May 25, 2017 10:17 PM
  • User326332 posted

    Thank you for sharing that.

    Friday, May 26, 2017 11:49 PM
  • User262191 posted

    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() RegisterType() RegisterType()

    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) >:)

    Tuesday, June 13, 2017 7:58 AM
  • User262191 posted

    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() RegisterType() RegisterType()

    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! ;)

    Tuesday, June 13, 2017 8:04 AM
  • User116727 posted

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

    Tuesday, June 13, 2017 6:48 PM