0
votes

I have a class LkCredentials, which is used to store data from SQL table.

[Table(Name = "Credentials")]
public class LkCredentials : LkTable
{
    // Database fields
    [Column(Name = "id", IsPrimaryKey = true)]
    public Binary Uid { get; set; }
    ...

    // Used for dependency injection through Ninject
    public ICustomer Customer { get; set; }

    public LkCredentials(ICustomer Customer) 
    {
        this.Customer = Customer;
    }

    // Data loader from database
    public void Load(string login)
    {
        var user = (new SqlTRepository<LkCredentials>()).DBObject.Where(x => x.Login == login).Single();
        ... // copying data from user to this
    }

I'm using Ninject to inject proper ICustomer class this way:

// Create new instance for correct constructor to run and Ninject to resolve
var cred = new LkCredentials((ICustomer)null);
// Load data from database
cred.Load(model.UserName);

But in the process of loading data (void Load), in the variable user new instance of LkCredentials is created, and compiler demands parameterless constructor to be defined. If I create parameterless constructor, then it will be used to create new instance of LkCredentials, but Ninject will not bind correct class - cause constructor incorrect :( And NullReference exception will be raised.

I tried to create constructors chain:

public LkCredentials() : this((ICustomer)null)
{ }

But it didn't work. What I can do for Ninject to work properly? Any ideas?

P.S.:

Ninject installed as MVC Extension. Ninject injection in controllers works great, with the same bindings.

Ninject bindings from NinjectWebCommon.cs:

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<ICustomer>().ToProvider<ObjectProvider<ICustomer, Customer, Customer82>>();
        kernel.Bind<IAddress>().ToProvider<ObjectProvider<IAddress, Address, ContactInfo>>();
    }

    public class ObjectProvider<T1,T2,T3> : IProvider
    {
        public Type Type { get { return typeof(T1); } }
        public object Create(IContext context)
        {
            var securityInfo = context.Kernel.Get<SecurityInformation>();
            if (securityInfo.isAuthenticated & securityInfo.DatabaseType == "81")
                return context.Kernel.Get<T2>();
            else if (securityInfo.isAuthenticated & securityInfo.DatabaseType == "82")
                return context.Kernel.Get<T3>();
            else
                return context.Kernel.Get<T2>();
        }
    }
2
Ninject will not take over new - in the code above you are passing basically a null ICustomer every time. Have you tried using kernel.Get<ICustomer>() instead? Also, why aren't you injecting SqlTRepository<LkCredentials> into your LkCredentials instance? - Stephen Byrne
@StephenByrne I don't understand, where I should use kernel.Get<ICustomer>() ? - Vasilij
// Create new instance for correct constructor to run and Ninject to resolve var cred = new LkCredentials((ICustomer)null); - perhaps I have misread but I understood this to mean that you expect Ninject to intercept this new operator here. It won't. This is where you would need to use kernel.Get<ICustomer>() (of course you will need to setup Ninject to inject the kernel into instances of LKCredentials) - Stephen Byrne

2 Answers

0
votes

I am a student of Ninject and like it a lot. I think the issue is you need to bind LkCredentials to an ILkCredentials and bind it with a parameter. Something like this:

Bind<ILkCredentials>().To<LkCredentials>().WithConstructorArgument("Customer", "Customer");

In the WithConstructorArgument(, ). It's a little confusing because your parameter name is also the name of the object you want to inject.

Here's another example where the parameter name is "name" and the constructor argument is "Fender":

Bind<IGuitar>().To<Guitar>().WithConstructorArgument("name", "Fender");

Hope that helps.

0
votes

I left parameterless constructor as is, but at the first point, where a need a Customer, I added:

        if (this.Customer == null)
            this.Customer = (ICustomer)System.Web.Mvc.DependencyResolver.Current.GetService(typeof(ICustomer));

It was enough. Great thanks to Stephen Byrne, he gives me great advice!