1

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>());
Chase Florell
  • 46,378
  • 57
  • 186
  • 376

2 Answers2

2

I would use LINQ to get the list of types. Unfortunately there's no way to get a list of registered types, so you'll have to enumerate the types again like you do for registration. You can even sort by type name. Now that you have a list of types, you can create a new list of instantiated/resolved types to pass into RunAll(). Something like:

var migrationTypes = typeof (IMigration)
    .Assembly
    .CreatableTypes()
    .Inherits<IMigration>()
    .AsTypes()
    .OrderBy(t => t.Name)
    .ToList();

Mvx.Resolve<IMigrationRunner>()
    .RunAll(SystemRole.Client,
         migrationTypes.Select(t => Mvx.Resolve(t)).ToList());

This is "browser" code, so no guarantees, but you get the gist.

Kiliman
  • 18,460
  • 3
  • 39
  • 38
1

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;
    }
}
Chase Florell
  • 46,378
  • 57
  • 186
  • 376