IoC Containers with Xamarin

When writing cross platform apps with Xamarin, our goal is share as close to 100% of our code across all the platforms. While this is an admirable goal to aim for, it is not realistic. Very often, we find ourselves needing to access a platform specific feature from our shared code. We have multiple options in this case. We could use a Shared Project with compiler directives, class mirroring, or partial classes and access the platform code alongside our shared code. Alternatively we could use an abstraction for the functionality in our shared code, and pass an implementation of the abstraction into our shared code. In this way, our shared code only needs to know about the abstraction, typically an interface. This strategy, known as Inversion of Control or IoC, works especially well when using Portable Class Libraries (PCL) for our shared code.

Even when using IoC, manually managing all of our dependencies, including instantiating the dependency tree for an object, can be tedious at best. This is where we turn to a host of existing IoC containers. The .net ecosystem has long had a wealth of choices in IoC containers. Some of the more popular ones include StructureMapCastle WindsorNinjectUnity, and Autofac. These are by no means the only choices, up to and including rolling our own.

Not all of these containers are able to run in limitations imposed by mobile devices though. Phones and tablets have constrained cpu and memory, and iOS devices forbid JIT compiling and certain uses of reflection. Additionally, the library authors have to specifically compile for Xamarin.iOS and Xamarin.Android, either individually or as part of a PCL.

I decided to put together some sample code showing how the Xamarin-compatible IoC containers work. As of this writing (July, 2014) I have limited the comparison only to IoC containers that 1) I could get to work successfully and 2) had an available Nuget package for easy installation. I did not want to go through the process of pulling individual repositories and building the source from scratch, although that is a valid option. This excluded some options that I do want to mention as alternatives.

  • Xamarin.Forms Dependency Service. This is really more of a Service Locator than it is an IoC container. Also, it is only available as part of Xamarin.Forms.
  • OpenNetCF. There is no nuget package for this library. Also, it requires custom attributes be added to the shared code, diminishing the usefulness.
  • XPlatUtils. There is no nuget package for this library.

The libraries that I focused on were AutofacMvvmCrossNinjectTinyIoc, and Unity.

All of the code is available from my Github Repo

Sample Project

In the sample project, we have a single IoCDemo.Core project. This project contains the interface abstractions for our platform specific projects (ISettings and IPlatform) and a concrete ViewModel (MainViewModel) which takes the two interfaces as constructor dependencies. For each library, I created an iOS and an Android project to demonstrate wiring up the dependencies to platform specific implementations and creating the view model. Each container will be wired up in an App.cs file in each platform.

Some of the IoC containers have the ability to scan your assemblies and automatically wire up your dependecies. I chose not to use this ability. In a mobile app, every bit of cpu power is precious. I would rather spend the extra few seconds to write the code to wire up the dependency once at development time than have the app scan the assemblies every single time it is started.

Autofac

Install-Package Autofac

Wiring up the container

using Autofac;  
using IoCDemo.Core;

namespace AutoFacDemo.iOS  
{
    public class App
    {
        public static IContainer Container { get; set; }

        public static void Initialize()
        {
            var builder = new ContainerBuilder();

            builder.RegisterInstance(new ApplePlatform()).As<IPlatform>();
            builder.RegisterInstance(new AppleSettings()).As<ISettings>();
            builder.RegisterType<MainViewModel> ();

            App.Container = builder.Build ();
        }
    }
}

Resolving the view model

MainViewModel viewModel = null;

using (var scope = App.Container.BeginLifetimeScope ()) {  
    viewModel = App.Container.Resolve<MainViewModel> ();
}

MvvmCross

Install-Package MvvmCross.HotTuna.CrossCore

Wiring up the container

using Cirrious.CrossCore;  
using IoCDemo.Core;  
using Cirrious.CrossCore.IoC;

namespace MvvmCrossDemo.iOS  
{
    public static class App
    {
        public static void Initialize ()
        {
            MvxSimpleIoCContainer.Initialize ();
            Mvx.RegisterType<IPlatform, ApplePlatform> ();
            Mvx.RegisterType<ISettings, AppleSettings> ();
        }
    }
}

Resolving the view model

var viewModel = Mvx.IocConstruct<MainViewModel> ();  

Ninject

Install-Package Portable.Ninject

Wiring up the container

using Ninject;

namespace NinjectDemo.iOS  
{
    public static class App
    {
        public static StandardKernel Container { get; set; }

        public static void Initialize()
        {
            var kernel = new Ninject.StandardKernel(new NinjectDemoModule());           

            App.Container = kernel;
        }
    }
}

Resolving the view model

var viewModel = App.Container.Get<MainViewModel> ();  

TinyIoc

Install-Package TinyIoc

Wiring up the container

using TinyIoC;  
using IoCDemo.Core;

namespace TinyIoCDemo.iOS  
{
    public static class App
    {
        public static void Initialize ()
        {
            var container = TinyIoCContainer.Current;

            container.Register<IPlatform, ApplePlatform> ();
            container.Register<ISettings, AppleSettings> ();
        }
    }
}

Resolving the view model

var viewModel = TinyIoC.TinyIoCContainer.Current.Resolve<MainViewModel> ();  

Unity

Install-Package Unity

Wiring up the container

using Microsoft.Practices.Unity;  
using IoCDemo.Core;

namespace UnityDemo.iOS  
{
    public class App
    {
        public static UnityContainer Container { get; set; }

        public static void Initialize()
        {
            App.Container = new UnityContainer();
            App.Container.RegisterType<IPlatform, ApplePlatform> ();
            App.Container.RegisterType<ISettings, AppleSettings> ();
        }
    }
}

Resolving the view model

var viewModel = App.Container.Resolve (typeof(MainViewModel), "mainViewModel") as MainViewModel;  

Again, checkout the sample app on my Github repo to compare our IoC container choices for Xamarin.

 

From:http://arteksoftware.com/ioc-containers-with-xamarin/

posted @   遥望星空  阅读(601)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
历史上的今天:
2012-06-15 ASP.NET性能优化
2012-06-15 大型电子商务网站架构
点击右上角即可分享
微信分享提示