Anshuman Jasrotia
Anshuman Jasrotia

Reputation: 3185

How to pass parameters down the dependency chain using Ninject

My Class Structure is:

public class PhotoService {

    private IRepository _repo;
    private DTConfig _config;

    public PhotoService(IRepository repo, DTConfig config)
    {    

        _repo = repo;
        _config = config;
    }
}

public class DTConfig
{
     private int _accountId;
     public DTConfig(int accountId)
     {
           _accountId = accountId;
     }
}

My Ninject Bindings are like:

var kernel = new StandardKernel();
kernel.Bind<IPhotoService>().To<PhotoService>();
kernel.Bind<IRepository>().To<Repository>();
kernel.Bind<DTConfig>().ToSelf();

Now what I want, is to pass the accountId as a parameter while creating an instance of PhotoService

var photo = kernel.Get<IPhotoService>(); 

How can I pass the parameter to DTConfig while creating an instance of PhotoService. The accountId is fetched from a service and is not available in compile time.

Feel free to comment if any other information is required.

Upvotes: 3

Views: 2174

Answers (3)

Daniel Park
Daniel Park

Reputation: 4021

While I have found that it is overkill in some situations, using a factory will help provide constructor-like features while preserving the style of writing for injection. This is provided by the Ninject.Extensions.Factory extension.

At a basic level, you create a factory interface which has a matching subset of the constructor arguments. It can both resolve bound components, and require input itself. Here is a slightly modified example from the wiki;

public class Foo
{
    readonly IBarFactory barFactory;

    public Foo(IBarFactory barFactory)
    {
        this.barFactory = barFactory;
    }

    public void Do()
    {
        var bar = this.barFactory.CreateBar("doodad");
        //Do Foo things
        bar.Stuff();
    }
}

public interface IBarFactory
{
    IBar CreateBar(string someParameter);
}
public interface IBar
{
    void Stuff();
}

public class Bar : IBar
{
    public Bar(IDependancy aDependancy, string someParameter)
    {
        //Initialise Object
    }
    public void Stuff()
    {
        //Do Stuff
    }
}

Then by binding a factory with;

_kernel.Bind<IBarFactory>().ToFactory();

the extension will do some magic behind the scenes.

In this example, assuming IDependancy is bound correctly, calling the CreateBar method of the factory will resolve any dependancies in parallel with inserting your parameter.

One word of caution, however, is that the parameter names need to be the same.

Upvotes: 4

Dave Thieben
Dave Thieben

Reputation: 5437

Yannick's answer is a good, however, here's an alternative: create an IAccountService that has the logic to find and return the AccountId. Then inject that service into your IPhotoService.

Upvotes: 3

Yannick Meeus
Yannick Meeus

Reputation: 5910

There's the concept of a ConstructorArgument in Ninject, which allows you to pass through variables only known at runtime. The typical example of this would be:

var photoService = kernel.Get<IPhotoService>(new ConstructorArgument("accountId", <your value here>));

Now the caveat with this is that this only goes one level deep. There is however a contructor that accepts a bool flag called shouldInherit, which allows your values to propagate to the children when resolving the concrete types:

var photoService  = kernel.Get<IPhotoService>(new ConstructorArgument("accountId", <your value here>, shouldInherit:true));

Upvotes: 7

Related Questions