Ninject conditional binding based on parameter type

binding, c#, conditional-statements, ninject

Solution

After some looking into Ninject source I have found following:

`a.Parameters.Single(b => b.Name == "connection")` gives you variable of type `IParameter`, not real parameter.

`IParameter` has method `object GetValue(IContext context, ITarget target)` that requires not null context parameter (target can be null).

I have not found any way to get IContext from Request (variable a in your sample).

`Context` class does not have parameterless constructor so we can't create new Context.

To make it work you can create dummy IContext implementation like:

public class DummyContext : IContext
{
    public IKernel Kernel { get; private set; }
    public IRequest Request { get; private set; }
    public IBinding Binding { get; private set; }
    public IPlan Plan { get; set; }
    public ICollection<IParameter> Parameters { get; private set; }
    public Type[] GenericArguments { get; private set; }
    public bool HasInferredGenericArguments { get; private set; }
    public IProvider GetProvider() { return null; }
    public object GetScope() { return null; }
    public object Resolve() { return null; }
}

and than use it

kernel.Bind<IDataSender>()
      .To<RemotingDataSender>()
      .When( a => a.Parameters
                   .Single( b => b.Name == "connection" )
                   .GetValue( new DummyContext(), a.Target ) 
               as RemotingConnection != null );

It would be nice if someone could post some info about obtaining Context from inside `When()`...

Problem

I'm using a factory to return a datasender: ``` Bind<IDataSenderFactory>() .ToFactory(); public interface IDataSenderFactory { IDataSender CreateDataSender(Connection connection); } ``` I have two different implementations of datasender (WCF and remoting) which take different types: ``` public abstract class Connection { public string ServerName { get; set; } } public class WcfConnection : Connection { // specificProperties etc. } public class RemotingConnection : Connection { // specificProperties etc. } ``` I am trying to use Ninject to bind these specific types of datasender based on the type of Connection passed from the parameter. I have tried the following unsuccessfully: ``` Bind<IDataSender>() .To<RemotingDataSender>() .When(a => a.Parameters.Single(b => b.Name == "connection") as RemotingConnection != null) ``` I believe this is because '.When' only provides a request and I would need the full context to be able to retrieve the actual parameter value and check its type. I'm at a loss as to what to do, other than using named bindings, actually implementing the factory and putting the logic in there i.e. ``` public IDataSender CreateDataSender(Connection connection) { if (connection.GetType() == typeof(WcfConnection)) { return resolutionRoot.Get<IDataSender>("wcfdatasender", new ConstructorArgument("connection", connection)); } return resolutionRoot.Get<IDataSender>("remotingdatasender", new ConstructorArgument("connection", connection)); } ```

Original source