How to setup Ninject as the default DI container in MvvmCross?
When you build a multi-platform application in .NET, especially for the mobile, you typically choose between two approaches. One is to code the shared UI layer commonly with Xamarin.Forms (you will still need to have some parts to be placed in platform projects, like custom renderers or providers). The second is to put the entire UI code in platform-specific projects. In this approach you can use the full power of each platform features (like fragments on Android). Both solutions allow for sharing common business logic between all the platforms. On the other hand full implementation of MVVM pattern in the second approach can be tricky and time consuming. The solution is to use 3rd party library; and here comes the MvvmCross. It covers many more areas than the pure MVVM pattern:
- cross-platform plug-ins,
- platform-specific helpers (i.e. Android recycler views with grouping or iOS table views with simplified customization API),
- IoC and messaging infrastructure.
Thanks to the consistent design, all the plugins and extensions, it can seriously speed-up building UI-intensive cross-platform projects. And it still allows you to take all the benefits provided by MVVM design pattern.
Now let’s see how to make Ninject and MvvmCross work together on your project. I will describe how to set it up for PCL, Xamarin.iOS and Xamarin.Android (the general rules remain the same for other platforms).
You can implement everything from scratch, but I decided to use a helper package MvvmCross.Adapter.Ninject. To avoid adding new dependency and to be able to track dependencies in depth, I just add this code to my projects (it’s only two classes in PCL and one for each platform). If you decide to add it as a NuGet package, remember to check for pre-release versions. Also, keep in mind that two platform-specific classes - NinjectMvxIosSetup
and NinjectMvxDroidSetup
- are missing in the package. In such case, remember to add them as I describe below.
The first thing to implement is the IMvxIoCProvider
. This is the base type for DI container in MvvmCross and it’s basically only the facade around the real container. It is required by MvvmCross as an interface between its API and Ninject kernel methods. MvvmCross.Adapter.Ninject
comes with NinjectMvxIoCProvider
class for this (full code available here):
Second type, NinjectDependenciesProvider, is not necessarily required by MvvmCross but is a quite handy helper. It will help you separate the dependencies that are platform specific (GetPlatformSpecificModules()
) from those defined in your common PCL project (GetPortableNinjectModules()
).
Next, you will need some code to plug this into the MvvmCross infrastructure on each platform. It will consist of two pieces: type derived from NinjectDependenciesProvider
and the one derived from Mvx...Setup
.
Providers job is to return the dependencies in form of standard INinjectModule
collections. Those classes are quite straightforward:
Most probably you will want to have at least one for PCL and for each of supported platforms:
Mvx...Setup
classes are responsible for bootstrapping MvvmCross on each platform. Like the NinjectDependenciesProvider
they are just an abstract base classes that ensures the actual platform setup types configures the DI container properly:
Obviously, you can omit this level of inheritance and configure IoC directly in your MvxSetup.InitializeLastChance()
method but I find this implementation more elegant. You will find those classes also in MvvmCross.Adapter.Ninject
but for some reason, they are not present in NuGet package.
The final step is creating the platform-specific setup classes that derives from above abstract setups which boils down to implement GetNinjectDependenciesProvider()
method:
This configuration will enable you to use the standard Mvx.Resolve<T>()
to resolve the dependencies from Ninject container. More importantly, it will do the same for other standard MvvmCross components.
Happy coding!