Using Autofac with Xamarin

Good news is that Autofac, my IoC container of choice, works with Xamarin and even within Portable Class Library.  However there is one potential pitfall and it seems it happens at least when you use factories.

Imagine resolving ITubo defined as:

public class Tubo: ITubo
{
    public Tubo(Func<ITubo> tuboFactory)
    {}
}

public interface ITubo
{}

Note the use of factory through Func<ITubo>. In this case Autofac uses reflection and perhaps some runtime IL code generation. Now, try running the following piece of code on Xamarin.Android:

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Tubo>().As<ITubo>();
var container = builder.Build();
container.Resolve<ITubo>();

It is simple registration and after that I do resolve the interface. When you run this code it will most probably work. But that’s only because you are running it in Debug configuration. Now try running in in Release configuration. It will most probably throw an exception at you:

Autofac.Core.DependencyResolutionException: An exception was thrown while executing a resolve operation.

Not very informative but at least the call stack shows that problem happens within System.Core assembly. And it isn’t Autofac’s fault at all.

The reason for the problem is simple but perhaps not the most obvious one. Default project settings are that at Release configuration it cuts out all of the unused code from SDK libraries (Xamarin stuff which is basically all .net BCL) and combines all of the assemblies into a single file - through its linker (at Debug time it uses shared libraries as would .net on Windows). And since Autofac is doing operations at runtime (at least when it comes to factories), linker doesn’t see those and simply cuts off unused types at compilation time to reduce the output size. Read more about Xamarin linking process here:

Linking

The nasty part is that you won’t know what types are cut off until you run the application in Release configuration. Remember, always try your applications in Release configuration!

The solution

Anyway, the solution is, as I’ve found out, rather simple. Just instruct linker to leave alone (don’t optimize) System.Core assembly. If you are using Visual Studio the go to Project/Properties, Android Options tab and enter System.Core text into Skip linking assemblies text box. If you are using Xamarin IDE the go to Project/Properies, Build/Android Build tab, Linker subtab and enter the same System.Core into Ignore Assemblies text box (didn’t try this one). That’s it, linker will leave alone that assembly and Autofac will happily run even in Release configuration.

Luckily the difference in output file size isn’t that significant: 450KB in worst case.

Comments (4) -

  • DarkDeny

    24.3.2014 13:31:00 | Reply

    I've just met this problem with Xamarin.iOS trying to use Autofac, and it turns out this solution does not work for iOS, thus making impossible using autofac in Xamarin.iOS.
    For details please refer to:
    https://bugzilla.xamarin.com/show_bug.cgi?id=14765

    • Miha Markic

      28.3.2014 11:28:54 | Reply

      Perhaps Autofac can't run on iOS due to the iOS restrictions? What error are you getting?

  • Bryan Griffiths

    31.10.2014 10:41:51 | Reply

    Thank you for sharing this tutorial about autofac and I would like to know if this code works on IOS? Cheers!
    http://www.gethummered.com.au

    • Miha Markic

      4.11.2014 8:40:17 | Reply

      Theoretically it should, however, there might be an iOS restriction (problem mentioned in the comment above). Did you try it?

Pingbacks and trackbacks (1)+

Loading