Some time ago I decided to update my NFC library for Xamarin.Forms so to eliminate all the unnecessary dependencies like the Xamarin.Forms package that was used exclusively for the DependencyService.
Searching on the net I came across this post from James Montemagno that explains how to get exactly what I wanted using a practice called Bait&Switch: an awesome way of tricking .NET 😀
When we build a project it’s assembly references need to be resolved in order to find the physical assemblies that the build system should use.
The process is more or less this:
- The build system locates a physical assembly that it can potentially use
- The build system compares the physical assembly’s version to the assembly version stored in the .csproj file for the assembly reference
- If the two assembly versions are exactly the same, the resolution process succeeds and the physical assembly found is used for the build
- If the two assembly versions do not match, the physical assembly is discarded and the resolution process continues by locating the next potential assembly
You can find more informations about this process here
But what happens if we have two assemblies with the same version and name? In this case .NET will always prefer a platform library to a PCL!
DEPENDENCY SERVICE APPROACH
In the first release of my library I used the following approach:
Basically we have a PCL project that contains the Interface and a platform library with the implementation for each supported platform. Then, when developing an app, we reference the implementation in each platform specific project and just the interface in the shared project. Last step before building, with a Dependency Service (I used the on built in Xamarin.Forms) we register every implementation of the interface. In this way when we use a method of the Interface the right implementation will be executed.
The downside of this approach is that I had to add Xamarin.Forms as dependency of my library just for the Dependency Service.
Bait&Switch works thanks to the fact that .NET always prefer a platform library to a PCL. So what happens if we add a “fake implementation” of the interface in the PCL project of the library?
Simple! If we provide an Assembly for every platform in the PCL, this means that nobody will ever execute the code in the PCL version, only the platform versions. This means that we don’t even need to actually implement interface, we can simply throw exceptions 🙂
But since we have the fake implementation we don’t need anymore the DependencyService and .NET will automatically switch the fake implementation PCL with the right platform specific platform. Our diagram then becomes:
In this way we solved the problem: no more Dependency Service and no more unneeded packages like Xamarin.Forms 😀
Here you can find a sample of all this, try building and you will see it works 🙂
If in your exepriments you happen to get:
Error APPX1101: Payload contains two or more files with the same destination path
instead of referencing directly the project of the fake implementation add a reference directly to the dll and then set “Specific Version” to false.
This error will appear only if you reference “by hand“, if you try to create a Nuget from your project you’ll see the error disappear. This is because Nuget works directly with the ddls and not the projects
If you found this post useful consider nominating me for the MVP Award 🙂