parametersninjectconditional-bindingcontextual-binding

Parameter based bindings in ninject 2.0


I want to use conditional binding in ninject, based on passed parameters. I have something like below:

public class Subject
{
}

public interface ITarget
{
}

public class Target1 : ITarget
{
}

public class Target2 : ITarget
{
}

And now I need to instantiate ITarget interface:

    public void MethodName(IKernel kernel)
    {
        ITarget target1 = kernel.Get<ITarget>(new Parameter("name", new Subject(), true)); // Should be instance of Target1
        ITarget target2 = kernel.Get<ITarget>(); // Should be instance of Target2
    }

I have problems to define proper bindings. I tried the following:

kernel.Bind<ITarget>().To<Target1>().When(Predicate);
kernel.Bind<ITarget>().To<Target2>();

private bool Predicate(IRequest request)
{
    IParameter parameter = request.Parameters.Count == 0 ? null : request.Parameters[0];
    if (parameter == null)
    {
        return false;
    }
    object parameterValue = parameter.GetValue( /*what to put here?*/);
    return parameterValue != null && parameterValue.GetType().IsAssignableFrom(typeof(Subject));
}

but I don't know how to get value of passed parameter. I need to pass IContext instance to GetValue method, but don't know how to get valid instance of IContext. Or maybe there is better way to accomplish my task?

EDIT: BindingMetadata is better way to solve my problem. See Contextual bindings with Ninject 2.0 for details

Regards


Solution

  • Does IRequest.ParentContext not give you enough ?

    Also, if all you are looking for is to use a Name to disambiguate multiple instances [and you'll be in a position to provide it each time and are happy to work in that explicit Service Location manner instead of using DI as IDeity intended], then there is a Get overload with a name and a WithName for on the Bind side.

    EDIT: Spent some time in Reflector but am still not much wiser. The parameters mechanism seems to be for the purposes of overriding specific values in the context of an actual binding happening, not as part of selecting the binding that applies. Establishing a context is only done in one place internally (though Context has a public ctor) so it doesnt look like there's a neat factory for that.

    Does your actual scenario happen to fit the constraint mechanism (of which using a name to filter is just the simplest case). i.e., can you express your Get as something like:

    _kernel.Get<ITarget>( (Ninject.Planning.Bindings.BindingMetadata metadata)=>metadata.Has("x") );
    

    Hopefully @Ian Davis will be along soon as I'd love to know the answer too :D