Per Web Request lifestyle Extension methods

Note: For .NET 4.0 users, the ASP.NET Integration NuGet Package contains multiple RegisterPerWebRequest extension methods that replace the examples given here. The SimpleInjector.Integration.Web.dll is part of the default download here on Codeplex.
The following extension methods allows creation of instances with a per web request lifestyle:

using System;
using System.Diagnostics;
using System.Web;
using SimpleInjector;

/// <summary>
/// Extension methods for registering types on a per web request basis.
/// </summary>
public static partial class SimpleInjectorPerWebRequestExtensions
{
    [DebuggerStepThrough]
    public static void RegisterPerWebRequest<TService, TImplementation>(
        this Container container)
        where TService : class
        where TImplementation : class, TService
    {
        Func<TService> instanceCreator = 
            () => container.GetInstance<TImplementation>();

        container.RegisterPerWebRequest<TService>(instanceCreator);
    }

    [DebuggerStepThrough]
    public static void RegisterPerWebRequest<TService>(
        this Container container,
        Func<TService> instanceCreator) where TService : class
    {
        var creator = 
            new PerWebRequestInstanceCreator<TService>(instanceCreator);

        container.Register<TService>(creator.GetInstance);
    }

    [DebuggerStepThrough]
    public static void RegisterPerWebRequest<TConcrete>(this Container container) 
        where TConcrete : class
    {
        container.Register<TConcrete>();

        container.ExpressionBuilt += (sender, e) =>
        {
            if (e.RegisteredServiceType == typeof(TConcrete))
            {
                var transientInstanceCreator = Expression.Lambda<Func<TConcrete>>(
                    e.Expression, new ParameterExpression[0]).Compile();

                var creator = new PerWebRequestInstanceCreator<TConcrete>(
                    transientInstanceCreator);

                e.Expression = Expression.Call(Expression.Constant(creator), 
                    creator.GetType().GetMethod("GetInstance"));
            }
        };
    }

    [DebuggerStepThrough]
    public static void DisposeInstance<TService>() where TService : class
    {
        object key = typeof(PerWebRequestInstanceCreator<TService>);

        var instance = HttpContext.Current.Items[key] as IDisposable;

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

    private sealed class PerWebRequestInstanceCreator<T> where T : class
    {
        private readonly Func<T> instanceCreator;

        internal PerWebRequestInstanceCreator(Func<T> instanceCreator)
        {
            this.instanceCreator = instanceCreator;
        }

        [DebuggerStepThrough]
        public T GetInstance()
        {
            var context = HttpContext.Current;

            if (context == null)
            {
                // No HttpContext: Let's create a transient object.
                return this.instanceCreator();
            }

            object key = this.GetType();

            T instance = (T)context.Items[key];

            if (instance == null)
            {
                context.Items[key] = instance = this.instanceCreator();
            }

            return instance;
        }
    }
}
Usage:
container.RegisterPerWebRequest<IUserRepository, SqlUserRepository>();

// When an instance should be disposed after the request ends, add the
// following code to the Global.asax:
protected void Application_EndRequest()
{
    SimpleInjectorPerWebRequestExtensions.DisposeInstance<IUserRepository>();
}

Last edited Aug 11 at 10:40 AM by dot_NET_Junkie, version 16