0
votes

I have an existing web project that I converted to use Ninject with the bindings set to InRequestScope.

// binding in AppStart
kernel.Bind<IDbContext>().To<DbContext>().InRequestScope();

...

// business layer
public class BusinessService {
    public BusinessService(IDbContext context) {
        this.Context = context;
    }

    private IDbContext Context { get; set; }

    public void UpdateUser(int userId) {
        User user = this.Context.Users.Single(u => u.UserId == userId);
        user.LastUpdated = DateTime.Now;
        this.Context.SaveChanges();
    }
}

Now, I'm trying to convert a few console apps that use the code in the business layer.

// ... Console App ...
foreach(int userId in usersNeedingToBeUpdated) {
    // do stuff to each user
    BusinessService businessService = kernel.Get<BusinessService>();
    businessLayer.UpdateUser(userId);
}

However, I'm having trouble with understanding the scope. I would like each time I do kernel.Get() for Ninject to give me a new IDbContext and dispose of the old IDbContext. I tried doing

kernel.Bind<IDbContext>().To<DbContext>().InParentScope();

And this works until someone requests the IDbContext directly:

kernel.Get<IDbContext>();

Then I get a null pointer exception because there isn't a parent scope. If I used TransientScope instead, then Ninject doesn't dispose of the IDbContext1. How can I get it to where for every kernel.Get<>() I get a new service as well as new dependencies and the old dependencies are disposed?

I have read this post, but I'm still unsure of what to do.

2
See here for an explanation of how InRequestScope works and hopefully giving you enough detail for you to figure out what you need.qujck

2 Answers

1
votes

For your console app, if you do

kernel.Get<IDbContext>();

Then the only (predefined) scopes available to you are:

  • .InSingletonScope()
  • .InTransientScope()
  • .InThreadScope()
  • .InCallScope()

Why? The others rely on a ninject context being there. For example '.InParentScope()" will look for the object where IDbContext is injected into (by constructor - or property injection) - but there is none, since you did kernel.Get<...>. So it fails.

Most of the scopes which are usable with kernel.Get<> won't help you. Maybe if your console application lifecycle is tightly coupled to the one of the IDbContext and IDbContext is used in several objects in the console application, then it might make sense to use .InSingletonScope(). With '.InSingletonScope()' ninject instanciates the object on first request and disposes it when the kernel is disposed / shut down. However '.InSingletonScope()' is certainly no fit for you web project.

So basically you will need two different bindings:

  • Bind<IDbContext>().To<DbContext>().InRequestScope(); for the web application
  • Bind<IDbContext>().To<DbContext>(); (default transient scope) for the console application

As a hack, in case you don't want to define separate bindings, you could also just do

kernel.Get<DbContext>();

in the console application.

There's lots of other possibilities but they highly depend on your use case / implementation. You could implement you own scope with '.InScope()'

Also see https://github.com/ninject/ninject/wiki/Object-Scopes

0
votes

Since it looks like you are possibly storing the DbContext instance after you create it, you should be able to just ignore the scopes all together. By default, Ninject will return a new instance if no scopes are defined because InTransientScope() is the default.

https://github.com/ninject/ninject/wiki/Object-Scopes

You can also implement your own mechanism to returning specific instances if you want. There are instructions for doing so in the link I provided above.

Hopefully I read your question correctly.