Friday, February 5, 2010

Web.config inheritance madness!

We’re slowly migrating to Server 2008/IIS 7, and we hit on a curious issue the other day. We have a marketing "subsite” that’s incredibly basic – think a handful of .html and .asp pages -  in the same domain space as our flagship asp.net application, just taking up an isolated subfolder (and I actually use a virtual directory, because there’s no good reason to physically host one project inside another project, let alone an html/asp project inside a .net 3.5 project where you have two totally disparate groups making changes). Other than in Production nobody makes a habit of hitting the marketing site. So when a break-fix for one of the few pieces of functionality it has showed up, Development wasn’t able to pull up the marketing subsite in Test. They got this instead:


Server Error in '/Child' Application.




Could not load file or assembly 'Super.Awesome.v3.3, Version=3.3.2.0, Culture=neutral, PublicKeyToken=abc123youandme' or one of its dependencies. The system cannot find the file specified.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.IO.FileNotFoundException: Could not load file or assembly 'Super.Awesome.v3.3, Version=3.3.2.0, Culture=neutral, PublicKeyToken=abc123youandme' or one of its dependencies. The system cannot find the file specified.


The assembly that whacked us is an http module used by the parent asp.net website, referenced in the parent folder’s web.config in httpModules and system.webServer modules. IIS 7 has some great inheritance features, but they never seem to work when you want them to (MSEntLib database connection strings) and work when you don’t want them to (referenced modules).

Googling around, there are a few solutions, but the one that seems to work best is the one I didn’t like at all, initially. They want you to modify the web.config of the parent application to stop inheritance. I’d rather modify the child application to block inheritance. MS’s method seems backwards to me, more of a security risk and a hinderance than a help. If you’re on a locked down server farm (say, rented web space at a 3rd party co-location facility), anyone with physical rights above your folder can make you inherit whatever you don’t explicitly call out. They could write a http, network or file stream logger that steals logins and passwords, for instance. Securing your site via https wouldn’t help because they would be on the inside of the protection. And you wouldn’t be able to do anything about it; you wouldn’t even know what you were inheriting.

Alright, soap box time over. Here’s the simplest way to block web.config section inheritances downstream:
Insert
<location path="." inheritInChildApplications="false">

and
</location>
Around the section you want to stop child inheritance for.

I used system.web & system.webServer in this example, as that’s where extension mapping modules seem to be loaded most commonly.

<?xml version="1.0"?>
[…]
  <configuration>

    <location path="." inheritInChildApplications="false">
      <system.web>
      […]
        <httpModules>
          <add type="SuperAwesome.HttpHandlerModule, Super.Awesome.v3.3, Version=3.3.2.0, Culture=neutral, PublicKeyToken=abc123youandme" name="SuperAwesomeHttpHandlerModule" />
        </httpModules>
      </system.web>
    </location>

  […]
    <location path="." inheritInChildApplications="false">
      <system.webServer>
        <modules>
          <add type="SuperAwesome.ASPxHttpHandlerModule, Super.Awesome.v3.3, Version=3.3.2.0, Culture=neutral, PublicKeyToken=abc123youandme" name="SuperAwesomeHttpHandlerModule" />
        </modules>
      </system.webServer>

    </location>
  </configuration>

Not the way I would have handled this (to repeat, I would have had the child web.config be able to block inheritance) but it could be worse.