So for transactions in webforms I like to create a simple Transaction wrapper extension method to encapsulate the begin/try-commit/catch-rollback/finally - dispose code.
Hi all,
I've been trying to come up with/find a 'best practice' route for NHib session management in ASP.Net WebForms. I'm unable to use IoC containers etc due to architectural features of the code (it's a fixed framework we use internally). What I'm looking for is some pointers on the solution I've come up with, as I'm sure it could be improved.
Keeping it simple, I'm trying to achieve session-per-request with no requirement for transactions. The code below has an overall 'wrapping' transaction because I found if I did a delete then immediately re-loaded the list objects to the page in the same cycle, the deleted object would 're-appear', even though I'd just deleted it (object disappears if I do a page refresh). Not entirely sure why this is if I'm honest! Do I need a Transaction/is it best practice?
Overall code is (the extension stuff is because I'm using IIS6 and found it begins/ends even when loading images etc):
protected void Application_BeginRequest(object sender, EventArgs args)
{
HttpContext context = this.Context;
string filePath = context.Request.FilePath;
string fileExtension = VirtualPathUtility.GetExtension(filePath);
if (fileExtension.Equals(".aspx") || fileExtension.Equals(".ashx"))
{
SessionFactoryManager.Instance.BeginTransaction();
}
}
protected void Application_EndRequest(object sender, EventArgs args)
{
HttpContext context = this.Context;
string filePath = context.Request.FilePath;
string fileExtension = VirtualPathUtility.GetExtension(filePath);
if (fileExtension.Equals(".aspx") || fileExtension.Equals(".ashx"))
{
SessionFactoryManager.Instance.CommitTransaction();
SessionFactoryManager.Instance.CloseSession();
}
}
The session manager is a singleton and the interesting bits are:
public ISession GetSession()
{
ISession session = ContextSession;
if (session == null)
{
session = sessionFactory.OpenSession();
session.FlushMode = FlushMode.Commit;
ContextSession = session;
}
//Check.Ensure(session != null, "session was null");
return session;
}
public void BeginTransaction()
{
ITransaction transaction = ContextTransaction;
if (transaction == null)
{
transaction = GetSession().BeginTransaction();
ContextTransaction = transaction;
}
}
public void CommitTransaction()
{
ITransaction transaction = ContextTransaction;
try
{
if (HasOpenTransaction())
{
transaction.Commit();
ContextTransaction = null;
}
}
catch (HibernateException)
{
RollbackTransaction();
throw;
}
}
/// <summary>
/// If within a web context, this uses <see cref="HttpContext" /> instead of the WinForms
/// specific <see cref="CallContext" />. Discussion concerning this found at
/// </summary>
private ITransaction ContextTransaction
{
get
{
if (IsInWebContext())
{
return (ITransaction)HttpContext.Current.Items[TRANSACTION_KEY];
}
else
{
return (ITransaction)CallContext.GetData(TRANSACTION_KEY);
}
}
set
{
if (IsInWebContext())
{
HttpContext.Current.Items[TRANSACTION_KEY] = value;
}
else
{
CallContext.SetData(TRANSACTION_KEY, value);
}
}
}
/// <summary>
/// If within a web context, this uses <see cref="HttpContext" /> instead of the WinForms
/// specific <see cref="CallContext" />. Discussion concerning this found at
/// </summary>
private ISession ContextSession
{
get
{
if (IsInWebContext())
{
return (ISession)HttpContext.Current.Items[SESSION_KEY];
}
else
{
return (ISession)CallContext.GetData(SESSION_KEY);
}
}
set
{
if (IsInWebContext())
{
HttpContext.Current.Items[SESSION_KEY] = value;
}
else
{
CallContext.SetData(SESSION_KEY, value);
}
}
}
private bool IsInWebContext()
{
return HttpContext.Current != null;
}
Thanks for any thoughts on the above, as I've been finding it really hard to track down current information regarding NHibernate and WebForms without the use of IoC frameworks to manage sessions, etc.
Thanks,
Paul