views:

204

answers:

3

I have the Global.asax like the code below:

public class MvcApplication : System.Web.HttpApplication
{
    public static void RegisterRoutes(RouteCollection routes)
    {
    // ....
    }

    protected void Application_Start()
    {
    AreaRegistration.RegisterAllAreas();

    RegisterRoutes(RouteTable.Routes);

    ControllerBuilder.Current.SetControllerFactory(typeof(IOCControllerFactory));
    }
}

public class IOCControllerFactory : DefaultControllerFactory
{
    private readonly IKernel kernel;

    public IOCControllerFactory()
    {
        kernel = new StandardKernel(new NanocrmContainer());
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
            return base.GetControllerInstance(requestContext, controllerType);

        var controller = kernel.TryGet(controllerType) as IController;

        if (controller == null)
            return base.GetControllerInstance(requestContext, controllerType);

        var standartController = controller as Controller;

        if (standartController is IIoCController)
            ((IIoCController)standartController).SetIoc(kernel);

        return standartController;
    }

    class NanocrmContainer : Ninject.Modules.NinjectModule
    {
        public override void Load()
        {
            // ...

            Bind<DomainModel.Entities.db>().ToSelf().InRequestScope().WithConstructorArgument("connection", "Data Source=lims;Initial Catalog=nanocrm;Persist Security Info=True;User ID=***;Password=***");
        }
    }
}

In this case if somewhere it is the class, defined like:

public class UserRepository : IUserRepository
{
    private db dataContext;
    private IUserGroupRepository userGroupRepository;

    public UserRepository(db dataContext, IUserGroupRepository userGroupRepository)
    {
        this.dataContext = dataContext;
        this.userGroupRepository = userGroupRepository;
    }
}

then the dataContext instance is created (if no one was created in this request scope) by Ninject.

So the trouble now is - where to invoke dataContext method .Dispose()?

UPD:

so i followed the advice from KeeperOfTheSoul and solved the issue in such way:

    public override void ReleaseController(IController controller)
    {
        base.ReleaseController(controller);

        var db = kernel.Get<DomainModel.Entities.db>();
        db.Dispose();
    }
+2  A: 

A pattern that is sometimes used to dispose db connections is to call Dispose from the finaliser.

public class db : IDisposable {
   //called by the garbage collector 
   ~db() {
     //Call dispose to make sure the resources are cleaned up
     Dispose(false);
   }

   //IDisposable implementation
   public void Dispose() {
     Dispose(true);
   }
   //subclasses of db can override Dispose(bool) and clean up their own fields
   protected virtual void Dispose (bool disposing) {
     if (disposing) {
       //Supress finalization as all resources are released by this method
       //Calling Dispose on IDisposable members should be done here
       GC.SupressFinalize();
     }
     //Clean up unmanaged resources
     //Do not call other objects as they might be already collected if called from the finalizer
   }
}
Igor Zevaka
For my case (when I use `linq2sql` `dataContext`) I should invoke the parent `.Dispose()` in the end of my `Dispose()` implementation. Right?
zerkms
No need for a finalizer if you're not dealing with unmanaged resources.
KeeperOfTheSoul
Yeah, in that case this might not work as you can't dispose class members that implement IDisposable when called from the finalizer. Kevin Pang's answer might be of more use to you if you need to dispose the object directly.
Igor Zevaka
@KeeperOfTheSoul - that is correct.
Igor Zevaka
+1  A: 

You could hook it into Application_EndRequest.

Kevin Pang
+2  A: 

A good place to handle this is in IControllerFactory.ReleaseController, eg

public override void ReleaseController() {
    base.ReleaseController();
    //Do whatever you need to clean up the IoC container here
}

In NInject this could be handled by scoping using an activation block, at the start of the request when creating the controller you can store the activation block in the HttpContext's current items, during ReleaseController you can retrieve the previously created activation block and dispose it.

You could also consider using InScope and having the custom scope implement INotifyWhenDisposed. After that the usage is the same as with an activation block, except now you store the scope in the HttpContext's current items.

KeeperOfTheSoul