views:

330

answers:

2

I have an ASP.NET 3.5 WebForms application using Ninject 2.0. However, attempting to use the Ninject.Web extension to provide injection into System.Web.UI.Page, I'm getting a null reference to my injected dependency even though if I switch to using a service locator to provide the reference (using Ninject), there's no issue.

My configuration (dumbed down for simplicity):

public partial class Default : PageBase // which is Ninject.Web.PageBase
{
    [Inject]
    public IClubRepository Repository { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        var something = Repository.GetById(1); // results in null reference exception.
    }
 }

... //global.asax.cs

public class Global : Ninject.Web.NinjectHttpApplication
{
    /// <summary>
    /// Creates a Ninject kernel that will be used to inject objects.
    /// </summary>
    /// <returns>
    /// The created kernel.
    /// </returns>
    protected override IKernel CreateKernel()
    {
        IKernel kernel =
        new StandardKernel(new MyModule());
        return kernel;

    }

..

...

public class MyModule : NinjectModule
{
    public override void Load()
    {
        Bind<IClubRepository>().To<ClubRepository>();
        //...
    }
}

Getting the IClubRepository concrete instance via a service locator works fine (uses same "MyModule"). I.e.

  private readonly IClubRepository _repository = Core.Infrastructure.IoC.TypeResolver.Get<IClubRepository>();

What am I missing?

[Update] Finally got back to this, and it works in Classic Pipeline mode, but not Integrated. Is the classic pipeline a requirement?

[Update 2] Wiring up my OnePerRequestModule was the problem (which had removed in above example for clarity):

    protected override IKernel CreateKernel()
    {
        var module = new OnePerRequestModule();
        module.Init(this);

        IKernel kernel = new StandardKernel(new MyModule());

        return kernel;
    }

...needs to be:

    protected override IKernel CreateKernel()
    {
        IKernel kernel = new StandardKernel(new MyModule());

        var module = new OnePerRequestModule();
        module.Init(this);

        return kernel;
    }

Thus explaining why I was getting a null reference exception under integrated pipeline (to a Ninject injected dependency, or just a page load for a page inheriting from Ninject.Web.PageBase - whatever came first).

+1  A: 

This is fairly puzzling because from what I can tell it appears that you have everything configured correctly. From the fact that you are getting a Null Reference Exception instead of an ActivationException, it would seem that the page level injection does not appear to be happening. Typically this is due to the protection level of the property being injected, but based on your code there is no issue there. Here are some things you can try to help track down what this issue is:

  1. The call to Kernel.Inject(this), which initiates the property injection for Ninject is done in the OnInit method of the PageBase class. If for some reason this method is not getting executed it could result in the issue your seeing. You can do some further investigation by overriding the RequestActivation() method, which is the method called to do the actual injection (be sure to call base.RequestActivation()). If your override is never called, then there is an issue with the OnInit.

  2. The InjectAttribute is set up in the default kernel configuration, so there should not be any need to specify it, however if you wanted to be extra certain, you could set up the attribute mapping in your kernel set up by doing something like:

    IKernel kernel = new StandardKernel(new NinjectSettings { InjectAttribute = typeof(InjectAttribute) },new MyModule());

  3. The kernel instance used by the PageBase class for the injection (and likewise the one that should be instantiated by your CreateKernel override in your Global.asax.cs) is stored in a service locator type object in Ninject.Web.KernelContainer. I would make sure you can see the Kernel property on KernelContainer and that it is not null from your Page_Load method.

Thats all I've got at the moment as far as insight. Like I said it appears from here that you have all of your ducks dressed and put in rows, so they should be working....

Good luck tracking down the issue.

ckramer
Thx for the thorough discussion of possible issues - very informative. 1. Tried in OnLoad, as well as wiring up Page_Load. Same result. Will try with base.RequestActivation() and the following recommendations. All in all weird that it's not working, but thanks for the tips - will get back with results.
Ted
Please note that this works with classic pipeline, but strangely enough does not work with integrated. Results in [NullReferenceException: Object reference not set to an instance of an object.] System.Web.PipelineStepManager.ResumeSteps(Exception error) +1216 System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb) +113 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +616
Ted
Thats pretty shocking...I guess there are some subtle changes to the way web applications work with the Integrated Pipeline??? That is truly bizzare. This one might be worth a bug report to the Ninject dev team.
ckramer
A: 

This may not be specific to Ninject. I can get the same exception running in integrated mode with no IoC. I just have a simple asp.net app that just contains one aspx page with no logic.

In my global.asax file i have the following:

public class Global : HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        this.EndRequest += new EventHandler(Global_EndRequest);
    }

    void Global_EndRequest(object sender, EventArgs e)
    {
        // do stuff
    }

Basically subscribing to an event in the application_start causes this exception for me when running in integrated pipeline mode. Switching to classic pipeline or removing the event subscription and handler makes the error go away. I'm running IIS 7.5 on Win7 Enterprise 64bit.

This may not solve your specific problem but i'm posting here as this is the only page that came up when i pasted the exception into google! I'll move my answer into a separate question when i'm allowed to ask one. I have no stackoverflow kudos yet :(

rob bentley
Rob: that looks a little messed to me. Why would you attempt to subscribe to an event in the application start event? Just use the Application_End event already in Global? Or if you're trying to do at the end of every request, then Application_EndRequest?
Ted
For other issues with integrated and application_start that are different from before, see http://mvolo.com/blogs/serverside/archive/2007/11/10/Integrated-mode-Request-is-not-available-in-this-context-in-Application_5F00_Start.aspx
Ted
Anyone ever determine what's going on here?I'm having the same problem, and was hoping someone would have figured it out by now.
Fred Chateau