Best Practices Question

236 views
Skip to first unread message

ROBERT L CRAVENS

unread,
Nov 13, 2010, 10:15:45 PM11/13/10
to nin...@googlegroups.com
I have been using Ninject in a ASP.NET MVC application with a database. I am using a repository pattern and have a unit of work object that encapsulates the NHibernate ISession. The following is how I am binding together all the elements:

public class RepositoryModule : NinjectModule
{
    public override void Load()
    {
        /* For demo only...this should be in the web.config. */
        const string connectionString = @"Server=localhost; Port=3306; Database=trucktracker; Uid=root; Pwd='your_own_password';";

        NHibernateHelper helper = new NHibernateHelper(connectionString);
        Bind<ISessionFactory>().ToConstant(helper.SessionFactory)
            .InSingletonScope();

        Bind<IUnitOfWork>().To<UnitOfWork>()
            .InRequestScope();
        Bind<ISession>().ToProvider(new SessionProvider())
            .InRequestScope();
        Bind<IIntKeyedRepository<Truck>>().To<Repository<Truck>>()
            .InRequestScope();
    }
}

public class SessionProvider : Provider<ISession>
{
    protected override ISession CreateInstance(IContext context)
    {
        UnitOfWork unitOfWork = (UnitOfWork)context.Kernel.Get<IUnitOfWork>();
        return unitOfWork.Session;
    }
}

I have the UnitOfWork instance (wrapper around the NHibernate Session and thus the database connection) bound "InRequestScope". (By the way, I know that recently there was a Ninject defect fixing an issue with 'InRequestScope'. I am using Ninject bits that have that defect fixed.)
Here is more info if you want:


A reader brought to my attention that MySQL was starting a lot of threads that are tied to the application when he followed this recipe. I took a look and found that (as expected) Ninject is deactivating UnitOfWork instances at the rate of garbage collection. Left to its own, the rate that Ninject deactivated UnitOrWork instances was not sufficient to keep up with data access. More and more MySQL threads are added. Eventually the server runs out of resources.

Just to be certain everything was working, I forced GC by adding a GC.Collect() call. When I added this, the UnitOfWork instances are collected at a rate where MySQL threads were not continually increasing. Since it appears that I need to take control of the clean up of the UnitOfWork (and db connections), I added the following bit of code to the ASP.NET session end event:

            IUnitOfWork uow = Kernel.Get<IUnitOfWork>();
            uow.Dispose();


This code disposes the unit of work and closes the NHibernate session.

Here are my questions:

1. I thought one of the benefit of using an IOC container was to let it manage the lifetime of the objects. Since I am writing code to manage the end of life of the UnitOfWork, it feels a bit like I am violating some IOC rule. Is the above code recommended? Is there a better approach for managing the lifetime of valuable resources (such as db connections)?

2. I understand that Ninject is used outside of ASP.NET. I also read Nate's explanation how Ninject (circa March 2009) managed the life-cycle of objects (WeakReference and a timer). I was wondering if the 'InRequestScope' life-cycle management could be improved by tapping into the session end event? As per Nate's blog post, it is currently tied to the lifetime of the 'HttpContext.Current' object. Since you have the object, why not register for the end session event and release all the 'InReqestScope' objects?

Thanks for all your help and congrats on the recently release.

Bob


Remo Gloor

unread,
Nov 14, 2010, 8:39:51 PM11/14/10
to ninject
Hi Bob

It should be quite simple to add a better release strategy for
InRequestScope. It has to be implemented in the MVC extension. But I
do not want to add this feature to the current release anymore in
order to not postbone it any more. I see your ponit and add it to the
todo list for the next release Q1.2011 with this feature added in the
development version soon. In the mean time you can add it yourself to
the global asax.

In the end request event handler you have to get the cache and clear
the scope.
without checking against the sources I'd say it is
kernel.Components.Get<ICache>().Clear(HttpContext.Current);

Remo

On 14 Nov., 04:15, ROBERT L CRAVENS <bob.crav...@gmail.com> wrote:
> I have been using Ninject in a ASP.NET MVC application with a database. I am using a repository pattern and have a unit of work object that encapsulates the NHibernate ISession. The following is how I am binding together all the elements:
>
> public class RepositoryModule : NinjectModule
> {
>     public override void Load()
>     {
>         /* For demo only...this should be in the web.config. */
>         const string connectionString = @"Server=localhost; Port=3306; Database=trucktracker; Uid=root; Pwd='your_own_password';";
>
>         NHibernateHelper helper = new NHibernateHelper(connectionString);
>         Bind<ISessionFactory>().ToConstant(helper.SessionFactory)
>             .InSingletonScope();
>
>         Bind<IUnitOfWork>().To<UnitOfWork>()
>             .InRequestScope();
>         Bind<ISession>().ToProvider(new SessionProvider())
>             .InRequestScope();
>         Bind<IIntKeyedRepository<Truck>>().To<Repository<Truck>>()
>             .InRequestScope();
>     }
>
> }
>
> public class SessionProvider : Provider<ISession>
> {
>     protected override ISession CreateInstance(IContext context)
>     {
>         UnitOfWork unitOfWork = (UnitOfWork)context.Kernel.Get<IUnitOfWork>();
>         return unitOfWork.Session;
>     }
>
> }
>
> I have the UnitOfWork instance (wrapper around the NHibernate Session and thus the database connection) bound "InRequestScope". (By the way, I know that recently there was a Ninject defect fixing an issue with 'InRequestScope'. I am using Ninject bits that have that defect fixed.)
> Here is more info if you want:
>
> http://blog.bobcravens.com/2010/07/using-nhibernate-in-asp-net-mvc/http://blog.bobcravens.com/2010/06/the-repository-pattern-with-linq-t...http://blog.bobcravens.com/2010/09/the-repository-pattern-part-2/

Bob Cravens

unread,
Nov 15, 2010, 10:15:18 AM11/15/10
to nin...@googlegroups.com
Hi Remo,

Thanks. I will give that a try and let you know how it works.

Bob

>--
>You received this message because you are subscribed to the Google Groups
>"ninject" group.
>To post to this group, send email to nin...@googlegroups.com.
>To unsubscribe from this group, send email to
>ninject+u...@googlegroups.com.
>For more options, visit this group at
>http://groups.google.com/group/ninject?hl=en.
>


ROBERT L CRAVENS

unread,
Nov 17, 2010, 10:24:05 AM11/17/10
to nin...@googlegroups.com
Hi Remo,

I can confirm that the 'InRequestScope' objects are being deactivated during the end request event when you add the following to the 'NinjectHttpApplication.cs' file:


        protected NinjectHttpApplication()
        {
            EndRequest += NinjectHttpApplication_EndRequest;
        }

        protected static void NinjectHttpApplication_EndRequest(object sender, System.EventArgs e)
        {
            _kernel.Components.Get<ICache>().Clear(HttpContext.Current);
        }


As a test case, I created an object that implemented the IDisposable interface. As a result of the above code, this object was disposed at the end of each request. This works a lot better than waiting for GC for critical resources. Thanks.

Bob


Remo Gloor

unread,
Nov 17, 2010, 11:35:39 AM11/17/10
to ninject
Thanks for the information. I'll add support for this soon to the mvc
and web extensions.
> >>http://blog.bobcravens.com/2010/07/using-nhibernate-in-asp-net-mvc/ht...
Reply all
Reply to author
Forward
0 new messages