I recently upgraded Ninject to the most recent builds to fix this issue: ninject binding issue
As far as I can tell, it corrected the issue, but it seems to have messed up my controller unit tests. I now get the error that I was trying to fix when running my unit tests. The error is:
Error activating ISomething
More than one matching bindings are available.
I'm sure there's something wrong with my test harness/ninject setup, but I can't figure out what it is. Here's an overview of the current code. Note, I'm using MVC 2 as well as the MVCContrib test helpers.
public class SomeControllerTests : ControllerTestBase<SomeController>
{
public SomeControllerTests () : base() { }
[Fact] //this test fails
public void ConstructorIsNotNull()
{
var controller = this.GetController();
Assert.NotNull(controller);
}
}
public class ControllerTestBase<T> where T : Controller
{
protected IKernel Kernel { get; set; }
private MockRepository _mocks = new MockRepository();
public ControllerTestBase()
{
this.Kernel = new StandardKernel(new ControllerTestBootStrapper());
}
protected T GetController()
{
return this.GetController(null);
}
protected T GetController()
{
DependencyResolver.InitializeWith(new NinjectDependencyResolver(this.Kernel));
TestControllerBuilder testContBuilder = new TestControllerBuilder();
return testContBuilder.CreateIoCController<T>();
}
}
public class ControllerTestBootStrapper : NinjectModule
{
public override void Load()
{
Bind(typeof(IRepository<>)).To(typeof(MockRepository<>));
var ppCredentials = new PaymentProcessorCredentialCollection {
new PaypalPaymentsProCredential(true,
ConfigurationManager.AppSettings["PaypalAPIUsername"],
ConfigurationManager.AppSettings["PaypalAPIPassword"],
ConfigurationManager.AppSettings["PaypalAPISignature"],
ConfigurationManager.AppSettings["PaypalEnvironment"]
)
};
Bind<PaymentProcessorCredentialCollection>().ToConstant(ppCredentials);
Bind<ICCProcessingService>().To<PayPalService>();
Bind<IACHProcessingService>().To<ACHDirectService>();
Bind<IPaymentProcessingService>().To<ACHDirectService>();
Bind<IEmailSendService>().To<SmtpEmailSendService>();
Bind<IEmailGenerationService>().To<SparkEmailGenerationService>();
NHibernate.Cfg.Configuration cfg = Fluently.Configure()
/*various nhibernate configuration */
.BuildConfiguration();
Bind<ISessionManager>().To<SimpleSessionManager>().WithConstructorArgument("cfg", cfg);
}
}
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel _kernel;
public NinjectDependencyResolver(IKernel kernel)
{
this._kernel = kernel;
}
public void DisposeImplementation(object instance)
{
}
public object GetImplementationOf(Type type)
{
return this._kernel.Get(type);
}
public Interface GetImplementationOf<Interface>(Type type)
{
return (Interface)this._kernel.Get(type);
}
public Interface GetImplementationOf<Interface>()
{
return this._kernel.Get<Interface>();
}
}
EDIT
Ok I've stepped through the code some and here are some more details.
So the general path in which it fails is like this:
CreateIoCController<MyController>
GetImplementationOf<MyController>
kernel.Get<MyContoller>
*fails on resolution with multiple bindings
Here's what I've tracked down. Just before entering kernel.Get, the bindings are correct. Here is the internal bindings collection:
{Name = "IRepository`1" FullName = "MySite.Service.Repository.IRepository`1"}
{Name = "PaymentProcessorCredentialCollection" FullName = "MySite.Domain.ECommerce.PaymentProcessorCredentialCollection"}
{Name = "ICCProcessingService" FullName = "MySite.Service.ECommerce.ICCProcessingService"}
{Name = "IACHProcessingService" FullName = "MySite.Service.ECommerce.IACHProcessingService"}
{Name = "IPaymentProcessingService" FullName = "MySite.Service.ECommerce.IPaymentProcessingService"}
{Name = "IEmailSendService" FullName = "MySite.Service.Email.IEmailSendService"}
{Name = "IEmailGenerationService" FullName = "MySite.Service.Email.IEmailGenerationService"}
{Name = "ISessionManager" FullName = "MySite.Service.Repository.NHibernateRepository.SessionManagers.ISessionManager"}
The problem seems to be that sometime during the binding resolution, additional bindings are added to the internal collection.
I looked at the internal bindings collection at the point of exception. The ones of importance that are causing this to blow up are here:
{Name = "IRepository`1" FullName = "MySite.Service.Repository.IRepository`1[[MySite.Domain.ECommerce.CreditCard, MySite.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
{Name = "IRepository`1" FullName = "MySite.Service.Repository.IRepository`1[[MySite.Domain.ECommerce.RecurringPaymentProfile, MySite.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
{Name = "IRepository`1" FullName = "MySite.Service.Repository.IRepository`1[[MySite.Domain.ECommerce.Order, MySite.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
{Name = "IRepository`1" FullName = "MySite.Service.Repository.IRepository`1[[MySite.Domain.ECommerce.Payment, MySite.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
{Name = "IRepository`1" FullName = "MySite.Service.Repository.IRepository`1[[MySite.Domain.ECommerce.BankAccount, MySite.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
{Name = "IRepository`1" FullName = "MySite.Service.Repository.IRepository`1[[MySite.Domain.ECommerce.Product, MySite.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
{Name = "IRepository`1" FullName = "MySite.Service.Repository.IRepository`1[[MySite.Domain.External.PayPalIPN, MySite.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
So for example, when it tries to resolve IRepository, there's two bindings:
{Name = "IRepository`1" FullName = "MySite.Service.Repository.IRepository`1"}
{Name = "IRepository`1" FullName = "MySite.Service.Repository.IRepository`1[[MySite.Domain.ECommerce.Order,MySite.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
The question is, why are these getting added, and how can I stop it? Thanks in advance.