Adding SSL Binding to a remote website using Microsoft.Web.Administration

Microsoft.Web.Administration is very useful providing read and write access to the IIS configuration in a simple way.

However, I stumbled across a peculiar issue when trying to add a SSL binding to a website located on another machine. Here’s my code (*asterisk denotes code I’ve hidden on purpose):

using (ServerManager mgr = ServerManager.OpenRemote(serverName))
{
   // Code to create the website*    

   // Adding bindings
   // this webSite variable is of a custom type I've created to simplify things
   for (int i = 0; i < webSite.Bindings.Count; i++)
   {
       var binding = webSite.Bindings[i];                        
       string bindingInformation = string.Format("{0}:{1}:{2}", binding.IpAddress, binding.TcpPort, binding.HostName);
       // iisSite is of type Microsoft.Web.Administration.Site
       iisSite.Bindings.Add(bindingInformation, binding.CertificateHash, binding.CertificateStore);
    }
    mgr.CommitChanges();
    webSite.Id = iisSite.Id;
}

I kept getting this exception:

NotSupportedException: The specified operation is not supported when a server name is specified.

Upon investigating the BindingCollection class, I’ve found the culprit:

bindingCollectionAdd

Setting BindingInformation also loads the Endpoint. Curiously, this wouldn’t be a problem, however both CertificateHash and CertificateStore also have some additional logic to set their values:

certificateHash

When its underlying variable is null OR the EndPoint is null, it just sets the value. Otherwise, it sets the value and adds/modifies the associated binding transaction. Further investigating this method, I’ve noticed it doesn’t work when the ServerManager is open remotely:

ensureLocal1

Check inside the EnsureLocal method:

ensureLocal2

So instead of adding the Binding through the BindingCollection.Add method, I’ve changed my code to this:

using (ServerManager mgr = ServerManager.OpenRemote(serverName))
{
   // Code to create the website*    

   // Adding bindings
   // this webSite variable is of a custom type I've created to simplify things
   for (int i = 0; i < webSite.Bindings.Count; i++)
   {
       var binding = webSite.Bindings[i];                        
       // Binding class = Microsoft.Web.Administration.Binding
       Binding iisBinding = iisSite.Bindings.CreateElement();
       iisBinding.Protocol = protocol;
       if (binding.Type == Business.IIS.Binding.BindingType.Https)
       {   
            try
            {
                iisBinding.CertificateHash = binding.CertificateHash;
                iisBinding.CertificateStoreName = binding.CertificateStoreName;
            }
            catch (Exception)
            {
                // Error treatment*
            }                            
        }
        iisBinding.BindingInformation = string.Format("{0}:{1}:{2}", binding.IpAddress, binding.TcpPort, binding.HostName);
        // iisSite is of type Microsoft.Web.Administration.Site
        iisSite.Bindings.Add(iisBinding);
    }
    mgr.CommitChanges();
    webSite.Id = iisSite.Id;
}

By creating the Binding manually and setting the BindingInformation at last (rather than at the beginning), the problem was gone!
Must confess, though. I have no clue why that method in particular had to “ensure it’s the local server”.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s