Archives

Archives / 2006 / December
  • Tool to generate strongly typed classes for configuration sections

    I wrote a simple tool to generate strongly typed classes for IIS configuration sections which can then be used with MWA to enable intellisense. This tool should be able to generate very logical intuitive type names in most cases. Generated code is similar to code samples in my earlier blog.

    Usage:
    genscode.exe <schemaFile> <optional section name>

    This tool dumps the code on the console. Redirect to save in a file.
    genscode.exe %windir%\system32\inetsrv\config\schema\IIS_Schema.xml system.webServer/httpCompression > HttpCompression.cs

    Omitting section name will make it generate classes for all sections defined in schema file.
    genscode.exe %windir%\system32\inetsrv\config\schema\IIS_Schema.xml > IISConfigSections.cs

    Compile the generated code to build a library.
    csc /t:library /r:Microsoft.Web.Administration.dll IISConfigSections.cs

    Add this library to your project references or just copy-paste the generated code in your code which is using MWA and start editing IIS sections without referring to schema. Here is how adding caching profiles will look like.

    using SystemwebServer;

    ServerManager
    sm = new ServerManager();

    CachingSection cs = (CachingSection)sm.GetApplicationHostConfiguration().GetSection(
        CachingSection.SectionName,
        typeof(CachingSection));
    cs.Profiles.Add(
        ".htm",
        EnumProfilesPolicy.CacheForTimePeriod,
        EnumProfilesKernelCachePolicy.CacheForTimePeriod,
        new TimeSpan(1000),
        EnumProfilesLocation.Downstream,
        "HEADER",
        "QUERYSTRING");

    ProfilesCollection profiles = cs.Profiles;
    ProfilesCollectionElement aspProfile = profiles.CreateElement();
    aspProfile.Extension = ".asp";
    aspProfile.Policy = EnumProfilesPolicy.CacheUntilChange;
    profiles.Add(aspProfile);

    sm.CommitChanges();

    Attached: GenSCodeInstall.zip (containing installer GenSCodeInstall.exe which will install genscode.exe and configschema.dll).

    View the original post

  • 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.

    View the original post