views:

376

answers:

3

I'm learning NHibernate and was looking at some code recently where NHibernate was used in an ASP.Net MVC project.

In a certain part of this app, entities loaded from NH are being kept in the (HttpContext) Session. Is this OK, or are there any dangers with this if you use (NHibernate) Session-per-request pattern?

+1  A: 

I wouldn't recommend it unless you really know what you're doing. Off the top of my head:

  • Entities stored in httpsession would have to be fully serializable, otherwise non-inproc session storage would break.
  • Lazy loading would break unless you explicitly reattach the entity to the new session.

If you want to have cross-request conversations check out NHibernate.Burrow which is a framework designed for this specific purpose.

Mauricio Scheffer
A: 

"Session per request" with NHibernate does not have a relationship with HttpSession. "Session" in session per request is the NHibernate ISession. It's safe to store NHibernate.ISession in HttpContext.Current.Items at the beginning of the request and dispose it at the end of the request.

Paco
I know that. Maybe I didn't make myself clear, however the question was whether it's safe to store an entity (loaded from NH ISession) in the (Http) Session, when the NH ISession is indeed disposed of at the end of the request. I'm pretty sure it's problematic, but I would like to know what problems are being introduced.
jeroenh
The biggest problem with storing large objects in HttpSession are memory leaks. You can better store a reference to a large object in the HttpSession instead of the large object itself
Paco
A: 

Yes you can and it does make sense to cache a frequently used object if you are fetching it based on a property that is not the primary key.

My site has a Person class which represents a specific user on the site. On any given web request I need to fetch the current logged-in user object several times to access various configuration settings and properties that are specific to the current user. Rather than hitting the database every time, I store the current user in HttpContext.Items[] and I have a static method that checks if the Items cache contains the current user. If it does, return it, if it doesn't get it from the database and add it to the cache so its available next time:

    public static Person CurrentUser
    {
        get
        {
            if(!IsAuthenticated) return null;
            Person person = (Person) HttpContext.Current.Items[HttpContext.Current.User.Identity.Name];
            if(person != null) return person;

            IPersonDao personDao = new PersonDao();
            person = personDao.getByUsernameEmail(HttpContext.Current.User.Identity.Name);
            if(person==null)
            {
                FormsAuthentication.SignOut();
                HttpContext.Current.Response.Redirect("/");
            }
            HttpContext.Current.Items[HttpContext.Current.User.Identity.Name] = person;
            return person;
        }
    }

I also store my NHibernate session object in HttpContext.Items so the session and the cached object will be garbage collected at the same time at the end of the HttpRequest, what you don't want is for the object to survive past the lifetime of the session, otherwise a new session may start and NHibernate will barf with a NHibernate.NonUniqueObjectException because the object is bound to another session.

Its worth pointing out that the NHibernate's 1st level cache keeps all objects accessed by the session cached by ID. If I was calling session.get(id) there is no need to cache as NHibernate's 1st level cache maintains objects by their id. But in the above case where I am fetching the person object by the User.Identity.Name the 1st level cache doesn't work as the user's username is not the primary key of the object.

More info on HttpContext.Items http://aspnet.4guysfromrolla.com/articles/060904-1.aspx

DO NOT use HttpContext.Cache, which for some reason lasts beyond the Http Request.

reach4thelasers
the question was about HttpContext Session, **not** about HttpContext.Items
Mauricio Scheffer
His question was about caching an NHibernate object, when managing NHibernate Sessions per request. HttpContext.Session won't work for Session per Request. If he needs to cache an object he needs to use HttpContext.Items[] otherwise the object will survive beyond the lifetime of the NHibernate session.
reach4thelasers