When using a container for dependency injection in your Xamarin.Forms app, you may find yourself trying to use a plugin or library that is static
that you want to register with your container. Having static
s in our code makes it hard to test and causes coupling. In this post, I will demonstrate using Prism.Forms how to inject a static
plugin or library that may or may not expose an abstraction.
In Xamarin cross-platform world, plugins and libraries are abundantly available and used, which is a good thing since we do not need to reinvent the wheel in most cases i.e. Settings, Location, Permission, etc., can be handled by using a reliable plugin (like those from Xamarin) or other well supported libraries. Some provide an abstraction (interface) to be used to get the implementations, others do not. So, let’s see how we can inject both of these types of libraries or plugins.
Note: For simplicity, I am going to lump ‘Plugin’ and ‘Library’ into ‘library’, and ‘Abstraction’ and ‘Interface’ into ‘interface’.
The MVVM-Friendly Statics
Some libraries such as Xamarin’s Setting Plugin and Connectivity plugin expose interface such as ISettings
and IConnectivity
that we can register with our container for injection. In Prism.Forms, we can simply register and instance of these libraries with our container,
protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterInstance<ISettings>(CrossSettings.Current); containerRegistry.RegisterInstance<IConnectivity>(CrossConnectivity.Current); }
and that’s it. To inject,
public MyViewModelOrService(ISettings settings, IConnectivity connectivity) {}
The Not-So-MVVM-Friendly Statics
Now, what about dealing with a static
library that does not expose an interface, not to worry, design patterns to the rescue. We can simply wrap the static
class using Adapter Pattern. Let’s say you have a static
library for logging called StubbornLogger
. Consider the following implementation,
public static class StubbornLogger { public static void Log(string message) { // Log message } }
If your ViewModel
is using this, then while unit testing, you would have to somehow get to the Log()
, which is challenging.
To make it readily injectable and testable, we can wrap this class,
public interface ILoggerWrapper { void Log(string message) } public class LoggerWrapper : ILoggerWrapper { public void Log(string message) { StubbornLogger.Log(message); } }
Now, simply register ILoggerWrapper
with your container,
containerRegistry.Register<ILoggerWrapper>();
and inject away,
public MyViewModelOrService(ISettings settings, IConnectivity connectivity, ILoggerWrapper loggerWrapper) {}
By abstracting away your static
library, you decoupled your code and made it future-proof. You can swap out the implementation anytime without impacting your code as long as you conform to ILoggerWrapper
.
Have questions, comments? Leave them below. Enjoy!
Icon made by Kiranshastry from www.flaticon.com
Thanks for this useful tip,Hussain
Absolutely 🙂