Creating Object Per Web Request

May 23, 2008 at 10:25 AM
Edited May 23, 2008 at 10:27 AM
I am trying to create a Lifetime Manager for a ASP.NET application which will make sure that the same object will be returned in a single web request. Here is the ode:

public class UnityPerWebRequestLifetimeManager : LifetimeManager, IDisposable
{
private readonly IDictionary _backingStore;
private readonly object _key = new object();

public UnityPerWebRequestLifetimeManager(IDictionary backingStore)
{
//This constructor is needed for TDD;
_backingStore = backingStore;
}

public UnityPerWebRequestLifetimeManager()
{
if ((HttpContext.Current != null) && (HttpContext.Current.Items != null))
{
_backingStore = HttpContext.Current.Items;
}
else
{
//This is needed for TDD;
_backingStore = new Hashtable(StringComparer.InvariantCultureIgnoreCase);
}
}

public void Dispose()
{
Dispose(true);
}

protected void Dispose(bool disposing)
{
Value = null;
}

private object Key
{
[DebuggerStepThrough]
get
{
return _key;
}
}

private IDictionary BackingStore
{
[DebuggerStepThrough]
get
{
return _backingStore;
}
}

private object Value
{
get
{
if (BackingStore.Contains(Key))
{
return BackingStore[Key];
}

return null;
}
set
{
if (BackingStore.Contains(Key))
{
object oldValue = BackingStore[Key];

if (!ReferenceEquals(value, oldValue))
{
TryDispose(oldValue);

if (value == null)
{
BackingStore.Remove(Key);
}
else
{
BackingStore[Key] = value;
}
}
}
else
{
if (value != null)
{
BackingStore.Add(Key, value);
}
}
}
}

public override object GetValue()
{
return Value;
}

public override void SetValue(object value)
{
Value = value;
}

public override void RemoveValue()
{
Value = null;
}

private static void TryDispose(object target)
{
IDisposable disposable = target as IDisposable;

if (disposable != null)
{
disposable.Dispose();
}
}
}

But somehow it is not working, So I am wondering what wrong with it?
May 23, 2008 at 6:00 PM
Please define "not working." Does it throw an exception? Crash? Silently do nothing? Reformat your hard drive?

Also, please include a small test case that demonstrates the problem.

May 24, 2008 at 9:40 PM
Sorry for not posting the remaing codes:

//Interface
public interface IDependencyResolver : IDisposable
{
T Resolve<T>();

T Resolve<T>(string name);

IEnumerable<T> ResolveAll<T>();
}

//Unity Implementation
public class UnityDependencyResolver : IDependencyResolver
{
private readonly IUnityContainer _container;

public UnityDependencyResolver(IUnityContainer container)
{
Validate.Argument.IsNotNull(container, "container");

_container = container;
}

public UnityDependencyResolver():this(new UnityContainer())
{
UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
configuration.Containers.Default.Configure(_container);
}

public void Dispose()
{
_container.Dispose();
}

public T Resolve<T>()
{
return _container.Resolve<T>();
}

public T Resolve<T>(string name)
{
Validate.Argument.IsNotEmpty(name, "name");

return _container.Resolve<T>(name);
}

public IEnumerable<T> ResolveAll<T>()
{
return _container.ResolveAll<T>();
}
}

And Lastly I have a static class which I am using for Resolving the dependency:

public static class IoC
{
private static IDependencyResolver _resolver;

private static IDependencyResolver Resolver
{
[DebuggerStepThrough]
get
{
return _resolver;
}
}

public static void InitializeWith(IDependencyResolver resolver)
{
_resolver = resolver;
}

public static void InitializeWithDefaultResolver()
{
InitializeWith(new UnityDependencyResolver());
}

public static T Resolve<T>()
{
return Resolver.Resolve<T>();
}

public static T Resolve<T>(string name)
{
Validate.Argument.IsNotEmpty(name, "name");

return Resolver.Resolve<T>(name);
}

public static IEnumerable<T> ResolveAll<T>()
{
return Resolver.ResolveAll<T>();
}
}

In the Application_Start event I am callling the IoC.InitializeWithDefaultResolver(). In my configuration file i am specifying the UnityPerWebRequestLifetimeManager as lifetime manager for certain objects.

Okay not working means, it is not creating object as per request, instead the same object is shared in the all the web requests.

So what is the resolution, given that I dont want to create/configure the container per request instead i want to share the same container with all the request but certain object which uses the above lifetime manager will be created per request.
Does it now make sense?
May 24, 2008 at 10:02 PM
Edited May 24, 2008 at 10:33 PM
Just as a Note that I want a similar thing like Windsor lifeStyle="PerWebRequest"
May 25, 2008 at 3:37 AM
You've got several problems here, but the underlying cause is your attempt to make this testable. In your constructor, you take HttpContext.Current.Items and sock it away, and that's where you store the item.

On the next request, a new instance of HttpContext, with its own items collection, is created by ASP.NET. But you're still using the old one! Thus, you're sharing all the instances across every request.

Refetch the context every time you call Get and you'll be fine.

Also, I would recommend not supporting Disposable this way. You'll end up leaking stuff, since the lifetime manager isn't disposed until the CONTAINER is disposed. As a result, the lifetime manager will only attempt to dispose the item for the current request; all previous requests will have been leaked.

May 26, 2008 at 12:23 PM
Thanks it solves the issue when I try to fetch the HttpContent each time.

Can you pls clarify more on the memory leak issue?