Let’s talk about how to properly handle advanced cross platform architectural implementations in Xamarin Forms projects, specifically when you’re abstracting native services/implementations in your shared code base, while trying to maintain loosely-coupled and scalable architecture.
Yaay! Xamarin Forms!
Now we all know how Xamarin Forms allows us to build cross platform mobile apps while sharing almost up to 100% of our code base and skill having native performance and look and feels.
It does this by adding a common layer of abstraction which shares properties and behaviors which are common for the native platforms.
Despite the incredible architecture of the Framework, one of the main drawbacks of it is that we do not get access to 100% of the native properties and behaviors, thus we only get the “common subset” of behaviors of each native platform that are shareable in a common manner among all the platforms through Xamarin Forms.
So when we need to access some properties, behaviors or services that’s not available from Xamarin Forms layer, we need to drill down to the native platform specific level of that certain platform.
Now for UI Controls and their properties or behaviors we could use Custom Renderes or Effects.
But how about inbuilt native Services, such as Storage, Text-to-Speech, Location and so on?
Turns out it’s all abstraction of an interface and mapping it to a platform specific concrete implementation, which could be described as the famous “Bridge Pattern”.
Yes it does seem pretty simple but when it comes to actual practicality of it, then it becomes a little bit complicated or rather messy, unless you follow a proper implementation pattern.
And it only gets more complicated when you keep on scaling your app project.
Therefore it’s very crucial that we maintain a certain set of principal patterns when we do platform specific implementation with abstraction mapping.
So we need to make sure that we maintain a proper set of principal patterns when deal with this situation as I explained earlier.
Here I’m going to talk about three key principles to deal with advanced cross platform implementations for handling native abstractions.
- Factory Pattern
- Service Locator Pattern
- Dependency Injection Pattern
Now with the above principle patterns you could maintain a properly constructed and easily scalable Xamarin Forms project solution, when you’re dealing with advanced cross platform implementations with abstracting native services. Or rather any kind of an abstraction service implementation you could keep properly maintained by following the above patterns. The key advantage in all the above patterns are decoupled code, and scalability at any given time.
Now keep in mind there’s actually many kinds of patterns you could follow in this scenario or you could come up with your own architectural patterns, but the above are known to be most used among Xamarin Forms projects.
It is best to be aware of them, since you could either use them straight away or modify them according to your requirements. And keep in mind the above principle patterns could become slightly changed from their literal definition when it comes to actual implementation, it’s only the foundation concept that we need to keep in mind when we implement them, and make sure we are following the basics of it at least.
Which one should I use?
There is no such thing as “the best” or “the worse”pattern for cross platform mobile development, it all depends on how you interpret it based on your requirements. The selection of which pattern or architecture suits best for you is totally up to you and your requirements, that is something very crucial to keep in mind. Therefore here in this post I shall be demonstrating each of the above patterns and how to implement them properly in a Xamarin Forms project solution for the same app concept.
Let’s talk Demonstration!
In order to properly demonstrate the above said patterns I will be implementing a simple Xamarin Forms app which allows you to writing notes, save them, view them, read them out loud, edit them, and also delete them. So in that case we will be using native Storage Services and Text-To-Speech Services of those native platforms, while having a shared code base.
Alright now, I’m not going to get into spoon feeding details of how to do each native services implementation such as Storage and Text-To-Speech and implementing the XAML pages for the app and so on, but I will only be focusing on implementing the pattern for the given scenario, which is what matters for this post.
So we are going to create a Xamarin Forms solution in Visual Studio, and keep the interface for the above native services in the PCL or Shared Project (INoteReader and INoteLoader) and have the concrete implementations of them to be moved down to the native projects.
Then to demonstrate the differences of implementation of all the above three patterns I have created a complete solution (XFCPMobilePatterns) which has three sub folders, and included three Xamarin Forms projects in each of them which has the demo for Factory Pattern (XFMyNotesAppFP), Service Locator Pattern (XFMyNotesAppSL) and Dependency Injection w/ IoC (XFMyNotesAppDI).
Yep, that’s how it would look, if you’re interested in diving further into the implementation, You may find the complete solution up on my Github repo: https://github.com/UdaraAlwis/XFCPMobilePatterns
1. FACTORY PATTERN with Xamarin Forms
Oh yeah, back to basics yeah? the good old Factory Pattern, which allows you to create objects without exposing the creation logic to the client, or as in without having to aware of the concrete implementation.
So for our implementation we are going to keep a static generic Factory which will handle mapping and creation of the services. And we would request the service by passing the service type.
Alright next we are going to map our Service Interfaces (INoteReader and INoteLoader) which we have placed in the PCL project, with their actual concrete implementations in the platform specific projects using the ServiceLoaderFactory. Make sure to do this mapping in the run time execution point of each project as shown below.
Next we need a NoteManager which is going to keep tract of all the service instances after they’re mapped to their concrete implementations at the run time, and also to maintain sort of a ‘facade-like’ access to the services. So for obvious reasons, we need to make it a singleton access point, as there’s no point of duplicating service objects. Also we are creating the NoteManager to handle basic functions such as loading and saving Notes at run time. 🙂
You can see there in the constructor, how we are loading the Service objects from our ServiceLoaderFactory and mapping them to the public interface instances, so that we could use them anywhere in our app.
Now the reason why I’m maintaining the NoteLoader and NoteReader instances here is because with the Factory Pattern, every time we request a service instance, it creates a new instance of the service and returns to the client, which obviously is not efficient, that’s why I’m retaining those instances in the NoteManager class. But with few tweaks you could easily implement a Factory Pattern which caches instances, and reuse them upon request, but I wouldn’t waste time on that, since we could use Service Locator or Dependency Injection for such scenarios, which I would explain later in the article.
Here’s how to access the above services in anywhere your PCL or Shared Project.
There you have it, now that shows how to add platform dependent services and use them in your shared code following the Factory Pattern, as you go on scaling up the project solution! 😉
But keep in mind that this may not exactly according to literal definition of “Factory Pattern 101” but rather a customized version of it which I came up with for cross platform implementation, so you might have a different kind of implementation of the same concept, which is totally ‘ok’, as long as the foundation is the same. 🙂
2. SERVICE LOCATOR PATTERN with Xamarin Forms
As we already know, Service Locator Pattern, is all about locating a concrete implementation instance of an abstracted service interfaces at run time.
This is something similar to Factory Pattern, but a different type of a solution for our situation, whereas it maintains a dictionary of registered services which has been mapped with their concrete implementation, which we can look up at run time and retrieve the instance. Now it is considered that Service Locator pattern is a variation of Inversion of Control principle, just as Dependency Injection pattern, which we’ll discuss in the next topic.
This provides an on demand service look up at anywhere in the run time. The native service instances are stored in a dictionary-like data structure inside the Service Locator object, and returned at run time when they’re requested by the interface type. Obviously there will be a singleton static reference to the Service Locator object.
There’s many Service Locator ready-made libraries out there, and heck even Xamarin Forms already provides a solid Service Locator in the framework, which you may have already heard of, Xamarin Dependency Service. So you could use it right out of the box in Xamarin Forms, for your abstracted service implementations.
But that being said it’s not so hard to roll out our own Service Locator (just for the demonstration of it’s mechanics). 😉
So let’s implement our own simple Service Locator, this was actually something I grabbed off of github.
As you can see how simple and straightforward it is. We maintain a singleton instance of the ServiceLocator, and there are the Add<TContract, TService>() which is used for registering the service interfaces with their concrete implementation and the Resolve<T>() which is used for retrieving the service instance at run time.
Notice how its maintaining a Dictionary of the service instances and retrieve it up on Resolve() call. 😉
Let’s add the above Service Locator to our project and construct it as below. And keep in mind the service implementation is going to be the same, having your service interfaces in the PCL shared project and the concrete implementations in the platform specific projects.
Now with our Service Locator this is how you would register your Service Interfaces (INoteReader and INoteLoader) with their concrete implementations.
Then just like what we had in Factory Pattern implementation we need a NoteManager which is going to handle basic Note managing functions such as loading and saving notes. 🙂
As you can see, compared to the NoteManager we had in the Factory Pattern, this NoteManager is much more simplified and cleaner thanks to the ServiceLocator.
This is because ServiceLocator allows us to maintain a single instance of our services such as INoteLoader and INoteReader, thereby we do not have to worry about duplicating their instances, we could simply access them anywhere in our code.
You can see how its easily calling the ServiceLocator.Resolve<T> to retrieve the service instances. 🙂
Here’s how to access the above services in anywhere your PCL or Shared Project, and notice how we are directly accessing the service instance unlike in Factory Pattern thanks to the ServiceLocator.
There you have it, now this clearly shows how easy it is to add more and more platform dependent services and use them in your shared code as you go on scaling up the project solution, all thanks to Service Locator Pattern! 😉 Altogether while simplifying the shared code compared to the Factory Pattern.
And keep in mind this is a well improved pattern over Factory Pattern, but it still depends on your requirement as to which one is best suited for your implement. 🙂
3. DEPENDENCY INJECTION with Xamarin Forms
Now this right here is like the holy grail or the most praised and most used pattern in our scenario. Dependency Injection is all about injecting dependencies to create a given object just as said by its name. This is all about automatically resolving the required dependencies at run time without having the client specifically looking it up and creating them and injecting them to the new object to be created. So we are delegating the whole dependency resolving to an automated mechanism, thus a very popular form of Inversion of Control principle, whereas a massive improvement over the Service Locator.
Service Locator is good enough, only for smaller scale projects, where as you register services manually and look them up on demand at run time. But when the project gets more bigger and complex, with a lot of inter-connecting service and dependencies, it is very hard to keep a track on all of them, and most likely you’ll up missing a whole bunch of required dependencies in your code. This is usually a common case when you move into patterns such as MVVM implement for your mobile project, where you deliberately loosely couple all the layers of your app project, and you could easily end up missing dependencies.
This is where Dependency Injection comes for the rescue, where as we inject the required dependencies in the constructor or as properties and delegate that whole process to an automated mechanism, which we call the “Container“. So whenever we implement a DI it always comes with a static singleton Container which manages all the dependencies and resolve them automatically at run time, and we just have to register the dependency mapping only with the container.
Now there’s so many kinds of Dependency Injection Containers out there for you to choose from, given the popularity of this pattern. Unity, Ninject, AutoFac, TinyIoC and so on are some examples. It’s also pretty straight forward to roll out our own, but for this demo I would use an existing DI Container, Unity, quite a popular counterpart in this space.
Alright then, first of all let’s add the Unity library to our solution.
Make sure to select your PCL project and all the platform specific projects when you’re adding Unity from nuget.
Let’s make use of the Dependency Injection with our IoC Container as below. Now there’s nothing to be changed in how you implement your abstract interfaces in your PCL shared project and concrete implementations in the platform specific projects. 🙂
Let’s create a static reference for our container instance.
Next here’s our NoteManager which is going to handle basic Note managing functions such as loading and saving notes. 🙂 You might see something different than what we had in Service Locator.
As you can see we are passing in the INoteLoader and INoteReader services to the constructor of the NoteManager, this means that NoteManger cannot exist without those parameters services. So what happens here is that, when we request an instance of the NoteManager, the IoC Container (Unity Container) will resolve those depending services instances and inject them into the NoteManager, whilst creating the NoteManager.
Look how simple and clear the NoteManager is compared to our Service Locator and Factory Pattern principles.
Also you can see that we are no longer maintaining a singleton static reference to the NoteManager like how we did in Service Locator, because we could do the same thing directly using our IoC Container as shown below. 🙂
That’s how we are registering our NoteManager instance with the container, and we are instructing the container to retain a single instance of it by passing in the ContainerControlledLifetimeManager() type object to it. Also its good to keep in mind there are several object life time management types in Unity Container which you could play around with.
One of the coolest things about IoC containers is that we could instruct it to how we need a certain object or a type should be managed in the run time of the app. 😉 Oh yeah, cool indeed!
Now with our Unity Container this is how you would register your Service Interfaces (INoteReader and INoteLoader) with their concrete implementations on the platform specific level.
Also something to keep in mind is that we need to instantiate our UnityContainer instance here in the platform specific level where the execution begins. 🙂
Thanks to the IoC Container you could easily access the NoteManager anywhere in your code, which will give you access to the static retained instance.
And of course the services as well.
There you have it, now this clearly shows how easy it is to add more and more platform dependent services and use them in your shared code as you go on scaling up the project solution, all thanks to Dependency Injection Pattern! 😉
Specially you noticed how it simplifies our shared code compared to the Service Locator pattern. Also its worth it to notice, how using an IoC Container brings many useful features to the table that you could use to improve your code.
So again, which one should I use?
Now that should have given you a very good comparison between the use of,
- Factory Pattern
- Service Locator Pattern
- Dependency Injection Pattern
Each one of those patterns have their own advantages and disadvantages, yet you may have noted a general aspect improvement over each other such as Factory Pattern < Service Locator Pattern < Dependency Injection Pattern. Let’s break it down as below.
Considering some of the negative aspects of NoteManager implementation in each pattern,
in Factory Pattern we had,
- Maintain static singleton access to NoteManager
- Maintain static references to the INoteLoader and INoteReader service objects
- Use NoteManager to access INoteLoader and INoteReader service objects
- Resolve INoteLoader and INoteReader service objects manually
in Service Locator Pattern we had,
- Maintain static singleton access to NoteManager
- Resolve INoteLoader and INoteReader service objects manually
in Dependency Injection Pattern we had,
- none of the above issues
So there you can clarify my claim of general improvements over each pattern, Factory Pattern < Service Locator Pattern < Dependency Injection Pattern.
Although that’s being said, the choice of Pattern to follow is totally up to you and your requirements. As an example something like Factory Pattern or Service Locator Pattern would be good enough for a small scale projects and Dependency Injection would be perfect for large scale projects with heavy MVVM based apps which uses a lot of service dependencies and so on.
So I hope my demonstration of each of the patterns and how to implement them properly in a Xamarin Forms project solution for the same app concept, may have helped you in deciding which patterns to be used in any given scenario, which uses cross-platform dependencies.
Oh once again, You may find the complete solution up on my Github repo: https://github.com/UdaraAlwis/XFCPMobilePatterns
Go ahead and play around with the app and check out how each pattern is used in the MyNotes App scenario! 😉
Cheers everyone! 😀