MWA and intellisense for configuration sections

Microsoft.Web.Administration (MWA) returns generic ConfigurationSection, ConfigurationElementCollection, ConfigurationElement classes for dealing with different configuration sections. Using these classes directly requires you to remember attribute/collection/element names which needs to be passed to GetAttribute(), GetCollection(), GetChildElement(). MWA allows you to define your Section/Collection/Element types which can then be passed to GetSection, GetCollection, GetChildElement to get an instance of strongly typed class which makes dealing with sections very easy. Jan’s article on extending IIS7 schema talks about writing a strongly typed class to enable intellisense for simple sections. If the section contains a collection (or an element with one collection), you can define additional type which derives from ConfigurationElementCollectionBase and then use this type in call to GetCollection(). This class should implement Add(), Remove(), CreateNewElement(), this[keys] for handling elements specific to this collection. Taking example of system.webServer/httpErrors section, code for dealing with errors collection will look like this.

public class HttpErrorsCollection : ConfigurationElementCollectionBase<HttpErrorsCollectionElement>
{
    public HttpErrorsCollectionElement this[uint statusCode, int subStatusCode]
    {
        get
        {
            for (int i = 0; i < Count; i++)
            {
                HttpErrorsCollectionElement element = base[i];
                if ((element.StatusCode == statusCode) && (element.SubStatusCode == subStatusCode))
                {
                    return element; 
                }
            }

            return null;
        }
    }

    public HttpErrorsCollectionElement Add(
        uint statusCode,
        int subStatusCode,
        string prefixLanguageFilePath,
        string path,
        EnumHttpErrorsResponseMode responseMode)
    {
        HttpErrorsCollectionElement element = CreateElement();

        element.StatusCode = statusCode;
        element.SubStatusCode = subStatusCode;
        element.PrefixLanguageFilePath = prefixLanguageFilePath;
        element.Path = path;
        element.ResponseMode = responseMode;

        return Add(element);
    }

    protected override HttpErrorsCollectionElement CreateNewElement(string elementTagName)
    {
        return new HttpErrorsCollectionElement();
    }

    public void Remove(uint statusCode, int subStatusCode)
    {
        Remove(this[statusCode, subStatusCode]);
    }
}

public class HttpErrorsCollectionElement : ConfigurationElement
{
   public uint StatusCode
    {
        get { return (uint)base["statusCode"]; }
        set { base["statusCode"] = (uint)value; }
    }

    public int SubStatusCode
    {
        get { return (int)base["subStatusCode"]; }
        set { base["subStatusCode"] = (int)value; }
    }

    public string PrefixLanguageFilePath
    {
        get { return (string)base["prefixLanguageFilePath"]; }
        set { base["prefixLanguageFilePath"] = (string)value; }
    }

    public string Path
    {
        get { return (string)base["path"]; }
        set { base["path"] = (string)value; }
    }

    public EnumHttpErrorsResponseMode ResponseMode
    {
        get { return (EnumHttpErrorsResponseMode)base["responseMode"]; }
        set { base["responseMode"] = (int)value; }
    }}

public enum EnumHttpErrorsErrorMode
{
    DetailedLocalOnly = 0,
    Custom = 1,
    Detailed = 2
}

public
class HttpErrorsSection : ConfigurationSection
{
    public static string SectionName = "system.webServer/httpErrors";
    public HttpErrorsCollection Errors
    {
        get { return (HttpErrorsCollection)GetCollection("error", typeof(HttpErrorsCollection)); }
    }
}

If the section/element schema has an <element> tag, you can define a type deriving from ConfigurationElement and then pass the type in GetChildElement. Taking example of request filtering section, code to handle requestLimits element will look like this. public class RequestFilteringSection : ConfigurationSection{
    public static string SectionName = "system.webServer/security/requestFiltering";

    public RequestLimitsElement RequestLimits
    {
        get { return (RequestLimitsElement)GetChildElement("requestLimits", typeof(RequestLimitsElement)); }
    }
}

Declaration of RequestLimitsElement looks similar to collection element class as in HttpErrorsCollectionElement.

public
class RequestLimitsElement : ConfigurationElement
{
    public uint MaxAllowedContentLength
    {
        get { return (uint)base["maxAllowedContentLength"]; }
        set { base["maxAllowedContentLength"] = (uint)value; }
    }

    public uint MaxUrl
    {
        get { return (uint)base["maxUrl"]; }
        set { base["maxUrl"] = (uint)value; }
    }

    public uint MaxQueryString
    {
        get { return (uint)base["maxQueryString"]; } 
        set { base["maxQueryString"] = (uint)value; }
    }

    //
    // This element can further have collections.
    // HeaderLimitsCollection will look similar to
    // HttpErrorsCollection.
    //
    public HeaderLimitsCollection HeaderLimits
    {
        get { return (HeaderLimitsCollection)GetCollection("headerLimits", typeof(HeaderLimitsCollection)); }
    }
}

Checkout the tool to generate this code from schema definition here.

-Kanwal

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>