views:

80

answers:

0

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.