MSBuild.Community.Tasks - WebDirectoryCreate / WebDirectorySetting / WebDirectoryDelete

Recently I submitted a patch for the MSBuild.Community.Tasks because there were certain tasks that were not working for us.  I decided to blog about this because there are others that indicated they were having the same issues. 

In IIS, you are able to specify more than one website with the same ports.  By default, the WebDirectoryCreate task will always loop through and choose the last website with that port.  If you do have more than one website with the same ports, you need to distinguish differences between the two by either the host header name or by having different IP addresses for the two on the same server.  So I added a HostHeaderName property to the WebBase.cs where you can put in either an IP address or a Host header and it will search for that as a string based on the entire web site identification.

 

This is where the search across the different websites in IIS to find the one that has the site header.

/// <summary>
/// Verify that the IIS Website exists if it has been specified.
/// </summary>
/// <param name="site">DirectoryEntry that meets the IISWebServer schema</param>
/// <returns>True if a site is found when specified. True if no site has been specified.</returns>
private bool VerifySiteHostHeaderExists(DirectoryEntry site)
{
    bool siteHeaderFound = false;
 
    if (HostHeaderName == null)
    {
        siteHeaderFound = true;
    }
    else
    {
        //get the serverBinding information
        foreach (object serverBinding in (PropertyValueCollection)site.Properties["ServerBindings"])
        {
            //find the IIS Website that has been specified by the user
            if (((string)serverBinding).ToLower().IndexOf(HostHeaderName.ToLower()) != -1)
            {
                siteHeaderFound = true;
                break;
            }
        }
    }
 
    return siteHeaderFound;
}

 

Second, if you specify more than one identity for a website, it would break the functionality of the create and delete tasks.  This is due to the site.Properties["ServerBindings"].Value.ToString() being a String when there was only one item and returning as an Object() if there was more than one.  This is what the code looked like below.  The offending code is in bold below.

private bool VerifyServerPortExists(DirectoryEntry site)
{
    string serverBindings = site.Properties["ServerBindings"].Value.ToString(); //offending line of code
    string[] serverBindingsArray = serverBindings.Split(':');
 
 
    if (mServerPort == Convert.ToInt32(serverBindingsArray[1])) //This is where the error originates
    {
        mServerInstance = site.Name;
        mIISServerPath = string.Format("IIS://{0}/W3SVC/{1}/Root", mServerName, mServerInstance);
        mIISApplicationPath = string.Format("/LM/W3SVC/{0}/Root", mServerInstance);
        mIISAppPoolPath = string.Format("IIS://{0}/W3SVC/AppPools", mServerName);
        return true;
 
    }
    return false;
}

 

This is what it looks like now.  Notice that I moved the setting of the IIS primitives out of the verification area (although it is still being called by the VerifyIISRoot).

private bool VerifyServerPortExists(DirectoryEntry site)
{
    bool portServerExists = false;
 
    //get the serverBinding information
    foreach (object serverBinding in (PropertyValueCollection)site.Properties["ServerBindings"]) //now we are using a PropertyValueCollection
    {
 
        //look for an integer
        foreach (string bindingPiece in ((string)serverBinding).Split(':'))
        {
            int serverPort;
            int.TryParse(bindingPiece, out serverPort); //we do a safer int.TryParse() to look for the integer
            if (serverPort != 0)
            {
                if (ServerPort == serverPort)
                {
                    SetIISPrimitives(site.Name);
                    portServerExists = true;
                    break;
                }
            }
        }
        if (portServerExists)
        {
            break;
        }
    }
 
    return portServerExists;
}
 
/// <summary>
/// Sets some of the protected properties for the Virtual Directory Creation Wizard.
/// </summary>
/// <param name="serverInstance">DirectoryEntry.Name where the Entry is an IISWebServer schema</param>
private void SetIISPrimitives(string serverInstance)
{
    mServerInstance = serverInstance;
    mIISServerPath = string.Format("IIS://{0}/W3SVC/{1}/Root", mServerName, mServerInstance);
    mIISApplicationPath = string.Format("/LM/W3SVC/{0}/Root", mServerInstance);
    mIISAppPoolPath = string.Format("IIS://{0}/W3SVC/AppPools", mServerName);
}

 

There are also tests to verify this works and there are additional pieces to this to ensure the returned error includes the host header if specified.  If you would like to take a look at the code submitted, take a look at my patch submission on the MSBuild Community Tasks project.  Working on this over a couple of hours I validated about where I am at as far as development goes compared to others in the community.  This was fun and it made me feel great to contribute something to OSS.

Any comments/thoughts on the code?

Print | posted @ Tuesday, December 18, 2007 11:08 PM

Comments have been closed on this topic.