Runar Ovesen Hjerpbakk

Software Philosopher

VTable setup of type LightInject.ServiceContainer failed

An important concept in app development is the D in SOLID, the Dependency inversion principle. While using this technique together with the Interface segregation principle you end up with a lot of interfaces. And with cross-platform Xamarin apps, you’ll sometimes have different implementations on iOS and Android with some fake service implementations for testing too.

When creating iOS apps using Xamarin, another good practice is to enable linking. Enabling linking will remove unused code before compilation and decreases the size of your app manyfold. There’s a difference between 80 and 20 MB, even in 2019.

Xamarin Forms has a built-in DependencyService to help manage the interfaces and their implementations, but I prefer the always excellent LightInject. And after adding LigthInject to my latest Xamarin Forms app and enabling linking, this error message appeared on startup:

VTable setup of type LightInject.ServiceContainer failed

Obviously, LigthInject had insufficient information to compose its dependency table, and since linking was enabled, this most likely was the culprit.

Since most IoC containers rely on reflection to create objects, the linker will never see their constructors. And also, if every member access happens through an interface, the class implementing it will seem unused and be stripped by the linker.

Skipping linking for parts of the app

There are two main ways to tell the linker to skip some parts of the code.

Skip a class

For your own code, you can tell the linker to skip parts based on your needs using:

[Preserve (AllMembers = true)]

You can use this for whole classes like this:

namespace Birthdays.iOS.Services {
  [Preserve(AllMembers = true)]
  public class iOSLocaleService : ILocaleService {
  }
}

Skip an entire assembly

To skip an entire assembly, specify the linkskip option in the build options. To skip LightInject, use this:

--linkskip=LightInject

You can have as many linkskips as you need, separated by spaces:

--linkskip=NameOfFirstAssembly --linkskip=NameOfSecondAssembly

Thus, to fix the error at the start of this post, I needed to preserve the classes constructed by the container and make the linker skip the LightInject assembly. Easy, when you know what to do 😃