1

Some of the provided bindings for the mutli injection may fail to resolve.

    public List<IMyCommand> GetMyCommands()
    {
        //throws
        return kernel.GetAll<IMyCommand>().ToList();
    }

I want to still get all the successfully resolved objects, and ideally which ones failed. Is there a way to achieve this with Ninject?

Landerah
  • 203
  • 2
  • 12
  • 2
    How is it possible that your objects might fail to resolve? – Steven Jun 12 '15 at 09:13
  • 1
    Failure of construction of objects in the object graph should not typically not be ignored, because [injection constructors should be simple, fast and reliable](http://blog.ploeh.dk/2011/03/03/InjectionConstructorsshouldbesimple/). – Steven Jun 12 '15 at 12:33
  • @Steven for example, some of them might be provided by a plugin, or there resolution might be forwarded from another container via an IProvider and that container may be populated via plugin... Does knowing this actually help answer my question or is just to say I shouldn't be asking it. – Landerah Jun 13 '15 at 12:54
  • Knowing this does not help answering this specific question, but it strengthens me in my opinion that my initial reaction is correct. Of course you are free to ask this, but I think that if you change your design, you don't have to ask this question at all. If some registration exists, it must be possible to resolve it. Failing to do so is a bug in the application. If a plugin didn't supply such command, it should simply not be in the list and this allows you to resolve the complete list without risk of failure. – Steven Jun 13 '15 at 13:52

1 Answers1

1

Not out of the box. But we can create some kind of hack/Workaround. Caution. I would rather implement some specific mechanism which handles my case explicitly than to involve Ninject in that.

But for the curiuous minded, here you go:

If you have a look at the implementation of IResolutionRoot.TryGet you'll see that all it does is catch ActivationException and return default(T) in that case.

We can create our own TryGetAll<T> which does the same, but not for the entire IRequest but rather for each binding separately. So here's how to do it:

public static class ResolutionRootExtensions
{
    public static IEnumerable<T> TryGetAll<T>(this IResolutionRoot resolutionRoot)
    {
        var request = resolutionRoot.CreateRequest(
            typeof(IFoo),
            x => true,
            Enumerable.Empty<IParameter>(),
            true,
            false);
        IEnumerable results = resolutionRoot.Resolve(request);
        IEnumerator enumerator = results.GetEnumerator();

        while (MoveNextIgnoringActivationException(enumerator))
        {
            yield return (T)enumerator.Current;
        }
    }

    private static bool MoveNextIgnoringActivationException(
       IEnumerator enumerator)
    {
        while (true)
        {
            try
            {
                return enumerator.MoveNext();
            }
            catch (ActivationException)
            {
            }
        }
    }
}

I've tested it and it works:

public class Test
{
    [Fact]
    public void Foo()
    {
        var kernel = new StandardKernel();

        kernel.Bind<IFoo>().To<FooA>();
        kernel.Bind<IFoo>().To<FooWithDependencyD>();
        kernel.Bind<IFoo>().To<FooB>();
        kernel.Bind<IFoo>().To<FooC>();
        kernel.Bind<IFoo>().To<FooWithDependencyE>();

        kernel.TryGetAll<IFoo>().Should()
            .HaveCount(3)
            .And.Contain(x => x.GetType() == typeof(FooA))
            .And.Contain(x => x.GetType() == typeof(FooB))
            .And.Contain(x => x.GetType() == typeof(FooC));
    }
}

public interface IFoo
{
}

class FooA : IFoo { }

class FooB : IFoo { }

class FooC : IFoo { }

class FooWithDependencyD : IFoo
{
    private readonly IDependency _dependency;

    public FooWithDependencyD(IDependency dependency)
    {
        _dependency = dependency;
    }
}

class FooWithDependencyE : IFoo
{
    private readonly IDependency _dependency;

    public FooWithDependencyE(IDependency dependency)
    {
        _dependency = dependency;
    }
}

internal interface IDependency
{
}
BatteryBackupUnit
  • 12,934
  • 1
  • 42
  • 68
  • 1
    I ended up writing something like this, though I ended up returning a list of 'Resolvers' that each can be called to resolve a specific context, that way any exceptions can be caught and handled appropriately. – Landerah Jun 13 '15 at 12:57
  • yeah I think that's much better anyway. – BatteryBackupUnit Jun 14 '15 at 05:16