Per Web Request Lifetime Manager

May 12, 2011 at 6:26 PM
Edited May 13, 2011 at 7:53 AM

Hello,

I am trying to use the open session in view pattern to store an NHibernate session for the current request.

My code is:

 

public class RequestLifetimeManager : LifetimeManager
{
	private readonly Guid id = Guid.NewGuid();

	public override Object GetValue()
	{
		lock (HttpContext.Current.Items)
		{
			Object value = HttpContext.Current.Items[this.id.ToString()];
			return (value);
		}
	}

	public override void RemoveValue()
	{
		lock (HttpContext.Current.Items)
		{
			HttpContext.Current.Items.Remove(this.id.ToString());
		}
	}

	public override void SetValue(Object newValue)
	{
		lock (HttpContext.Current.Items)
		{
			HttpContext.Current.Items[this.id.ToString()] = newValue;
		}
	}
}

 

I register the current instance in Application_BeginRequest and dispose of it in Application_EndRequest (I know modules are better, but that is not the issue):

 

protected void Application_BeginRequest(Object sender, EventArgs e)
{
	if (this.NeedsProcessing == true)
	{
		ISession session = ServiceLocator.Current.GetInstance<ISessionFactory>().OpenSession();

		unity.RegisterInstance(session, new RequestLifetimeManager());
	}
}

protected void Application_EndRequest(Object sender, EventArgs e)
{
	if (this.NeedsProcessing == true)
	{
		ISession session = ServiceLocator.Current.GetInstance<ISession>();

		if (session != null)
		{
			session.Dispose();
			//should never happen, but it does!
		}
	}
}

 


Sometimes, the current session is null, and the Application_EndRequest method. Inspecting the unity registrations, I can see my object is there, however, it is not being returned by the Resolve<T> method!

Any ideas why this is happening?

Thanks!

RP

May 13, 2011 at 7:36 PM

Has no one ever had this problem?

It seems very unlikely that I'm the only one... and I think my implementation of the lifetime manager is good...

RP

May 13, 2011 at 9:02 PM

Just found out: the problem is that I am not removing the instance (because Unity does not allow removal) on Application_EndRequest. The second registration overrides the first, and so the first can never be found.

The only way to solve this seems to me CreateChildContainer...

RP

May 15, 2011 at 8:32 PM

Hi,

Using RegisterInstance bypasses your lifetime manager.  Lifetime managers are responsbile for creating instances, whereas you supplied the instance to use so the lifetime is redundant.

If you want the desired behaviour I would suggest you move your Application_BeginRequest logic into your lifetime manager, or use child containers.  If you use a lifetime manager, you will need to hook into an event to remove your instance if your ISession implementation requires disposal.  Disposing child containers automatically dispose all registered items as well.

 

I would like to make a note about your NeedsProcessing property ( ?field ) in your sample code.  If this is in the global.asax then I hope this property is backed by request-based ( ie Context or Session ) storage.

May 16, 2011 at 8:43 AM

@rslaney:

Thanks, I am already using a child container, because Unity does not allow removing a registered instance. 

As for NeedsProcessing, it's a simple property that lets me know if the request is for dynamic content (ASPX, ASMX, SVC, etc), not static (PNG, CSS, etc).

RP