Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Ninject, if I create a custom provider must I ensure a single instance or can I use the SingleInstance attribute?

I am hoping either Peter or Ruben sees this question as they seem to be the go to guys regarding Ninject. I needed to create a custom provider because I have a class that takes 4 arguments. The two can be injected because they are types but the other two are configuration parameters and are integers. They refer to timeouts in milliseconds.

[SingleInstance]
MyClass
{
    ISomething something;
    IOther other;
    int timeout;
    int delay;

    [Inject]
    MyClass(ISomething something, IOther other, int timeout, int delay)
    {
        this.something = something;
        this.other = other;
        this.timeout = timeout;
        this.delay = delay;
    }
}    

I was previously relying on a factory that I had created to get the config settings for timeout and delay and to inject something and other. Now it seems to get this right I would have to create my own custom provider. Which I am okay with.

A couple of points of extra points:

  1. I know I could use injection on the parameters. But that creates a deceptive API. Objects should be returned in a ready to use state and without those 4 arguments it is not ready to use.
  2. Same argument applies to method injection.

So, my final questions:

  • Does that mean that I am in control of ensuring the single instance again or will Ninject still take care of it via the [SingleInstance] attribute?
  • Should I not just switch back to the factory I had? What do I gain from using Ninject in this case?

UPDATE: Code sample as requested

Then my provider I assume would like something like this:

class MyClassProvider : SimpleProvider<MyClass> {
protected override MyClass CreateInstance(IContext context) {
    int timeout= ConfigurationManager.AppSettings.Get("timeout");
    int delay= ConfiguraionManager.AppSettings.Get("delay");
    ISomething something = new SomethingImpl();
    IOther other = new OtherImpl();
    MyClass newOne = New MyClass(something, other, timeout, delay);
    }
}

But because I am now using a provider does that bypass ninject's mechanisms of ensuring only a single instance of the object is created so do I have to fall back on:

class MyClassProvider : SimpleProvider<MyClass> {

    protected static readonly MyClass myClassInstance;
    private static object locker = new object();

    protected override MyClass CreateInstance(IContext context) {
        if (myClassInstance == null) 
        {
            lock (locker)
            {
                int timeout = ConfigurationManager.AppSettings.Get("timeout");
                int delay = ConfiguraionManager.AppSettings.Get("delay ");
                ISomething something = new SomethingImpl();
                IOther other = new OtherImpl();
                MyClass newOne = New MyClass(something, other, timeout, delay );
            }
            return MyClassInstance
        }
        return myClassInstance
    }
}

Is there something that I am missing?

like image 687
uriDium Avatar asked Feb 24 '10 10:02

uriDium


People also ask

What is ninject used for?

Why use Ninject? Ninject is a lightweight Dependency Injection framework for . NET applications. It helps you split your application into a collection of loosely-coupled, highly-cohesive pieces, and then glues them back together in a flexible manner.

What is a ninject module?

The Ninject modules are the tools used to register the various types with the IoC container. The advantage is that these modules are then kept in their own classes. This allows you to put different tiers/services in their own modules.

What is ninject DLL?

Ninject helps you use the technique of dependency injection to break your applications into loosely-coupled, highly-cohesive components, and then glue them back together in a flexible manner.

Is ninject open source?

License. Ninject is intended to be used in both open-source and commercial environments.


1 Answers

You guys have got quite a good conversation going here, but I thought I'd add an answer to help clarify things based on the original question.

The short answer is that Ninject will still ensure that you have a single instance of an object if you specify .Using<SingletonBehavior> in your binding statement, regardless of the activation mechanism -- i.e. you do not bypass Ninject's mechanisms of ensuring only a single instance of the object is created when using your own provider using .ToProvider syntax -- or .ToMethod syntax for that matter.

You should simply write your provider to supply object instances -- no other semantics are forced on the provider. So, all the typical goo required for creating singleton instances as you provided in your sample above is not required.

As an example, your provider becomes much simpler; although, I've added resolving the ISomething and IOther using the Ninject kernel to your original example:

class MyClassProvider : SimpleProvider<MyClass> {

  protected override MyClass CreateInstance(IContext context) {
    int timeout = ConfigurationManager.AppSettings.Get("timeout");
    int delay = ConfiguraionManager.AppSettings.Get("delay ");
    ISomething something = context.Kernel.Get<ISomething>();
    IOther other = context.Kernel.Get<IOther>();
    return new MyClass(something, other, timeout, delay );
  }
}

Your binding statement in your Ninject module would look like this:

public class MyModule : StandardModule {
  public override void Load() {

    Bind<IMyClass>()
      .ToProvider<MyClassProvider>()
      .Using<SingletonBehavior>();
  }
}

By using the SingletonBehavior Ninject will still give you only one instance of MyClass even though you are using your own provider.

This is pretty easy to test. You can add a DateTime property to your class, set it to DateTime.Now in the constructor and examine the objects returned by multiple calls to Get() -- they'll all have the same time even though you created the class in your provider. Next, change the Using<SingletonBehavior> to Using<TransientBehavior> and observe the difference. You'll get a new one each time, all created by your provider.

Hope this help -- by the way, not sure if I'm the Peter you were talking about, but if so, I'm flattered!

like image 164
Peter Meyer Avatar answered Sep 28 '22 08:09

Peter Meyer