Search code examples
ioc-containermvvmcross

How to resolve a Collection of Types from within the IoC Container


We're using MvvmCross in our app, and using the MvxSimpleIoCContainer

In the app startup, we register all of our Migrations.
it's easy do do since all migrations inherit from IMigration

typeof (IMigration)
    .Assembly
    .CreatableTypes()
    .Inherits<IMigration>()
    .AsTypes()
    .RegisterAsLazySingleton();

After the migrations are registered, we need to run them consecutively, and therefore the MigrationRunner looks a little something like this.

Mvx.Resolve<IMigrationRunner>().RunAll(SystemRole.Client, new List<IMigration>
    {
        Mvx.IocConstruct<Migration001>(),
        Mvx.IocConstruct<Migration002>()
    });

as you can see, I'm explicitely constructing each Migration using Mvx. This get's tedious and is prone to mistakes when a bunch of migrations end up in the app.

What I'd prefer to be able to do is resolve the entire collection in one fell swoop, and not have to touch it every time I create a new Migration.

Is there a way to do this via MvvmCross?


Pseudo Code

Mvx.Resolve<IMigrationRunner>()
   .RunAll(SystemRole.Client, Mvx.ResolveAll<IMigration>());

Solution

  • Ok, so reflection is the answer to this problem for now, and eventually, I'd like to either extend our custom MvxServiceLocator : IServiceLocator to include something like

    public IEnumerable<object> GetAllInstances(Type serviceType){...}

    but for now I've just got a RunMigrations() method in the app

    private void RunMigrations()
    {
        var migrationType = typeof (IMigration); // IMigration is in a separate assembly
        var migrations = GetType().Assembly
                                  .GetTypes()
                                  .Where(
                                      t => migrationType.IsAssignableFrom(t) && !t.IsAbstract)
                                  .OrderBy(t => t.Name)
                                  .Select(m => _serviceLocator.GetInstance(m) as IMigration)
                                  .ToList();
    
        var migrationRunner = new MigrationRunner(Mvx.Resolve<IDbProvider>());
        migrationRunner.RunAll(SystemRole.Client, migrations);
    }
    

    where _serviceLocator.GetInstance(m) just lives in our custom MvxServiceLocator

    public object GetInstance(Type serviceType)
    {
        return _ioCProvider.Resolve(serviceType);
    }
    

    Edit: here's how I extended our service locator wrapper.

    public class MvxServiceLocator : IServiceLocator
    {
        private readonly IMvxIoCProvider _ioCProvider;
    
        public MvxServiceLocator(IMvxIoCProvider ioCProvider)
        {
            _ioCProvider = ioCProvider;
        }
    
        public IEnumerable<TService> GetAllInstances<TService>()
        {
            var serviceType = typeof(TService);
            var registrations = GetType().Assembly
                                         .GetTypes()
                                         .Where(
                                             t => serviceType.IsAssignableFrom(t) && !t.IsAbstract)
                                         .Select(m => (TService)_ioCProvider.Resolve(m));
            return registrations;
        }
    }