How do I use GetAll with Ninject so that one failure doesn't stop the other bindings from resolving?

322 views Asked by At

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?

1

There are 1 answers

2
BatteryBackupUnit On BEST ANSWER

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
{
}