dimiguel
dimiguel

Reputation: 1579

HttpContext is null when accessing injected object with Ninject on first request through async/await

I'm getting an extremely cryptic error on my first request to my web server on a Task<ActionResult> method. Afterwards the server runs fine and no crashes occur. The error says:

Value cannot be null. Parameter name: httpContext

And it crashes on the first line:

 public async Task<ActionResult> Index()
    {
        var account = await Data.Of<Account>()
            .AsQueryable(a => a.Id == WebSecurity.CurrentUserId,
                "AllowedReportTypes",
                "AllowedReports.Parameters.ParameterChoices",
                "AllowedReports.ReportType",
                "AllowedBusinesses")
            .FirstOrDefaultAsync();

Where Data is an IWorker interface that is injected through Ninject like this:

kernel.Bind(typeof (IWorker<>))
    .To(typeof (Worker<>))
    .When(x=> HttpContext.Current == null)
    .InThreadScope();
kernel.Bind(typeof (IWorker<>))
    .To(typeof (Worker<>))
    .When(x => HttpContext.Current != null)
    .InRequestScope();

GlobalConfiguration.Configuration.DependencyResolver = 
    new NinjectDependencyResolver(kernel);

This issue only happens when I'm using async/await actions. When they are synchronous, this issue never happens.

Can anyone tell me why this code would crash on my first request and not any subsequent requests? Thanks.

Upvotes: 1

Views: 606

Answers (1)

dimiguel
dimiguel

Reputation: 1579

I haven't had time to update this post, but I've solved my issue. Unfortunately, the infrastructure of my application was poorly designed.

The Ninject kernel was exposed through a class library that was referenced by my user interface project. This meant that I had to make service calls to the kernel to resolve dependencies. For instance, controllers inherited an abstract class that exposed the property Data, and the abstract class would then have this in its declaration:

public IWorker<DbContext> Data { get { return Kernel.Get(typeof(IWorker<DbContext>)); } }

Unfortunately, this is an anti-pattern and it meant that Ninject was not doing much dependency injection. I had to rewrite the entire project (I'm unfortunately still not finished).

The user interface project is now the composite root. I was able to do this quickly by referencing Ninject.Web.Mvc from Nuget, which upon installation created a class named NinjectWebCommon that loads the kernel, its bindings, and sets it as the dependency resolver when the application starts. The hard part was rewriting all of my controllers, views, data access layer, and backend functionality... Ouch.

Upvotes: 1

Related Questions