Dependency injection into referenced project
Asked Answered
B

2

0

I've been trying to achieve something with Ninject (without a great understanding of the library) and have realized it may not be possible to do what I want.

I've got one of our own projects that I've referenced, and was attempting to use Ninject to push some dependencies in, something like:

public class ImageHelper
{
        [Inject]
        public static AdaptiveImageSettings Settings { get; set; }

        [Inject]
        public static IImageSizerFactory Factory { get; set; }
    }
}

The aim is to have some settings (which can be served by different classes) and a Factory who can create instances of an ImageHelper class. I'm not too caught up on what's static and what isn't right now.

If I try and use my ImageHelper from a WebApplication referencing that project however these properties are always null. From a Page in my WebApplication with the following the dependencies are injected fine:

 public partial class _Default : Page
 {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        [Inject]
        public NetC.Core.ImageSizer.IImageSizerFactory Factory { get; set; }
 }

From what I've read this is because the Kernel does get handled automatically, but I can't seem to figure out a way of getting access to the Kernel so I can resolve those properties. Can someone give me some pointers on what if this is reasonably possible, or what the next step might be? So far I've only seen the ServiceLocator anti-pattern and can't seem to find an extension that fits the bill.

Beth answered 2/6, 2014 at 8:8 Comment(4)
How do you resolve the Factory in your page? Because that looks strange - you seem to claim that Ninject succesfully resolves the factory but doesn't resolve its internal dependencies. Of course, these properties are static, this could be a reason Ninject doesn't want to touch them. Did you try to have instance properties there?Banjermasin
@WiktorZychla: The factory is resolved just using the InjectAttribute (I've obviously got a KernelBinds elsewhere in NinjectWebCommon). But I guess Ninject does something on the page, but does 'know' or 'intercept' requests on the ImageHelper? I've tried making the properties instance based on that didn't make any difference.Beth
Ninject knows this because it augments the OnPageInitComplete with a simple call to kernel.Inject(page) as described here. #4934195 However, resolving the property dependency should still work recursively and thus, I have no idea why instance properties on your image helper are not resolved. My idea would be to try constructor injection there. Could you try and report back?Banjermasin
The recursion may be the issue - the ImageHelper doesn't live on the Page at this point.Beth
C
0

Seems like a bad use case for any container.

Just assign them manually at application startup

Colb answered 2/6, 2014 at 8:36 Comment(0)
M
0

You should move to constructor injection:

public class ImageHelper
{
    private readonly AdaptiveImageSettings settings;
    private readonly IImageSizerFactory factory;

    public ImageHelper(AdaptiveImageSettings settings, IImageSizerFactory factory) {
        this.settings = settings;
        this.factory = factory;
    }
}

When you request an ImageHelper from Ninject, ninject will automatically inject the proper dependencies into its constructor. Constructor has many advantages such as:

  • It explicitly states what a type requires and becomes the contract.
  • The defining type doesn't have to know anything about the lifestyle of the dependencies (while your ImageHelper forces its dependencies to be singleton).
  • Dependencies can't be forgotten (the constructor requires them).

So whenever you can, go for constructor injection as much as possible.

Marchellemarcher answered 3/6, 2014 at 8:24 Comment(3)
Surely Ninject needs to know about the instance however? For example MVC Controllers, doesn't it intercept their construction somehow to resolve dependency resolution?Beth
@Ian: Ninject can sometimes resolve unregistered types (for instance ImageHelper because it is concrete), but it's usually best to explicitly register everything. So you should register (bind) ImageHelper, AdaptiveImageSettings and IImageSizerFactory.Marchellemarcher
Could you explain the binding a little further? I've currently got binding definitions along the lines of kernel.Bind<IImageSizerFactory>(new ImageSizerFactory()), are you referring to registering the ImageHelper's properties somehow?Beth

© 2022 - 2024 — McMap. All rights reserved.