:::: MENU ::::

Monday, August 3, 2009

Here's one thing that that irritates me to no end - the way IIS and ASP.NET inheritance works down from a root directory into child directories.

I started a new project today and immediately I was greeted by about 15 configuration errors. Like this:

Server Error in '/WebStore2008' Application.


Compilation Error

Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

Compiler Error Message: CS0246: The type or namespace name 'Westwind' could not be found (are you missing a using directive or an assembly reference?)

Source Error:

 

Line 30:     <pages>
Line 31:       <namespaces>
Line 32:         <add namespace="Westwind.Tools" />
Line 33:         <add namespace="Westwind.Web.Controls" />
Line 34:       </namespaces>


Source File: c:\Westwind\Web.Config    Line: 32

Show Detailed Compiler Output:

 

c:\windows\system32\inetsrv> "c:\Windows\Microsoft.NET\Framework\v3.5\csc.exe" /t:library /utf8output /R:"C:\Windows\assembly\GAC_MSIL\System.ServiceModel.Web\3.5.0.0__31bf3856ad364e35\System.ServiceModel.Web.dll" /R:"C:\Windows\assembly\GAC_MSIL\System.Xml\2.0.0.0__b77a5c561934e089\System.Xml.dll" /R:"C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll" /R:"C:\Windows\assembly\GAC_MSIL\System.Web.Mobile\2.0.0.0__b03f5f7f11d50a3a\System.Web.Mobile.dll" /R:"C:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\webstore2008\6c272261\3f6f6ff2\assembly\dl3\ea25c105\1062d9c4_dbdbc701\WebStore2008.DLL" /R:"C:\Windows\assembly\GAC_MSIL\System.Web.Services\2.0.0.0__b03f5f7f11d50a3a\System.Web.Services.dll" /R:"C:\Windows\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll" /R:"C:\Windows\assembly\GAC_MSIL\System.Xml.Linq\3.5.0.0__b77a5c561934e089\System.Xml.Linq.dll" /R:"C:\Windows\assembly\GAC_MSIL\System.Web.Extensions\3.5.0.0__31bf3856ad364e35\System.Web.Extensions.dll" /R:"C:\Windows\assembly\GAC_MSIL\System.Core\3.5.0.0__b77a5c561934e089\System.Core.dll" /R:"C:\Windows\assembly\GAC_MSIL\System.Runtime.Serialization\3.0.0.0__b77a5c561934e089\System.Runtime.Serialization.dll" /R:"C:\Windows\assembly\GAC_MSIL\System.Configuration\2.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll" /R:"C:\Windows\assembly\GAC_MSIL\System.WorkflowServices\3.5.0.0__31bf3856ad364e35\System.WorkflowServices.dll" /R:"C:\Windows\assembly\GAC_MSIL\System.IdentityModel\3.0.0.0__b77a5c561934e089\System.IdentityModel.dll" /R:"C:\Windows\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll" /R:"C:\Windows\assembly\GAC_MSIL\System.Drawing\2.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll" /R:"C:\Windows\assembly\GAC_MSIL\System.ServiceModel\3.0.0.0__b77a5c561934e089\System.ServiceModel.dll" /R:"C:\Windows\assembly\GAC_32\System.Web\2.0.0.0__b03f5f7f11d50a3a\System.Web.dll" /R:"C:\Windows\assembly\GAC_32\System.EnterpriseServices\2.0.0.0__b03f5f7f11d50a3a\System.EnterpriseServices.dll" /R:"C:\Windows\assembly\GAC_MSIL\System.Data.DataSetExtensions\2.0.0.0__b77a5c561934e089\System.Data.DataSetExtensions.dll" /R:"C:\Windows\assembly\GAC_MSIL\System.DirectoryServices\2.0.0.0__b03f5f7f11d50a3a\System.DirectoryServices.dll" /out:"C:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\webstore2008\6c272261\3f6f6ff2\App_Web_default.aspx.cdcab7d2.wfdhi8ei.dll" /debug- /optimize+ /warnaserror /w:4 /nowarn:1659;1699 /warnaserror-  "C:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\webstore2008\6c272261\3f6f6ff2\App_Web_default.aspx.cdcab7d2.wfdhi8ei.0.cs" "C:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\webstore2008\6c272261\3f6f6ff2\App_Web_default.aspx.cdcab7d2.wfdhi8ei.1.cs"
 
 
Microsoft (R) Visual C# 2008 Compiler Beta 2 version 3.05.20706.1
 
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.
 
c:\Westwind\Web.Config(32,11): error CS0246: The type or namespace name 'Westwind' could not be found (are you missing a using directive or an assembly reference?)
c:\Westwind\Web.Config(33,11): error CS0246: The type or namespace name 'Westwind' could not be found (are you missing a using directive or an assembly reference?)

 

This is of course only one in a whole string of errors that will come up one at a time. This particular error is due to a BIN deployed component that doesn't exist in my newly created application and the app is expecting the namespace which of course isn't actually there.

So this is a brand new project why these errors? Well, the problem is that the newly created app automatically inherits the root web's config settings. So if you use any custom modules, handlers, or as above even add a namespace, references that are not used in a new project down the virtual directory you'll get errors because those settings usually don't make sense in the lower virtual directories.

You can fix this by explicitly overriding adding a clear tag:

    <pages>
      <namespaces>
        <clear />
      </namespaces>
    </pages>

But this can be a royal pain if you have to do this on 10 or 20 different sections of the configuration for each application downwind of the root virtual. If you have 10 or 20 virtuals this gets old real quick, and it continues to be volatile if any changes are made to web.config in the root later on which can basically bring down all the applications on a server.

Don't think this is a big problem? Consider that configuration just got a lot more complex with the introduction of IIS 7 into the mix where you now have to worry about mixtures of IIS 7 settings (in system.webserver) in addition to the settings in system.web. Worse consider the slew of 'default' configuration settings that a .NET 3.5 app requires (think of the MS Ajax includes, handlers and modules, plus the 3.5 libraries) and imagine all that gunk in a root application. If you have a 2.0 virtuals underneath the root that things will get real ugly.

Stop Inheritance cold with <location inheritInChildApplications="false">

Thankfully there's a not very obvious way to work around this whole issue by using a location tag. Using the inheritInChildApplication attribute in the location element allows you to basically stop all inheritance dead from the current application down. All that's required is that the settings you want to protect are stored inside of a <location> element like this:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <configSections>
    <section name="webConnectionConfiguration" type="System.Configuration.NameValueSectionHandler,System,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <section name="wwBanner" type="System.Configuration.NameValueSectionHandler,System,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  </configSections>
  <connectionStrings>
    <add name="WestWindAdmin" connectionString="server=.;database=WestWindAdmin;integrated security=true;" providerName="" />
  </connectionStrings>
 
  <location inheritInChildApplications="false">
    <system.web>
      <compilation debug="true">
        <assemblies>
          <add assembly="System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
        </assemblies>
      </compilation>
      <pages>
        <namespaces>
          <add namespace="Westwind.Tools" />
          <add namespace="Westwind.Web.Controls" />
        </namespaces>
      </pages>
    </system.web>
    <system.webServer>
      <handlers>
        <add name="wst West Wind Web Connection" path="*.wst" verb="*" modules="IsapiModule" scriptProcessor="c:\westwind\wconnect\wc.dll" resourceType="Unspecified" />
      </handlers>
      <validation validateIntegratedModeConfiguration="false" />
    </system.webServer>
  </location>
  
  <wwBanner>
      <add key="ConnectionString" value="server=.;database=WestwindAdmin;integrated security=true;" />
      <add key="BannerManagerHandlerUrl" value="~/wwBanner.ashx" />
      <add key="TrackStatistics" value="True" />
      <add key="HomeUrl" value="~/admin/" />
    </wwBanner>
</configuration>

You can basically wrap the location tag around any entries you don't want to inherit or even the entire web.config below the Configuration tag. You can also leave settings that you might actually want to inherit all the way down outside of the location tag. Thus, in the above the connectionStrings and wwBanner configuration settings are visible to child virtuals.

Why oh, Why?

I've run into this issue on a number of occasions and this particular option isn't easy to find. The web.config Intellisense and schema preview doesn't show this attribute so it's easy to miss. In addition, when I have looked for this thing I always forget exactly where it is applied: on the Location tag.

This solves the problem neatly.

I really wish that IIS 7 provided a global option in its settings to simply stop inheritance at the root Web level for any entries automatically. Honestly I don't see why you'd ever want inheritance to jump virtual directory boundaries. There's no good reason for the inheritance in the first place not when you have machine level configuration settings. When I set up a virtual directory I want to be insured that I have a clean configuration and not have to worry about config settings higher up the chain.

But at least this problem has a solution even if it's one that I'll forget about probably a few times more. <s> Maybe writing it up here will help jog my memory...

More