Patterns for Referencing Dependencies in Cross Platform Development

There are many ways to obtain a reference to a dependency in programming. You may have heard of patterns called Service Locator, Constructor Injection, Static Instances or even PubSub. All of these are valid patterns and have their uses, but there are also many incorrect ways to use them.

architecture

Service Locator

Service Locator is a pattern you will see many argue over online. Is it a pattern, is it an anti-pattern? The answer is both, depending upon how you use it. ServiceLocator is a great way to get non-related dependencies in a common function that injects them into another class or object, but never uses them itself. Hence if you are writing a dependency injection framework, or function, like my StaticInitialize, it is a solid use of that pattern. If you are using it in a ViewModel or Model to pull in a dependency of that class, this is an incorrect usage, as it hides your classes dependencies.

// Similar to..
<container>.GetInstance<IDependency>()

Constructor Injection

Constructor Injection is one of the best ways to inject dependencies into a class. The constructor will define a list of dependencies it requires, and it can not even be constructed without them. The dependencies are kept in an IoC container, via the dependency injection framework you are using. Code based on the service locator pattern, then obtains these dependencies, and uses them to construct the object.

public class CustomClass(IDependency dependency) {}

Its always good to use an interface to define the contract of your class, to ensure you abstract away the implementation details.

Static or Instance Injection

The next way you might see dependencies injected, is via a property on an instance or assigning to a static instance. For example, say we have a CustomButton, that has the function DoSomethingPlatformSpecific. In this function we want to call something in the CustomRenderer, to perform a platform specific task. The best way to accomplish this would be to inject the function into the custom button.

In your CustomRenderer, you would create a function that performs this platforms specific action, however in order of the CustomButton to call it you will need to provide this function to the CustomButton

((CustomButton)e.NewElement).DoSomethingPlatformSpecific = () => {
   // Do something platforms specific here.
}

You may now wonder, isn’t the renderer now tightly coupled to the button? In terms of the button knowing what is happening in the renderer, the answer is no, because all the Custom button knows, is it has a function it can call. In terms of the reference, yes they are coupled, but this isn’t a bad thing. When is a CustomButton active and its renderer needs to be disposed of? When the button is alive, so is the renderer. When the button is disposed, so is the renderer.

PubSub

PubSub is a pattern standing for Publish and Subscribe. You may know the implementation in Xamarin Forms as the MessagingCenter. As you may also know, I don’t like the MessagingCenter due to its common misuse. The MessagingCenter allows two separate, non-related entities to talk to each other. It is simply a static global object, that any object can communicate with, anywhere in your app. I think of it as a glorified global static variable in your main App.cs.

The common example Xamarin will use is when communicating with two different ViewModels. Why two different ViewModel’s are communicating in the first place is another mystery, but the better way to handle that would be to store the state or result in a common Model they both share, and for the other ViewModel to reference it when it is loading. Or use an MVVM framework, that support parameters when moving between different pages.

The valid use for this pattern, is for allowing two non-related entities to communicate. What defines a non-related entity and how far they are separated logically in your app, will depend on whether it is a valid use.

Summary

Use PubSub, ServiceLocator very sparingly, if not at all. I never use these patterns in application development. Use Instance Injection, in cases where objects are already tightly coupled, such as the case of the renderer and element. Finally, Constructor Injection, will most likley be the most used way to inject dependencies throughout your app, keeping each class easily unit testable and abstracted from implementation.

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

Related Posts

4 Comments

  1. scyle

    Hi Adam,

    what would you do if you need dependency injection in a template, control or converter? Constructor Injection via x:Arguments in xaml could be possible (i assume; did not test it) but then you would need to add the dependency to the resources dictionary at some point which feels off.
    Are there other options?

    regards scyle

    1. Adam Pedley

      For that issue, I created a Static Initialization method. https://xamarinhelp.com/static-initialization/

      Its not perfect, but its better than arguments in XAML. I use this for Markup Extensions or UI Controls. Very similar to how dependency injection works, just that it static initializes them, but at least it keeps its references private.

      Its unfortunately the only best other option when the class construction is out your control.

    1. Adam Pedley

      Basically Paul is saying the same thing as I am, except he likes Service Locator with Constructor Injection as a specific pattern to reduce startup speed.

      However, that post is a little old. I tend to find DI Frameworks are lazy loaded these days, or at least the ones I use. They are only constructing upon first call/construction, not registration, hence the argument of using Service Locator for a speed boost, is a moot point in that regard.

Leave A Comment?