Using C# to Manage IIS – Microsoft.Web.Administration Namespace

Posted on Updated on


Introduction

If you have ever attempted to programmatically manipulate IIS in version 6 or earlier, you discovered that it is not a trivial endeavor! You could use Windows Management Instrumentation (WMI), ADSI, or write code to manually manipulate XML. It just wasn’t a task for the faint of heart! I have done it several times and remember it to be quite a headache.

Beginning with IIS 7, programmatic management of IIS has become much simpler with the Microsoft.Web.Administration objects. Using this API model, you can create websites, application pools, applications, virtual directories, etc. with just a few lines of code! Seriously!

The top-level objects of the API are illustrated below.

mwa_overview

This post will walk you through some of the features of the Microsoft.Web.Administration namespace objects and provide some real-world examples of how to implement this really cool API.

Getting Started

If you have IIS installed on your development machine, you will be able to find the .dll in Windows\system32\inetsrv folder or you can use the Nuget package. Either way, you will need the Microsoft.Web.Administration.dll file as a reference in your project.

Once you add the necessary reference to your project, you are ready to go!

Working with the ServerManager

To get started, we must first create an instance of the ServerManager class. We do this exactly as you might think:

ServerManager server = new ServerManager();

NOTE: It is important to note that an instance of the ServerManager assumes that the machine on which the application is running is the web server. It is possible to connect to a remote server using the ServerManager, and we will look at that later in this post.

Getting Sites Associated with the Server

Let’s get a list of all of the websites within our ServerManager. To do this, we access the Sites property of the ServerManager instance. The code block iterates each Site object.

 ServerManager server = new ServerManager();

SiteCollection sites = server.Sites;
foreach (Site site in sites)
{
    ApplicationDefaults defaults = site.ApplicationDefaults;

    //get the name of the ApplicationPool under which the Site runs
    string appPoolName = defaults.ApplicationPoolName;

    ConfigurationAttributeCollection attributes =  defaults.Attributes;
    foreach (ConfigurationAttribute configAttribute in attributes)
    {
        //put code here to work with each ConfigurationAttribute
    }

    ConfigurationAttributeCollection attributesCollection = site.Attributes;
    foreach (ConfigurationAttribute attribute in attributesCollection)
    {
        //put code here to work with each ConfigurationAttribute
    }

    //Get the Binding objects for this Site
    BindingCollection bindings = site.Bindings;
    foreach (Microsoft.Web.Administration.Binding binding in bindings)
    {
        //put code here to work with each Binding
    }

    //retrieve the State of the Site
    ObjectState siteState = site.State;

    //Get the list of all Applications for this Site
    ApplicationCollection applications = site.Applications;
    foreach (Microsoft.Web.Administration.Application application in applications)
    {
        //put code here to work with each Application
    }
}

For more information regarding all of the properties and methods of the Site class, click here.

Getting Applications Associated with each Site

The applications that run under a Site are represented through the Applications property of the Site class. The Applications property is an ApplicationCollection object. We can iterate each Application object with the following code:

ApplicationCollection applications = site.Applications;
foreach (Microsoft.Web.Administration.Application application in applications)
{
    //get the name of the ApplicationPool
    string applicationPoolName = application.ApplicationPoolName;

    VirtualDirectoryCollection directories = application.VirtualDirectories;
    foreach (VirtualDirectory directory in directories)
    {
        //put code here to work with each VirtualDirectory
    }
}

 Getting Virtual Directories Associated with each Application

The virtual directories associated with each Application are accessible via the VirtualDirectories property of the Application class. We can iterate each VirtualDirectory with the following code:

VirtualDirectoryCollection directories = application.VirtualDirectories;
foreach (VirtualDirectory directory in directories)
{
    ConfigurationAttributeCollection attribues = directory.Attributes;
    foreach (ConfigurationAttribute attribute in attributes)
    {
        //put code here to work with each attribute
    }

    ConfigurationChildElementCollection childElements = directory.ChildElements;
    foreach (ConfigurationElement element in childElements)
    {
        //put code here to work with each ConfigurationElement
    }

    //get the directory.Path
    string path = directory.Path;

    //get the physical path
    string physicalPath = directory.PhysicalPath;
}

Getting Application Pools Associated with a Server

The ServerManager.ApplicationPools property is an ApplicationPoolCollection object that contains all ApplicationPool objects associated with the server. Remember that this is a server-level property and that an ApplicationPool can be shared by multiple Sites and Applications.

ServerManager server = new ServerManager();

ApplicationPoolCollection applicationPools = server.ApplicationPools;
foreach (ApplicationPool pool in applicationPools)
{
    //get the AutoStart boolean value
    bool autoStart = pool.AutoStart;

    //get the name of the ManagedRuntimeVersion
    string runtime = pool.ManagedRuntimeVersion;

    //get the name of the ApplicationPool
    string appPoolName = pool.Name;

    //get the identity type
    ProcessModelIdentityType identityType = pool.ProcessModel.IdentityType;

    //get the username for the identity under which the pool runs
    string userName = pool.ProcessModel.UserName;

    //get the password for the identity under which the pool runs
    string password = pool.ProcessModel.Password;
}

Now that we have taken a quick look at the object hierarchy and iterated through some of the child collections, let’s switch our view to how to create and manipulate objects.

Creating a New Application Pool

To create a new ApplicationPool, we create a ServerManager instance, then check the ApplicationPools collection to see if our ApplicationPool already exists. If it does, we update a few of its properties, if not we create the new ApplicationPool. Regardless of the whether we are creating or updating, we use the ServerManager.CommitChanges() method.

ServerManager server = new ServerManager();

ApplicationPool myApplicationPool = null;

//we will create a new ApplicationPool named 'MyApplicationPool'
//we will first check to make sure that this pool does not already exist
//since the ApplicationPools property is a collection, we can use the Linq FirstOrDefault method
//to check for its existence by name
if (server.ApplicationPools != null && server.ApplicationPools.Count > 0)
{
    if (server.ApplicationPools.FirstOrDefault(p => p.Name == "MyApplicationPool") == null)
    {
        //if we find the pool already there, we will get a referecne to it for update
        myApplicationPool = server.ApplicationPools.FirstOrDefault(p => p.Name == "MyApplicationPool");
    }
    else
    {
        //if the pool is not already there we will create it
        myApplicationPool = server.ApplicationPools.Add("MyApplicationPool");
    }
}
else
{
    //if the pool is not already there we will create it
    myApplicationPool = server.ApplicationPools.Add("MyApplicationPool");
}

if (myApplicationPool != null)
{
    //for this sample, we will set the pool to run under the NetworkService identity
    myApplicationPool.ProcessModel.IdentityType = ProcessModelIdentityType.NetworkService;

    //we set the runtime version
    myApplicationPool.ManagedRuntimeVersion = "v4.0";

    //we save our new ApplicationPool!
    server.CommitChanges();
}

In the previous example, we set the ProcessModel.IdentityType to NetworkService. It’s a more common scenario to have a pre-defined service account that is most likely a domain account reserved specifically for this purpose. In this case, we can make a small modification to our code to implement this change. See below.

if (myApplicationPool != null)
{
    //for this sample, we will set the pool to run under the identity of a specific user
    myApplicationPool.ProcessModel.IdentityType = ProcessModelIdentityType.SpecificUser;
    myApplicationPool.ProcessModel.UserName = UserName;
    myApplicationPool.ProcessModel.Password = Password;

    //we set the runtime version
    myApplicationPool.ManagedRuntimeVersion = "v4.0";

    //we save our new ApplicationPool!
    server.CommitChanges();
}

The UserName and Password values are strings that we would provide to our code when creating the ApplicationPool.

Creating a New Site

Creating a new Site is just as easy as creating a new ApplicationPool!

ServerManager server = new ServerManager();

if (server.Sites != null && server.Sites.Count > 0)
{
    //we will first check to make sure that the site isn't already there
    if (server.Sites.FirstOrDefault(s => s.Name == "MySite") == null)
    {
        //we will just pick an arbitrary location for the site
        string path = @"c:\MySiteFolder\";

        //we must specify the Binding information
        string ip = "*";
        string port = "80";
        string hostName = "*";

        string bindingInfo = string.Format(@"{0}:{1}:{2}", ip, port, hostName);

        //add the new Site to the Sites collection
        Site site = server.Sites.Add("MySite", "http", bindingInfo, path);

        //set the ApplicationPool for the new Site
        site.ApplicationDefaults.ApplicationPoolName = myApplicationPool.Name;

        //save the new Site!
        server.CommitChanges();
    }
}

We have only touched on some of the functionality provided to us by the Microsoft.Web.Administration namespace objects. For more information, this MSDN resource is a great place to start. Remember that this API is only valid for IIS version 7.0 and higher and that if you seek to automate a prior version your plan of attack will be quite different.

19 thoughts on “Using C# to Manage IIS – Microsoft.Web.Administration Namespace

    dineshramitc said:
    June 15, 2014 at 4:30 pm

    Reblogged this on Dinesh Ram Kali..

    Liked by 1 person

    George said:
    June 22, 2014 at 4:14 pm

    It’s good to see content on the IIS objects. You’re right they are simple to work with but this is the kind of thing you would only need to do occasionally right? Good post though especially for guys who write installers and things like that.

    Like

    […] Using C# to Manage IIS – Microsoft.Web.Administration Namespace – John Nelson […]

    Like

    Alf said:
    February 11, 2015 at 3:50 am

    Great article, But how can we use ServerManager to manage IIS Express?

    Like

      johnnels responded:
      February 11, 2015 at 9:40 am

      It really depends on which Microsoft.Web.Administration dll you are referencing. There are different dlls for each and if you have IIS and IIS Express running on the same machine, Visual Studio may “silently” switch you. You can tell if ServerManager is using IIS or IIS Express by debugging your app and checking the value of the ServerManager.ApplicationPoolsSection.Configuration.ConfigFile.FilePath property.

      Like

    Mohamed Zackkariah said:
    April 6, 2015 at 5:48 am

    How to update the Existing website settings (IP Address, Port, AppPool Name, AppPool Identity, ManagedPipline mode, Identity Username, password and etc). Also How to replace the website files in the virtual directory.

    Like

    Ivan said:
    August 20, 2015 at 7:46 am

    Great article, but I am getting UnauthorizedAccessException if the application pool identity is a user that is not administrator. Is there any workaround for this?
    Thank you.

    Like

    Otavio Augusto said:
    August 25, 2015 at 8:05 pm

    How about when we don’t have the IIS on the machine on which the application is running? I mean, I’m developing a tool to help FrontEnd developers to create their’s own environment on their machines. But I couldn’t figure out how to know if the IIS is installed and if it is running. Is there any excpetion I should carry about ?

    One more topic, I think it make senses in this context, in your last answer you told that depends on which dll we are referecing … how about when we’ve referenced it by a Nuget package?

    Thanks,

    By the way, great article.

    Like

      JM said:
      October 26, 2015 at 10:15 am

      to get ServerManager on an other machine, use: ServerManager.OpenRemote()

      Like

    JM said:
    October 26, 2015 at 10:23 am

    Hi. Got any hint about a workaround for accessing ServerManager.Sites collection on Win8 (UnauthorizedAccessException if no right on file “%SystemRoot%\System32\inetsrv\config\redirection.config”) ?
    More largely you can get into trouble if your user has no right on “%SystemRoot%\System32\inetsrv\config”..

    Like

    xxx said:
    October 10, 2016 at 11:25 pm

    Great article, I’ll give it a try, thank you.

    Like

    Pradeep said:
    November 6, 2016 at 1:54 am

    Hi,

    I am using ServerManager.OpenRemote(Servername). where Serervname is the remote server. I am getting unauthorized Exception. could you please help me how to proceed for this.

    Like

      johnnels responded:
      November 6, 2016 at 6:39 pm

      Can you send me the stack trace associated with the exception?

      Like

    David Carty said:
    June 1, 2018 at 5:56 am

    Can anyone help with this issue?
    System.IO.FileLoadException was unhandled by user code
    HResult=-2147024864
    Message=Filename: \\?\C:\Users\david\OneDrive\Documents\IISExpress\config\applicationHost.config
    Error: Cannot write configuration file

    Stack trace:

    at Microsoft.Web.Administration.Interop.IAppHostWritableAdminManager.CommitChanges()
    at Microsoft.Web.Administration.ConfigurationManager.CommitChanges()
    at Microsoft.Web.Administration.ServerManager.CommitChanges()
    at mowzi.cms.ServerAdmin.CreateWebsite(JToken jsonObj) in C:\Dev\MowziProjects\MowziServer\ServerAdmin.cs:line 56
    at mowzi.cms.Actions.ProcessRequest(HttpContext context) in C:\Dev\MowziProjects\MowziServer\CMS.ashx.cs:line 118
    at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
    at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
    at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

    Like

      johnnels responded:
      June 2, 2018 at 12:06 pm

      Hello, David! Try this:

      1. Go to the IISExpress directory via My Computer (C:\Users\david\OneDrive\Documents\IISExpress)

      2. Right-click on the directory, click Properties, then Advanced, uncheck ‘Encrypt contents to secure data’.

      3. Once you have done this, click OK.

      See if that helps!

      Like

    AzaelCa said:
    October 11, 2018 at 3:15 pm

    Hello everyone, and thanks for the documentation. The use of IIS is very important, at the time of development, my question is, how to access the classes.
    For example, the kind of request or the collection of applications, in the Microsoft documentation is null, the information that exists, thanks in advance, and if someone could help me with an example I would appreciate it very much

    Like

    Veena Prabhakar said:
    August 26, 2019 at 12:25 am

    hi Johnnels,

    I want to display all the app pool identity usernames into a C# windows datagrid view. can you pls help me.
    thanks
    Veena

    Like

    Veena Prabhakar said:
    August 26, 2019 at 12:30 am

    hi Johnnels,

    I want to display all the app pools identiy usernames into a data gridview in c# windows. can you please advise.

    Thanks
    Veena

    Like

    Dharuman said:
    July 9, 2020 at 7:08 am

    Hi,How to get List of application from another server using C#

    Like

Leave a comment