Integrating IoC with Xamarin.iOS

At West Monroe we use Xamarin almost exclusively for our mobile application development.  There are a variety of reasons for this but a few of the notable ones are:

  • Code Uniformity – Other teams within the West Monroe technology practice utilize C# for software development. That Xamarin also employs C# for its platform makes the transition to and from the mobile team easier. Newcomers must still work to understand the specific platform, but they can rely on the fact that the language being used will be familiar to them
  • Code Sharing – This is a big advantage to any project using Xamarin. If a client wishes to build a native application using standard tools they must at least run two teams using different tools and languages.  Each team will need to create the same feature using a different language.  Xamarin alleviates this risk by enabling code uniformity and code sharing between platforms. Indeed, a major selling point for our clients is the flexibility to know that if they want an Android version the effort will be less than the effort to create the iOS version.

These reasons, as well as others have led our team to great success with many of the projects that have come our way. In addition, we consistently leverage MVVMCross (https://github.com/MvvmCross/MvvmCross) for our development as MVVM is a solid pattern and works well with Xamarin since you will have different views for each platform supported.

Recently, however, the teams have begun to notice problems with implementing MVVM on larger projects where the UX is of a considerably higher effort than apps in the past.  We are beginning to see a ceiling with what MVVM can do when forced upon a platform (iOS and Android) which are not built for the pattern.  Due to this we have begun exploring options for what to do in those cases where MVVM and MVVMCross simply do not make sense.

One of the things we really like about MVVMCross is the dependency resolution aspect which happens within view models. Having our services and their dependencies handled this way cleans up the code dramatically.  The following is my initial attempt at building AutoFac into a Xamarin.iOS project.

The AppDelegate

In every iOS application the AppDelegate class is the starting point, responsible for handling global lifecycle events, launching is no exception.  This makes it the best place to start our dependency mapping registration.  For this, I created the AutoFacUIApplicationDelegate class which takes care of the critical parts of registration; it inherits from UIApplicationDelegate which is what the AppDelegate normally inherits from.

Just to make it easy and eliminate the potential for conflict I have chosen to build the registration process at the “Will Finish Launching” point in the process.  Here is the code for the method:

        public override bool WillFinishLaunching(UIApplication application, NSDictionary launchOptions)
        {
            // create our container builder
            var builder = new ContainerBuilder();

            // access the assembly and register ALL classes which implement our custom base class
            var types = GetType().Assembly.DefinedTypes;
            foreach (var theType in types)
            {
                if (theType.BaseType == typeof(AutoFacUIController))
                    builder.RegisterType(theType).PropertiesAutowired();
            }

            // ask the user to register their dependencies
            RegisterDependencies(builder);

            // establish our static container
            _autoFacContainer = builder.Build();

            // return true
            return true;
        }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

The code here is still pretty rough, but it communicates the general idea.  The first goal is to register the types of all View Controllers which are going to use Dependency Injection, that is those that inherit from AutoFacUIController. By doing this, we can ensure that when injection occurs the ViewController type is registered with the IoC container.

Once this is complete, we pass the IContainerBuilder reference to RegisterDependencies which is a user method allowing for the definition of their dependencies.  Once this complete we build and assign the container to a static variable to enable it to be used elsewhere in the application.  Here is a look at the RegisterDependencies in my test app:

        protected override void RegisterDependencies(Autofac.ContainerBuilder builder)
        {
            builder.RegisterType<WorkplaceNameService>().As<INameService>();
        }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

This is a rather contrived example but this is where you could leverage AutoFac and register your types and modules as needed.

Our next goal is to be able to inject these dependencies into our view controllers.  The pattern we are going for is similar to what we see used in ASP .NET MVC and since iOS is built on an MVC approach (more MVP in my opinion) the pattern fits quite well.  We want to define properties on the View Controller that represent our dependencies.  We then want AutoFac to fulfill those properties as the page is loading up.

The first piece to understand here is the lifecycle of ViewController when they are displayed in iOS. Based on my analysis there are two lifecycle events that I can hook into for this process: LoadView (storyboards) and AwakeFromNib (Xib based development).  For the purpose of this test, we will ONLY focus on LoadView since we should all be using Storyboards for the majority of our UI development in iOS, Xamarin or otherwise.

The second thing to understand is how this will need to work.  We want to grab our static IoC container reference and the use it to fulfill our dependencies.  Here is the base LoadView method.

    public class AutoFacUIController : UIViewController
    {
        private IContainer _container;

        public AutoFacUIController(IntPtr ptr) : base(ptr)
        {
            _container = AutoFacUIApplicationDelegate.GetAutoFacContainer();
        }

        public AutoFacUIController()
        {
            
        }

        public override void LoadView()
        {
            // resolve all properties
            _container.InjectProperties(this);

            base.LoadView();
        }
    }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

The InjectProperties method call reflects on the current instance and finds properties whose declared type match a type registered with the IoC container.  The result is, as long as a class inherits from this class it will, when ViewDidLoad fires have all of its relevant dependency properties fulfilled.

Beyond

Obviously this is incredibly rough and relies on quite a bit of ceremony and it completely tied to AutoFac. Ideally, there is more automation and the IoC container is a personal choice rather than a forced one. Nevertheless it’s a good start and I hope to incorporate it into an API library that we can use at West Monroe for more complex projects where the MVVM gains are outweighed by the losses.

For now, I want to continue testing this approach under different situations.  If you are interested I have posted by code to GitHub and it will update as I move through this research process.

https://github.com/xximjasonxx/iOS_AutoFac

Advertisements

One thought on “Integrating IoC with Xamarin.iOS

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s