Developer Notes

Cycle Red

Castle: PerWebRequestLifeStyle won’t work from Application_Start

Update: Please read the follow up post on this topic.

I’m using the Castle project to implement dependency injection and inversion of control in my web applications.
Castle supports creating objects on a per-request basis which is a big help in keeping the number of objects created per request to a minimum.

I ran into a problem with this however. The PerWebRequestLifeStyle is implemented using an HttpModule to make sure objects are evicted at the end of a request. This works well except when using Castle from the Application_Start method (or the Init method for that matter).

The Application_Start method is invoked before any modules are initialized for the application and therefore any objects registered with Castle to use the PerWebRequestLifestyle cannot be used in Application_Start.

The problem manifests itself by reporting the module is probably not configured:

Looks like you forgot to register the http module Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule
Add '<add name="PerRequestLifestyle" type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.MicroKernel" />' to the <httpModules> section on your web.config.

Similar problems occur when performing tests outside the web environment because, well, there is no web request obviously.

Workaround
I’ve implemented a workaround by customizing the implementation of the lifestyle manager. This work-around falls back to the TransientLifeStyleManager in case the web context is not available. This enables both testing and application startup to use objects managed per web request.

[Serializable] 
public class PerWebRequestLifestyleManager : Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleManager 
{ 
  public PerWebRequestLifestyleManager() 
  { 
    _fallback = new TransientLifestyleManager(); 
  }

  public override object Resolve( CreationContext context ) 
  { 
    HttpContext current = HttpContext.Current;
    if ( null == current || current.ApplicationInstance == null )    
    {
      // fall back to transient behaviour if not in web context 
      return _fallback.Resolve( context ); 
    } 
    else 
    { 
      return base.Resolve( context ); 
    } 
  }

  public override void Dispose() 
  { 
    _fallback.Dispose(); 
    base.Dispose(); 
  }   
  
  public override void Init( IComponentActivator componentActivator, IKernel kernel, Castle.Core.ComponentModel model ) 
  { 
    base.Init( componentActivator, kernel, model ); 
    _fallback.Init( componentActivator, kernel, model ); 
  }   
  
  private TransientLifestyleManager _fallback; 
}

To make sure Castle uses this custom implementation I’m using a custom AttributeFacility:

internal class AttributeFacility : AbstractFacility
{
   protected override void Init()
   {
      Kernel.ComponentModelCreated += kernel_ComponentModelCreated;
   }

   void kernel_ComponentModelCreated( ComponentModel model )
   {
      var attributes = model.Implementation.GetCustomAttributes( typeof( Castle.Core.LifestyleAttribute ), false );
      if ( attributes.Length > 0 )
      {
         var attr = attributes[ 0 ] as LifestyleAttribute;
         if ( null != attr )
         {
            switch ( attr.Lifestyle )
            {
               case LifestyleType.PerWebRequest:
                  model.CustomLifestyle = typeof( Alanta.Services.PerWebRequestLifestyleManager );
                  model.LifestyleType = LifestyleType.Custom;
                  break;
               default:
                  break;
            }
         }
      }
   }    
}

I usually hook up the facility from code, like this:

var container = new WindsorContainer();
container.AddFacility<AttributeFacility>();

Update : this solution does not work on IIS7 in integrated pipeline mode. In this mode both HttpContext.Current and HttpContext.Current.ApplicationInstance are set so the detection method in the code above does not work.
I haven’t found a clean solution for this yet; I’ve had to resort to setting a flag in Application_Start that controls the behavior of the PerWebRequestLifestyleManager. Check out the demo code to see how this works.

Update : There is a discussion on this subject at the Castle Project Users group.

Update : Download the source code for this solution. The zip contains an ASP.NET MVC 1 demo application (VS 2008). The code in this

20 Comments

  • Image placeholder

    Fabian Fernandez

    01/21/2013

    Marnix, here's my version of PerWebRequestLifestyleManager refactored for Castle 3:

    [Serializable]
    public class PerWebRequestLifestyleManager : ScopedLifestyleManager
    {
    private TransientLifestyleManager fallback;

    public PerWebRequestLifestyleManager()
    : base(new WebRequestScopeAccessor())
    {
    fallback = new TransientLifestyleManager();
    }

    public override object Resolve(CreationContext context, IReleasePolicy releasePolicy)
    {
    HttpContext current = HttpContext.Current;

    if (null == current || current.ApplicationInstance == null)
    {
    // Fall back to transient behavior if not in web context.
    return fallback.Resolve(context, releasePolicy);
    }
    else
    {
    return base.Resolve(context, releasePolicy);
    }
    }

    public override void Dispose()
    {
    fallback.Dispose();

    base.Dispose();
    }

    public override void Init(IComponentActivator componentActivator, IKernel kernel, ComponentModel model)
    {
    base.Init(componentActivator, kernel, model);

    fallback.Init(componentActivator, kernel, model);
    }
    }

  • Image placeholder

    Fabian Fernandez

    01/21/2013

    Hi Marnix!
    Thanks a lot for this post!
    As I was trying to implement your proposed workaround I noted that Castle 3 has removed the PerWebRequestLifeStyleManager, I searched a little and found this.
    It would be nice a workaround version for Castle 3.
    Thanks again!

  • Image placeholder

    Marnix

    01/27/2011

    Looks good Mauricio. Especially since it also has the contextual life style you commented about on my Stack Overflow question a while back.

  • Image placeholder

    Mauricio Scheffer

    01/26/2011

    A while ago I created a contrib project with several lifestyles not included in stock Windsor (hybrid transient-web included).

  • Image placeholder

    Marnix

    09/18/2010

    As far as I know the position of the Castle team is that the behavior of the PerWebRequest lifestyle is by design. They are not planning to fix or change it.

  • Image placeholder

    David Aleu

    09/17/2010

    Anything new about this issue? I'm using Castle 2.5 and in my project your solution doesn't solve my problem (I can access the container but not the registered components).

  • Image placeholder

    Marnix

    01/07/2010

    Hi Bhoomi,

    I've updated the demo code to make it a bit simpler to use. Please download the code again and see if that works for your application.

  • Image placeholder

    Marnix

    01/07/2010

    This comment has been removed by the author.

  • Image placeholder

    Bhoomi

    01/07/2010

    Hi Murki,

    Thanks for the code. Yes your code works correctly.
    I replicated your Web.Config file but still I am getting the same error that is :

    Looks like you forgot to register the http module Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule
    Add '' to the section on your web.config


    It comes from :
    ServiceLocator.Current.GetInstance(commandHandler);

    here commandHandler is a generic of type : ICommandHandler

    Any ideas wht's wrong??

    Thanks again..

  • Image placeholder

    Marnix

    01/06/2010

    Hi Bhoomi,

    I've created a basic demo application that demonstrates my solution and added a link to the blog post.
    Please try the application and let me know if this works for you.

  • Image placeholder

    Bhoomi

    01/03/2010

    Visual Studio 2008.

  • Image placeholder

    Marnix

    01/03/2010

    Hi Bhoomi,

    What version of Visual Studio are you using?

  • Image placeholder

    Bhoomi

    12/31/2009

    I am still having the same problem. Tried various things. Implemented your code also. Tried out ploeh's way also. Nothing seems to work for me. I am using Castle.Windsor 2.0.0.0.
    I am running my solution from VS Integrated environment.

    Pl help.

  • Image placeholder

    ploeh

    11/17/2009

    Regarding getting PerWebRequest to work on IIS7, see my blog post Using Castle Windsor's PerWebRequest lifestyle with ASP.NET MVC on IIS7.

  • Image placeholder

    Marnix

    09/30/2009

    Hi Mausch,

    Good point. I haven't had a chance to report the issue so I've gone and done it right away.

    Thanks,
    Marnix

  • Image placeholder

    Mauricio Scheffer

    09/30/2009

    Hi Marnix, did you try asking on the castle users group? If this is bug it should be fixed.

  • Image placeholder

    Marnix

    07/23/2009

    Hi Murki,

    I haven't read the book, but I think I agree with the author.

    For simple applications where you have a single point of interaction with the datacontext in each request, transient lifestyle would do just fine. When things get more complicated problems will start to appear. For example, I use a filter to inject the current user into controller methods:

    ActionResult DoStuff( [CurrentUser] User current ){
    myRepo.DoStuffWithUser( current );
    }

    The filter retrieves the current user object from the database. In the action method the current user is passed to a repository to do some operations on it.
    If the datacontext has a transient lifestyle the filter and the repository used here would each have their own instance of the datacontext. Using an object retrieved by one datacontext to perform database operations in another will cause problems because datacontexts track their objects. The second datacontext does not 'own' the object retrieved by the first datacontext and will either throw an exception or try to insert it (again!).

    PerWebRequest lifestyle will prevent these problems because both the filter and the repository would get the same instance of the datacontext.

  • Image placeholder

    Unknown

    07/22/2009

    Hi Marnix,

    Yeah, I'm basing some parts of my design on the suggestions of the book of "Pro ASP.NET MVC Framework" about using a PerWebRequest lifestyle in conjunction with Linq 2 Sql DataContext, but there the author contrast it against the default of "Singleton" which makes a lot of sense. Still I can't see how using a Transient lifestyle would make impossible to still use the DataContext, it would be an overkill maybe, but I don't think "impossible".

  • Image placeholder

    Marnix

    07/15/2009

    Hi Murki,

    A transient lifestyle would mean that every time you resolve a service a new instance is created. That may not be a problem in itself but needless creation of objects is a waste of server resources (mostly memory).
    Also, I tend to use PerWebRequest lifestyle for things like a Linq DataContext. This ensures that every change to the database happens within the same context and all objects retrieved from the database are tracked by the same datacontext.
    This would be impossible with a transient lifestyle.

  • Image placeholder

    Unknown

    07/15/2009

    Hey! Thanks for your great post, you're the only person I've seen addressing this problem, even though I have taken a different approach, do you know what would be the implications of using a Transient lifestyle instead of a PerWebRequest?