Dependency Injection (DI)

Fixed and Explained: [Sitecore] Forgot to register the http module Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule

Posted on Updated on

Sitecore - Forgot to register the http module Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule.png

Looks like you forgot to register the http module Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule
To fix this add
<add name=”PerRequestLifestyle” type=”Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor” />
to the <httpModules> section on your web.config.
Windsor also detected you’re running IIS in Integrated Pipeline mode. This means that you also need to add the module to the <modules> section under <system.webServer>.
Alternatively make sure you have Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 assembly in your GAC (it is installed by ASP.NET MVC3 or WebMatrix) and Windsor will be able to register the module automatically without having to add anything to the config file.

Today, I faced a very descriptive error – how I wish all errors are like the one above. It mentioned the root cause, and at the same time the solution. In short, it says it all! 🙂

Actually, there were various posts that answers the same issue.

  1. Using Castle Windsor’s PerWebRequest lifestyle with ASP.NET MVC on IIS7, here
  2. WCF & Castle Windsor – Looks like you forgot, here
  3. Looks like you forgot to register the http module with Windsor Castle with IIS7, here
  4. IIS7 & Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule registering problems, here

Seems pretty straight forward, isn’t? But given that it’s too generic error – we know that – and too straight forward to fix – we know that; I would still try to put an effort to locate it in our Sitecore instance and to discuss it in more details.

In the mean time, let’s fix it first:

  1. Open your web.config file under the \Website root folder
  2. Locate the <system.webServer> group section
  3. Find the <modules runAllManagedModulesForAllRequests=”true”> section
  4. In the bottom part of the module section and before its closing tag </modules>, add the following line
&lt;add name=&quot;PerRequestLifestyle&quot; type=&quot;Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor&quot; /&gt;

Refresh the page, and that should fix the issue.

yes i did it

Even we know how to fix it, at this point, I am still inquisitive on how it was being invoked in our application. I understand that it was called in the Application_startup, but haven’t seen any blog posts that tackles and dive into the code yet – if there’s a blog post on this, you may comment it below, so I can add a reference to it.

Here’s the visual after decompiling the Castle.Windsor.dll – the dependency injection.

Sitecore -Castle Windsor - PerWebRequestLifeStyleModule

Pasting the entire code here, as well.

// Decompiled with JetBrains decompiler
// Type: Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule
// Assembly: Castle.Windsor, Version=3.2.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc
// MVID: BE35FEDF-2CA9-427E-91F9-D71A6688B7DC
// Assembly location: D:\Instances\8.0-U3.site.com\Website\bin\Castle.Windsor.dll

using Castle.MicroKernel.Lifestyle.Scoped;
using System;
using System.Text;
using System.Web;

namespace Castle.MicroKernel.Lifestyle
{
  public class PerWebRequestLifestyleModule : IHttpModule
  {
    private const string key = &quot;castle.per-web-request-lifestyle-cache&quot;;
    private static bool initialized;

    public void Dispose()
    {
    }

    public void Init(HttpApplication context)
    {
      PerWebRequestLifestyleModule.initialized = true;
      context.EndRequest += new EventHandler(this.Application_EndRequest);
    }

    protected void Application_EndRequest(object sender, EventArgs e)
    {
      ILifetimeScope scope = PerWebRequestLifestyleModule.GetScope(((HttpApplication) sender).Context, false);
      if (scope == null)
        return;
      scope.Dispose();
    }

    internal static ILifetimeScope GetScope()
    {
      PerWebRequestLifestyleModule.EnsureInitialized();
      HttpContext current = HttpContext.Current;
      if (current == null)
        throw new InvalidOperationException(&quot;HttpContext.Current is null. PerWebRequestLifestyle can only be used in ASP.Net&quot;);
      return PerWebRequestLifestyleModule.GetScope(current, true);
    }

    internal static ILifetimeScope YieldScope()
    {
      HttpContext current = HttpContext.Current;
      if (current == null)
        return (ILifetimeScope) null;
      ILifetimeScope scope = PerWebRequestLifestyleModule.GetScope(current, true);
      if (scope != null)
        current.Items.Remove((object) &quot;castle.per-web-request-lifestyle-cache&quot;);
      return scope;
    }

    private static void EnsureInitialized()
    {
      if (!PerWebRequestLifestyleModule.initialized)
      {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.AppendLine(&quot;Looks like you forgot to register the http module &quot; + typeof (PerWebRequestLifestyleModule).FullName);
        stringBuilder.AppendLine(&quot;To fix this add&quot;);
        stringBuilder.AppendLine(&quot;&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;add name=\&quot;PerRequestLifestyle\&quot; type=\&quot;Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor\&quot; /&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&quot;);
        stringBuilder.AppendLine(&quot;to the &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;httpModules&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; section on your web.config.&quot;);
        if (HttpRuntime.UsingIntegratedPipeline)
          stringBuilder.AppendLine(&quot;Windsor also detected you're running IIS in Integrated Pipeline mode. This means that you also need to add the module to the &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;modules&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; section under &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;system.webServer&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;.&quot;);
        else
          stringBuilder.AppendLine(&quot;If you plan running on IIS in Integrated Pipeline mode, you also need to add the module to the &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;modules&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; section under &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;system.webServer&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;.&quot;);
        stringBuilder.AppendLine(&quot;Alternatively make sure you have Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 assembly in your GAC (it is installed by ASP.NET MVC3 or WebMatrix) and Windsor will be able to register the module automatically without having to add anything to the config file.&quot;);
        throw new ComponentResolutionException(stringBuilder.ToString());
      }
    }

    private static ILifetimeScope GetScope(HttpContext context, bool createIfNotPresent)
    {
      ILifetimeScope lifetimeScope = (ILifetimeScope) context.Items[(object) &quot;castle.per-web-request-lifestyle-cache&quot;];
      if (lifetimeScope == null &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; createIfNotPresent)
      {
        lifetimeScope = (ILifetimeScope) new DefaultLifetimeScope((IScopeCache) new ScopeCache(), (Action&amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;Burden&amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;) null);
        context.Items[(object) &quot;castle.per-web-request-lifestyle-cache&quot;] = (object) lifetimeScope;
      }
      return lifetimeScope;
    }
  }
}

As shown in the above class, the class PerWebRequestLifestyleModule implements a contract / interface (line 14). This System.Web.IHttpModule is responsible for providing the module initialization and disposal events by implementing this interface. In the Init(HttpApplication context) method – line 23, it initializes the modules and prepares it to the handle request.

On the other hand, the line 57 the EnsureInitialized() method is being called in the GetScope() and the GetScope method is referenced by the Application_EndRequest that being referenced by the Init() method. If the initialized property returned FALSE which in our case, not instantiated or registered in the web.config (/configuration/system.webServer/modules) section, then the line 51-71 – the runtime error will be displayed on our page.

The PerWebRequestLifestyleModule  relies on the HttpModule which – perhaps – not initialized on the Application_Start event and Application_EndRequest event in the global.asax when the time the application init is being invoked.

Happy Sitecoring!

Advertisements