Incredibly, Unity only offers a Thread based lifetime manager – which is not appropriate for Web Scenarios.
Either use Ninject (as it has one baked in), or use the following when registering Services.
Code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.Practices.Unity;
namespace XAct.Services.IoC
{
/// <summary>
/// An implementation of the Unity Lifetime Manager specifically for
/// Web scenarios.
/// </summary>
/// <remarks>
/// <para>
/// Used by <see cref="XAct.Services.ServiceLocatorService"/> when
/// trying to register services by WebRequest.
/// </para>
/// </remarks>
/// <internal>
/// See: http://bit.ly/yyguHs
/// </internal>
public class HttpContextLifetimeManager : PerThreadLifetimeManager, IDisposable
{
private readonly string _key = Guid.NewGuid().ToString();
#region Constants
/// <summary>
/// Class of constants used within the
/// <see cref = "Environment" />
/// class.
/// </summary>
public static class Constants
{
/// <summary>
/// Constant used to save the ApplicationName in the Request's hashtable.
/// </summary>
public const string ApplicationNameKey = "ApplicationName";
/// <summary>
/// FQN of System.Web
/// </summary>
public const string SystemWebAssemblyString =
"System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
}
#endregion
/// <summary>
/// Retrieve a value from the backing store associated with this Lifetime policy.
/// </summary>
/// <returns>
/// the object desired, or null if no such object is currently stored.
/// </returns>
public override object GetValue()
{
if (HttpContext == null)
{
return base.GetValue();
}
return InnerDict[_key];
}
/// <summary>
/// Remove the given object from backing store.
/// </summary>
public override void RemoveValue()
{
if (HttpContext==null)
{
base.RemoveValue();
return;
}
InnerDict.Remove(_key);
}
/// <summary>
/// Stores the given value into backing store for retrieval later.
/// </summary>
/// <param name="newValue">The object being stored.</param>
public override void SetValue(object newValue)
{
if (HttpContext == null)
{
base.SetValue(newValue);
}
InnerDict[_key] = newValue;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
RemoveValue();
}
private IDictionary InnerDict
{
get
{
const string key = "Unity.HttpContextLifetimeManager.Cache";
IDictionary results = HttpContextItems[key] as IDictionary;
if (results == null)
{
results = new Dictionary<object, object>();
HttpContextItems.Add(key, results);
}
return results;
}
}
///<summary>
/// The HttpContext by Reflection
/// (so that this assembly does not end up having a reference
/// to System.Web)
///</summary>
public static object HttpContext
{
get
{
if (_cachedHttpContextPropertyInfo == null)
{
const string path = "System.Web.HttpContext";
const string assemblyName = Constants.SystemWebAssemblyString;
const string contextPath = "Current";
Type type = Type.GetType(path + ", " + assemblyName, true, true);
if (type == null)
{
return null;
}
//get the HTTP context property info
_cachedHttpContextPropertyInfo = type.GetProperty(contextPath,
(BindingFlags.Public | BindingFlags.Static));
}
//get a reference to the current HTTP context
return _cachedHttpContextPropertyInfo.GetValue(null, null);
}
}
private static PropertyInfo _cachedHttpContextPropertyInfo;
/// <summary>
/// Gets the items.
/// </summary>
public IDictionary HttpContextItems
{
get
{
if (HttpContext != null)
{
IDictionary items = HttpContext.GetValue("Items") as IDictionary;
return items;
}
throw new Exception("No HttpContext to back HttpContextLifetimeManager");
}
}
}
}