These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 
Author Message
 Post subject: Deserializing ISession after ASP.NET Application restarts
PostPosted: Wed Oct 19, 2005 4:03 pm 
Beginner
Beginner

Joined: Thu May 26, 2005 1:00 pm
Posts: 29
I'm temporarily serializing the ISession to ASP.NET's session state server. However, if the application has been restarted in the meantime (either by updating one of the DLLs or the Web.config file for instance), deserializing the ISession throws an uncatchable exception:
Quote:
[ArgumentNullException: Key cannot be null.
Parameter name: key]
System.Collections.Hashtable.get_Item(Object key) +340
NHibernate.Impl.SessionFactoryObjectFactory.GetNamedInstance(String name)
NHibernate.Impl.SessionFactoryImpl.GetRealObject(StreamingContext context)
System.Runtime.Serialization.ObjectManager.ResolveObjectReference(ObjectHolder holder) +72
System.Runtime.Serialization.ObjectManager.DoFixups() +223
System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, IMethodCallMessage methodCallMessage) +269
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, IMethodCallMessage methodCallMessage) +183
System.Web.Util.AltSerialization.ReadValueFromStream(BinaryReader reader) +765
System.Web.SessionState.SessionDictionary.Deserialize(BinaryReader reader) +98
System.Web.SessionState.StateClientManager.Deserialize(Stream stream, Int32 lockCookie) +133
System.Web.SessionState.OutOfProcStateClientManager.DoGet(String id, StateProtocolExclusive exclusiveAccess) +205
System.Web.SessionState.OutOfProcStateClientManager.GetExclusive(String id) +7
System.Web.SessionState.OutOfProcStateClientManager.System.Web.SessionState.IStateClientManager.BeginGetExclusive(String id, AsyncCallback cb, Object state) +6
System.Web.SessionState.SessionStateModule.GetSessionStateItem() +67
System.Web.SessionState.SessionStateModule.BeginAcquireState(Object source, EventArgs e, AsyncCallback cb, Object extraData) +271
System.Web.AsyncEventExecutionStep.System.Web.HttpApplication+IExecutionStep.Execute() +66
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +173

Unfortunately, all this takes place before my application gets control, so I'm at a bit of a loss for what to do here. Any ideas?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 19, 2005 8:07 pm 
Senior
Senior

Joined: Sat Sep 10, 2005 3:46 pm
Posts: 178
Im curious as to why you are storing the ISession into asp.net's sesison state.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 20, 2005 7:44 am 
Beginner
Beginner

Joined: Sat Apr 17, 2004 1:11 am
Posts: 36
Can the ISession be serialized reliably since it contains a database connection?

benster


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 20, 2005 10:27 am 
Beginner
Beginner

Joined: Thu May 26, 2005 1:00 pm
Posts: 29
Can the ISession be serialized reliably since it contains a database connection?

Yes.
Quote:
session.Disconnect();
this.Session["NhibSession"] = session;
//... on another page load
ISession session = (ISession)this.Session["NhibSession"];
session.Reconnect();

It works quite well except for the case I outlined above.

Im curious as to why you are storing the ISession into asp.net's sesison state.

Because this is the pattern implemented in the application I'm porting to NHibernate. There might be a better way that I'm not currently aware of, but I'd prefer to make as few changes as possible to avoid breaking anything.

However, I'd certainly like to hear other people's suggestions as to how to maintain the changes to an object across requests without persisting them to the database. Entering an "editing page" is like opening an "edit session" in which the changes are not persisted until the user clicks "OK". The application I'm working with currently handles this by maintaining the ISession across page requests, and committing the changes when the user clicks "OK". I believe this is the "session-per-application-transaction" approach, except the application transaction spans multiple page requests/responses.

If there is a better way to accomplish this I'd love to hear it.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 20, 2005 11:25 am 
Expert
Expert

Joined: Fri May 13, 2005 11:13 am
Posts: 292
Location: Rochester, NY
You could use a session-per-request model (I believe there is info about this in the FAQ, along with a link to a simple IHttpModule implementation). Your objects themselves could be held in the session state, and when responding to the "OK" click, Lock the (persistent) object(s) to the session then flush.

I have to say, though, that in a way I do like your pattern. Nonetheless, it doesn't seem to allow for the fragility and intentionally short-lived nature of ISession objects.

-Marc


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 20, 2005 11:46 am 
Beginner
Beginner

Joined: Sat Apr 17, 2004 1:11 am
Posts: 36
naasking wrote:
Can the ISession be serialized reliably since it contains a database connection?

Yes.


Right, but only if it's disconnected. I'm not too familiar with using NH in the HTTP world but I thought using session-per-request was pretty standard where a new session is created for each request. I just haven't seen anyone talk about disconnecting a session, serializing it and then reconnecting it later just because of marcal's point regarding the intention that sessions are short-lived. Depending on how long the session is serialized the data in the session could be pretty stale when it's reconstituted.

Interesting take on things although I think I'd prefer creating new sessions and locking the objects to the new session because of the fear that a session would be serialized for 1/2 hr while a user failed to click on anything and then the session would be very stale.

benster


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 20, 2005 11:49 am 
Senior
Senior

Joined: Sat Sep 10, 2005 3:46 pm
Posts: 178
Yes, I think the best way to solve your problem would be to detach the object form the ISession and store the object in session as opposed to the whole ISession.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 20, 2005 12:52 pm 
Beginner
Beginner

Joined: Thu May 26, 2005 1:00 pm
Posts: 29
You could use a session-per-request model (I believe there is info about this in the FAQ, along with a link to a simple IHttpModule implementation).

I do use the session-per-request, on every page that is not an editing page (ie. pages that require session-per-application-transaction).

Your objects themselves could be held in the session state, and when responding to the "OK" click, Lock the (persistent) object(s) to the session then flush.

Is Lock how you re-attach objects to an ISession? The description in the API reference didn't seem to imply this. In any case, this requires a great deal of manual intervention for each page (to load objects between the HttpSession and the ISession) doesn't it? I'm porting the application to NHibernate, so I want to retain the mimic the semantics as closely as possible. Deadlines you see. :)

Depending on how long the session is serialized the data in the session could be pretty stale when it's reconstituted.

That's perfectly ok. The application was running fine using this pattern and a custom O/R mapper. If data gets stale, the user is notified and has to re-enter their changes; that's what optimistic locking is for. :)

Besides, even if the objects themselves were serialized separately from the ISession then locked into a new one, you'd still have the stale data problem; the data is in the objects after all.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 20, 2005 4:01 pm 
Beginner
Beginner

Joined: Sat Apr 17, 2004 1:11 am
Posts: 36
naasking wrote:
Depending on how long the session is serialized the data in the session could be pretty stale when it's reconstituted.

That's perfectly ok. The application was running fine using this pattern and a custom O/R mapper. If data gets stale, the user is notified and has to re-enter their changes; that's what optimistic locking is for. :)

Besides, even if the objects themselves were serialized separately from the ISession then locked into a new one, you'd still have the stale data problem; the data is in the objects after all.


I didn't necessarily mean the object data as much as the fact that in general the ISession is meant to be a short-lived object because it acts as a 1st level cache. I actually looked at keeping sessions around and disconnecting/reconnecting them early on in my work but abandoned it because of having to deal with object evictions that were cached. It was much easier to create new sessions than to clean existing ones and reuse them. Plus I didn't have to worry as much if there was an exception and I needed to create another session.

In your case locking objects to the new session seems reasonable as there are a number of threads here cautioning against longer running sessions for various reasons. Just MO...

benster


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 08, 2005 9:56 am 
Newbie

Joined: Tue Nov 08, 2005 8:55 am
Posts: 3
We store ISession (actually a wrapper around ISession) in the HttpSession; however, this only works when using InProc Session State. It will fail if using State Server or SQL Server. Which pretty much rules out web farms.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 08, 2005 11:16 am 
Contributor
Contributor

Joined: Thu May 12, 2005 8:45 am
Posts: 226
naasking wrote:
I do use the session-per-request, on every page that is not an editing page (ie. pages that require session-per-application-transaction).


HOW do you use session-per-request? In my understanding, this does not involve the HttpSession at all. I prefer to use the global.asax (HttpApplication) to manage scope. The HttpContext object has a per-request lifecycle, so putting the ISession in there gives you session-per-request.
Code:
public class Global : HttpApplication
{
  private ISessionFactory sf;

  protected void Application_Start(Object sender, EventArgs e)
  {
    sf = // initialize NHibernate SessionFactory
  }

  protected void Application_BeginRequest(Object sender, EventArgs e)
  {
    HttpContext.Current.Items.Add( "nh.session", sf.OpenSession() );
  }

  protected void Application_EndRequest(Object sender, EventArgs e)
  {
    ISession nhSession = HttpContext.Current.Items[ "nh.session" ] as ISession;
    try
    {
      if( nhSession != null ) nhSession.Dispose();
    }
    catch( Exception ex )
    {
      // handle error
    }
  }

  protected void Application_End(Object sender, EventArgs e)
  {
    sf.Dispose();
  }

}


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 08, 2005 2:31 pm 
Beginner
Beginner

Joined: Thu May 26, 2005 1:00 pm
Posts: 29
Quote:
HOW do you use session-per-request? In my understanding, this does not involve the HttpSession at all.

Correct. I have a Page base class. On Page Init, I create an ISession, which is accessible via a protected property. On Unload (or perhaps Dispose), I close the session.
Code:
public class Page : System.Web.UI.Page {
   NHibernate.ISession nSession;
   protected NHibernate.ISession NSession {
      get {return this.nSession;}
   }
   override protected void OnInit(EventArgs e) {
      this.nSession = this.OpenSession();
   }
   public override void Dispose() {
      if (this.NSession != null) {
         this.NSession.Close();
      }
      base.Dispose();
   }
}

This pattern is not the problem though, the problem arises with serialized ISessions.
Quote:
The HttpContext object has a per-request lifecycle, so putting the ISession in there gives you session-per-request.

I initially used HttpContext as well, but I realized it wasn't really necessary since I only need access to the session from the Page itself. It's more straightforward this way, particularly for new developers.
Quote:
We store ISession (actually a wrapper around ISession) in the HttpSession; however, this only works when using InProc Session State. It will fail if using State Server or SQL Server. Which pretty much rules out web farms.

No, the ISession is fully serializable as long as your objects are marked Serializable. The only problem, as I described in the first post, is if the Application restarts while an ISession is serialized (due to an updated DLL for instance). When the ISession is deserialized, NHibernate attempts some sort of lookup which fails for some reason. This is the only thing keeping back session state servers and web farms. Anybody know what's going on?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.