3

I'm trying to use Ninject for an MVC5 application and I want to know if there's any way I can configure it so that instantiate a single object per Controller (I'm not sure if it the same as per request), use that instance in any Action of the controller and once the Action has finished release all the resources that the object utilized.

The class that I want Ninject to inject in my controllers implements the IDisposable interface.

So far I have tried this:

  private static void RegisterServices(IKernel kernel)
  {
     kernel.Bind<IUnitOfWork>().To<SqlUnitOfWork>();
  }

But the Dispose method never gets called. I also tried InRequestScope, but it didn't work either.

So far the only thing that has actually worked is wrapping the instantiation of the object that I need in a using statement in EVERY Controller's Action.

Something like this:

using (var uow = UnitOfWorkFactory.Create())
{
  var repos = new UserRepository(uow);

  uow.SaveChanges();
}

EDIT:

The NinjectWebCommon class added by the Ninject package

 public static class NinjectWebCommon
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();

        /// <summary>
        /// Starts the application
        /// </summary>
        public static void Start()
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }

        /// <summary>
        /// Stops the application.
        /// </summary>
        public static void Stop()
        {
            bootstrapper.ShutDown();
        }

        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        private static IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            try
            {
                kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
                kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

                RegisterServices(kernel);
                return kernel;
            }
            catch
            {
                kernel.Dispose();
                throw;
            }
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<IUnitOfWork>().To<SqlUnitOfWork>().InRequestScope();
        }
    }

As you can see from the code above, now I'm using kernel.Bind<IUnitOfWork>().To<SqlUnitOfWork>().InRequestScope();, but the Dispose method of my class still never gets called.

Is there really any way to achieve with Ninject the same behaviour we get with a using statement, that is, when the object created is done being used (the last line of code in the Controller's Action is processed) the Dispose method of that object is called?

eddy
  • 4,373
  • 16
  • 60
  • 94
  • [InRequestScope](https://github.com/ninject/Ninject.Web.Common/wiki/InRequestScope) should work. Why doesn't it work for you? – Steven Oct 23 '16 at 11:46
  • @Steven Because when I put a break point in the `Dispose` method and start debugging, that method never gets called. Perhaps it has something to do with the `Controller` lifecycle or that I'm not setting up Ninject correctly, mainly because it is not clear to me how to use `InRequestScope` – eddy Oct 23 '16 at 14:22
  • @Steven I edited my question to add the `NinjectWebCommon` class, but I'm still not getting what I need. – eddy Oct 23 '16 at 15:22
  • You are creating multiple Bootstrapper classes. Could that be the cause of your problems? – Steven Oct 23 '16 at 15:26
  • @Steven Well to tell you the truth I haven't touched that class other than to add this line `kernel.Bind().To().InRequestScope();` – eddy Oct 23 '16 at 17:55
  • 1
    @eddy long time since I did anything with Ninject https://github.com/ninject/ninject/issues/132#issuecomment-42459686 – Ruben Bartelink Oct 23 '16 at 19:00
  • @RubenBartelink I've been doing some tests and it seems to be working now. Upgrading all the Ninject packages to their latest versions fixed this issue for me. Please add this as an answer so that I can accept it. Thanks :) – eddy Oct 23 '16 at 19:57

1 Answers1

1

There's a Module within Ninject that needs to be installed, configured (and up to date)[https://github.com/ninject/ninject/issues/132#issuecomment-42459686] for this to be done deterministically at the end of each request (vs driven by GC).

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249