Creating a new website programmatically on IIS using ASP.NET and C#

Standard

Overview

This article describes how to create a new web site on IIS using ASP.NET and C#.

Description

Before going into the article, I just want to brief about the client requirement. It is a Content Management System which allows users to create new websites and host it on the server. Users can browse through the available domain names via a third party API and select a domain name and choose to host it on the server and then a new ASP.NET website should be created on IIS automatically and run within no time.

For each new website request, administrator cannot open IIS to create a new ASP.NET website. We require an instant solution where user enters website name and a new website should be created automatically on IIS with required settings like host name, local path, default document, etc., similar to the settings which a user does manually through wizard on the server.

Environment: Windows Server 2003, IIS 6.0, ASP.NET 2.0

For demo purposes, user interface is .aspx page with just a text box to enter website name and a submit button.

On the server side, web service does the job. It takes the website name as parameter and creates new website on IIS. And a point to be noted is all the new websites created point to a same physical location and depending upon the name of the website, content gets populated. If you need to configure different physical paths for each website, send an additional parameter to the web service.

Let’s start the job now

  1. Create a new “ASP.NET Web Service” with Language as “C#”.
  2. Open “web.config” file, add below configuration values under “appSettings” section.
    <appSettings>
      <clear/>
      <!---Default format is IIS://<your server name>/W3SVC-->
      <add key="metabasePath" value="IIS://C37336-113134/W3SVC"/>
      <!--Framework version of newly created website-->
      <add key="frameworkVersion" value="2.0.50727"/>
      <!---Local path of newly created website -->
      <add key="defaultFileLocation" value="C:\Test"/>
      <!---Application Pool of newly created website-->
      <add key="defaultAppPool" value="CustomAppPool"/>
    </appSettings>

     

  3. Add Reference to “System.DirectoryServices” library and navigate to .cs file and import the namespaces “using System.DirectoryServices”.
  4. Create a new web method “CreateWebsite”
  5. /// <summary>
    /// Creates new ASP.NET website on IIS
    /// </summary>
    /// <param name="siteName"></param>
    /// <returns></returns>
    [WebMethod]
    public string CreateWebsite(string siteName)
    {
      try
      {
         //Initialize configuration variables
         string metabasePath =  Convert.ToString(ConfigurationManager.AppSettings["metabasePath"]);
         string frameworkVersion = Convert.ToString(ConfigurationManager.AppSettings["frameworkVersion"].ToString());
         string physicalPath = Convert.ToString(ConfigurationManager.AppSettings["defaultFileLocation"].ToString());
         string defaultAppPool = ConfigurationManager.AppSettings["defaultAppPool"].ToString();//Host Header Info
         object[] hosts = new object[2];
         string hostHeader = siteName.Replace("www.", string.Empty).Replace(".com",string.Empty);
         hosts[0] = ":80:" + hostHeader+".com";
         hosts[1] = ":80:" + "www." + hostHeader + ".com";
    
         //Gets unique site id for the new website
         int siteId = GetUniqueSiteId(metabasePath);
    
         //Extracts the directory entry
         DirectoryEntry objDirEntry = new DirectoryEntry(metabasePath);
         string className = objDirEntry.SchemaClassName;
         if (!className.EndsWith("Service")) return "Invalid configuration variables";
    
         //creates new website by specifying site name and host header
         DirectoryEntry newSite = objDirEntry.Children.Add(Convert.ToString(siteId), (className.Replace("Service", "Server")));
         newSite.Properties["ServerComment"][0] = siteName;
         newSite.Properties["ServerBindings"].Value = hosts;
         newSite.Invoke("Put", "ServerAutoStart", 1);
         newSite.Invoke("Put", "ServerSize", 1);
         newSite.CommitChanges();
    
         //Creates root directory by specifying the local path, default  document and permissions
         DirectoryEntry newSiteVDir = newSite.Children.Add("Root", "IIsWebVirtualDir");
         newSiteVDir.Properties["Path"][0] = physicalPath;
         newSiteVDir.Properties["EnableDefaultDoc"][0] = true;
         newSiteVDir.Properties["DefaultDoc"].Value = "default.aspx";
         newSiteVDir.Properties["AppIsolated"][0] = 2;
         newSiteVDir.Properties["AccessRead"][0] = true;
         newSiteVDir.Properties["AccessWrite"][0] = false;
         newSiteVDir.Properties["AccessScript"][0] = true;
         newSiteVDir.Properties["AccessFlags"].Value = 513;
         newSiteVDir.Properties["AppRoot"][0] = @"/LM/W3SVC/" + Convert.ToString(siteId) + "/Root";
         newSiteVDir.Properties["AppPoolId"].Value = defaultAppPool;
         newSiteVDir.Properties["AuthNTLM"][0] = true;
         newSiteVDir.Properties["AuthAnonymous"][0] = true;
         newSiteVDir.CommitChanges();
    
         //Sets the framework version to 2.0 for the new website
         //Assuming the version will be something like n.n.nnnnn
         Regex versionRegex = new Regex(@"(?<=\\v)\d{1}\.\d{1}\.\d{1,5}(?=\\)");
         PropertyValueCollection lstScriptMaps =  newSiteVDir.Properties["ScriptMaps"];
         System.Collections.ArrayList arrScriptMaps = new   System.Collections.ArrayList();
          foreach (string scriptMap in lstScriptMaps)
          {
              if (scriptMap.Contains("Framework"))
              {
                 arrScriptMaps.Add(versionRegex.Replace(scriptMap, frameworkVersion));
              }
              else
             {
                 arrScriptMaps.Add(scriptMap);
              }
           }
          newSiteVDir.Properties["ScriptMaps"].Value =  arrScriptMaps.ToArray();
          newSiteVDir.CommitChanges();
          return "Website created successfully.";
      }
      catch (Exception ex)
      {
          return "Website creation failed. <br/>" + ex.Message;
      }
    }
    
    /// <summary>
    /// Retunrs Unique SiteId for the new website
    /// </summary>
    /// <param name="metabasePath"></param>
    /// <returns></returns>
    private int GetUniqueSiteId(string metabasePath)
    {
         int siteId = 1;
         DirectoryEntry objDirEntry = new DirectoryEntry(metabasePath);
         foreach (DirectoryEntry e in objDirEntry.Children)
         {
            if (e.SchemaClassName == "IIsWebServer")
            {
                int id = Convert.ToInt32(e.Name);
                if (id >= siteId)
                siteId = id + 1;
             }
          }
         return siteId;
    }
    
  6. Now take a new “ASP.NET website” and add the web reference to the created web service.
  7. In default.aspx, place a textbox control and button control and in button click event handler, call the web method by passing in textbox value.
    Service createWebsiteService = new Service();
    lblStatus.Text = createWebsiteService.CreateWebsite(txtSiteName.Text);
    
  8. Now get ready to run the application and enter a website name “www.stweet.com” in the textbox and click the button. OOPsssss!!!
  9. Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))

    Don’t worry. We are not yet done with required configuration part yet.

Configuration

Basically for creating a new website on IIS, user requires administrator privileges. But by default ASP.NET application runs under low privileged account i.e., Network Service, so additional settings needs to be done to run the above mentioned code.

Method 1

Remember, we have used two ASP.NET applications for this, one for website and another for web service. Now web service needs to be run under administrative privileges. Add below code in the “web.config” file under “system.web” section.

<identity impersonate="true" userName="adminname" password="adminpwd"/>

It impersonates the user request with administrator privileges and thus executes the code successfully.

Method 2

Typing administrator user name and password in web.config may not be feasible and less secured. No problem! We can do it in other way by creating a new application pool for the web service as explained below.

  1. Open IIS
  2. Right click on Application Pool > select “New” > select “Application Pool”
  3. Enter “Application Pool ID” and click OK. New application pool is created
  4. Right click on newly created application pool > select “Properties”
  5. Navigate to “Identity” tab, choose “configurable” and enter administrator user name and password and click “OK”
  6. Now configure web service to run under newly created application pool. Right click on already created web service>>Select “Properties” and navigate to “Home Directory” tab >>Select newly create application pool under “Application Pool” field

Note: Be careful with step no. 5 and 6, configuration issues occur while running the web service. This happens when invalid password is entered under the administrator account in application pool. In this case, modifying the administrator password doesn’t help. We need to again start configuration from beginning by removing the web service association with application domain and deleting the application domain and creating a new one with correct credentials.

For both methods, it is preferred to have new admin account which serves only this purpose and make sure he is member of  IIS_WPG user group. Because due to security reasons, password of existing administrator may change from time to time and for every reset we need to again re-configure the application pool.

That’s it. Now run the application and see the result.

Additional Inputs

  1. If time is not crucial part for new website creation on IIS, consider storing the website names in a database and implement the code written in the web service in a windows application (or) windows service and schedule it, so that the configuration part can be skipped.
  2. On Load Balancing servers, this won’t work because we don’t know where the request is routed. In this scenario, windows application/service is preferred.

Conclusion

This article demonstrated one of the concepts to create a new website on IIS programmatically using ASP.NET and C#.

Note: It is just the concept which is explained in this article but doesn’t include additional things like exception handling & web service security. Please feel to modify it according to your requirements.

It is my first article, please bear with me and it would be great help if you guys provide feedback and help me improve the content.

Advertisements

76 thoughts on “Creating a new website programmatically on IIS using ASP.NET and C#

  1. Khadar Khan

    Sundeep,
    It’s crystal clear and easy step by step approach to configure the IIS programmatically. A complete real time scenario and I really liked the way you have followed. A rare content and this will definitely helpful for auto website creation projects. Kudos to you. Looking forward to see more entries from you.

    Thanks
    Khadar

  2. Sundeep, I am having one problem, i.e. my site is getting created successfully. It is showing in the IIS Server. But I cannot access teh same. As soon as I try accessing the site “Page Cannot Be Displayed ” error is being thrown. I have checked the application pool and starting page. All are in sync with the running sites. Can U help?

    • Sriya, it might occur due to various reasons. Consider the below mentioned points

      1. Is the new domain correctly pointed to the web server?
      To check this, ping the domain and verify whether its pointing to correct webserver ipaddress.

      2. Check the host header of the new website created?
      Verify whether they have “newwebsitename.com” and “www.newwebsitename.com” entries?

      3. Alternatively, we can mock test whole process of creating new website on IIS and access it by typing the URL in the browser, without need to buying domain names and pointing to the webserver. After application is tested, we can deploy it in real time scenario.

      For this we require local intranet with atleast two machines, one is webserver which hosts the application and other is the client machine which be treated as end user. Below are the steps involved:

      i. Configure the application on a server machine.
      ii. Access the application and create a website to make sure “new website” gets created on the server machine. This step ensures that code is working fine and also completes the configuration required on server machine.
      iii. On client machine, add host entries in hosts file (C:\WINDOWS\system32\drivers\etc\hosts) and point to the web server on which new website is created and type the “url” from the client machine to access the website as we do in real time. Check this post to get more details for adding host entries.

      Note: We can access the new websites created case only from client machine. We can’t access the website from the webserver, it gives “HTTP 401.1 – Unauthorized: Logon Failed” error. Check this post for rectifying it.

      If you have further doubts, please feel free to post here.

      • hi, we have created the site the way guided, however there is some stuff we need support with.

        1 our server is having plesk 12.5 Installed, so we need that when we create site it must be there as subdomain or main domain in pleask as well, can you help me out.
        2 We Are having folder and template of file, like 10 design, so we need tweaking that help customer to choose the design as per there preferense, as happen with wordpress and they can change the same anytime as and when they need, but the primary content or user content will be there.

        Response appreciated.

  3. Jayesh

    Hi ,
    This is very nice code.
    I want to know more regarding create sub domain dynamically for a website using code.

    Best Regards,
    Jayesh Sorathia

  4. Hi Sundeep,

    Very good article. this type of scenario we have faced in one of my previous project in which we are suppose to create website for Real Estate Developer.

    This is very good example to get this type of requirement done.

    I must say that this is the kind of content that developer will find very rarely..

    Looking to have some more useful articles from your side in future..

    Regards
    Ramani Sandeep

  5. Arul

    Sundeep, This code is great. I had already hosted web site and running it successfully but my requirement is i need to configure the another project folder under that web site. For ex assume this is my website http://www.xxxxx.com i need to configure xxxx folder under the site http://www.xxxxx.com via coding. Please help me for this

    • Thanks for your comment Arul.

      Sorry for the delay in response. Actually you’ve to retrieve the siteid of website which is in IIS and by using directoryentry class you can create a directory under the website.

  6. DuBrute

    Hi,

    I am having problems abour DirectoryEntry instance. can’t create..

    May you help me about this ? If any chance, please share your project.

    ps. I added references.

    • DuBrute, Thanks for visiting my blog. Actually I had implemented this on virtual machine. I don’t seem I have backup of the disk to give you the solution. By the way what is the error you’re getting.

  7. mihir

    hey sandeep,

    how would you add a new website automatically under localhost. I want to create a website which is at the path – “localhost/”.

    The script you have given would add the website at the top level i.e the same level as localhost or

    thanks,
    mihir

  8. pradeep

    HEY Sundeep Podugu, NICE Article Yaar
    See i have completed all step
    i am getting ERROR Saying:
    “Website creation failed.
    The RPC server is unavailable. ”

    Please Help me!!!!

    thanks Sundeep Podugu

    • Thank you for visiting my blog.

      Check step no. 2, the value of “metabasePath” key should have your server name instead of “C37336-113134”. Here “C37336-113134” is my server name.

      And to avoid other errors please follow configuration part properly.

      Hope this helps 🙂

  9. pradeep

    Hey Sundeep Podugu

    Thanks A LOTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT

    IT’s Working Fine now…………

    Good job keep it up……

  10. Hi, do you know if its also possible to change the host name (host header value) of an existing iis6 website programmatically?

    Any sample code is much appreciated. Thanks.

  11. Mark

    Thanks for this, im working on an application needing to create new sites. however i presume this creates the website instance on IIS but how would i get the pages / site structure/ assets copied across at same time?

    • Hi Mark,

      As you can read through my article, I had only one path pointed by all websites. Based on the url, the application determines which website content to be rendered. In terms of code, below are two lines

      //Gets the default file location stored in web.config file
      string physicalPath = Convert.ToString(ConfigurationManager.AppSettings[“defaultFileLocation”].ToString());

      //Assigns it to the “path” of newly created virtual directory
      DirectoryEntry newSiteVDir = newSite.Children.Add(“Root”, “IIsWebVirtualDir”);
      newSiteVDir.Properties[“Path”][0] = physicalPath;

      In your case, if websites needs to be configured with different file locations then pass full path to the “createwebsite” method along with the name. Instead of getting the path from web.config file, use the passed variable and for this, I assume files are already on the server.

      Hope this helps.

      Thanks,
      Sundeep

  12. Mark

    thanks Sundeep, it all makes sense apart from im not entirely sure regarding the need for different file locations?

    how it will work is a user chooses both a theme for their site during signup and adds content (both of which will be stored in database). the theme will be fired on pre_init of each site load and content pulled in from db.

    basically, its like the users see a “demo” site and can simply change theme/images and add content to suit their needs for their own site. (address being set up as http://www.username.mysite.com)

    as each site will essentially be the same as regards configuration/page options/folder structure (ie pages/images/js/css etc) im not sure if i need to replicate this for each new subsite or if its possible to just have a “default” sub-site that can drive each different site, obviously over-riding the appropriate theme and content from db depending on user.

    what are your thoughts on how to best implement this ?

    • Hey Mark,

      I think we had somewhat similar situation as yours. Assume that we copy the common contents in each website created. And now, what if we need to make change to the design or to any file, it should be reflected in all locations. For this reason, I preferred single application to deal with.

      And regarding the customization, we had users uploading images and selecting themes too. We saved the images in another shared location under individual folders and the content i.e., html which the user customized into the db. When the page gets loaded, the url is checked and appropriate content gets loaded from the db.

      First step is to design this kind of structure thoroughly and start with the implementation.

      Thanks,
      Sundeep

      • Mark

        Hi Sundeep, ive just made a start on this, first issue i noticed is my site is created at the root (and has an X by it so doesnt seem to be created correctly) but anyway i would prefer it as a subdomain of my own main site. Though im just working with localhost at the moment so i guess this would be localhost/newsite?

        secondly how do you then associate each site with the physical web files and the users db content? do you use a single “base” site location for all the default files?

      • Mark,

        As the website is created but it has red cross means that some of parameters are missing. Check the parameters like host headers. Since it is sub domain host header must be different and try to edit it manually. If it works then programmatically assign them in your code.

        The metabasepath in web.config must be “IIS://servername/W3SVC”. Substitute server name with your machine name.

        As discussed we stored files for all website in one location and dynamically populated content based on site url by setting application path same for all websites.

      • Mark

        Sundeep, may i ask did you have the application for the subdomain websites within your main application or as a totally separate entity?

        Would it be workable within my main application where i could add existing business and data namespaces and avoid a lot of replication? Could i use this approach and have this internal application still work as the sub-domain target?

        Or are there any issues that means it would be best kept separate?

        Any thoughts or advice on this?

  13. Mark

    Thanks,

    this definately sounds the ideal approach for me, with less maintenance and of course more easier management of deleting sites when users no longer wish to continue with them.

    i will make a start following your advice and hopefully be able to ask you questions if i hit any problems.

  14. Antariksh

    Hi Brother,

    Seriously very well drafted article. It helped me a lot.
    I could solve my problem in no time. Good one buddy.

  15. rahul

    hi , sundeep

    i am using vs10
    i got a exception in this line — int siteId = GetUniqueSiteId(metabasePath);

    {System.Runtime.InteropServices.COMException (0x80005000): Unknown error (0x80005000)
    at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
    at System.DirectoryServices.DirectoryEntry.Bind()
    at System.DirectoryServices.DirectoryEntry.get_IsContainer()
    at System.DirectoryServices.DirectoryEntries.ChildEnumerator..ctor(DirectoryEntry container)
    at System.DirectoryServices.DirectoryEntries.GetEnumerator()
    at WebServiceforAccounting.Service1.GetUniqueSiteId(String metabasePath) in D:\eXtendcode\WebServiceforAccounting\WebServiceforAccounting\WebServiceforAccounting\Service1.asmx.cs:line 111
    at WebServiceforAccounting.Service1.CreateWebsite(String siteName) in D:\eXtendcode\WebServiceforAccounting\WebServiceforAccounting\WebServiceforAccounting\Service1.asmx.cs:line 45}

    can you help me ?

    • Hey Rahul,

      I assume you are creating website on IIS 6. I think issue is with security configuration settings. Double check configuration settings and also do see posted comments above for more info.

      Thanks,
      Sundeep

  16. rahul

    hi rahul ,
    can we create asp.net webservice project using c# and then deploy this project on iis programmatically ?

    I m elaborate this question :
    Suppose we have a asp.net application and there is a button inside the application when we click on this button then asp.net webservice project should be created and it deploy on iis .
    Is it possible?

    waiting for ur reply

    Thanks

    • @Asif, I am sorry I don’t have code now. I have implemented this on VM. Since you’re getting error with service initialization, make sure you’ve added reference to web service. If you did, check the proxy name and replace “Service” with it.

  17. sandeep

    I need to create sub domain from code. For example my web site register new user named battulga. After automatically create battulga.mydomain.com. How to do this?

  18. Mohan

    Thanks for your post. It give more idea and useful information about IIS dyanmic website creation.

    I want to create subdomain in IIS. suppose , I having url (www.ExWebsite.com). I want create new website with subdomain of (www.exwebsite.com) that is http://www.new.exwebsite.com.

    can you tell me how to do this.

    Thank you.

  19. Vaurn Sharma

    Hi Sundeep,

    First of all, this article rocks!!!.. IT really helped me to create website via code.
    I am sure you can help me with one thing.

    By executing the code , I managed to create the site in IIS but the site address that is
    http:// ABC.DomainName.com is not accessible by internet.

    I think the issue is that it is not adding records to ‘A’, ‘CNAME” and ‘MX’ records to DNS hence it is not able to create new sub domain.

    Can you please help me on the same on how to add the DNS records?

    The reason I am saying that the issue is one what I stated above is that when I am creating sub domain manually via ‘Control Panel’ (Plesk) of the web host, it adds the DNS records too but that is not happening when we are doing it via code.

    Please help..

    Regards
    Varun

      • Dieter

        What I’m trying is to make request via an API everything that a website needs to be created/stopped/started/deleted/ …
        So I guess that scheduling it is not an option.

      • If it needs to be on-demand, then you would need something mentioned in this article. If it can be with some delay, store the requests in a DB table with columns such as action, iscompleted, etc and use the exe file to schedule every 10 mins to check for new requests.

  20. Jaydevsinh Jadeja

    Hello Sundeep

    Thanks for providing Great Artical.. 🙂

    Using this code I had already hosted web site and running it successfully but my requirement is same as @Arul requirement which is in Post No 13. and as per your answer i tried with creating sub virtual directory using Site id of existing Website but i cant get output so Please help me for this.

    i want to create http://jaydev/Dynamic1/Dynamic1_1

    foreach (DirectoryEntry e in objDirEntry.Children)
    {

    if (e.SchemaClassName == “IIsWebServer”)
    {
    if (e.Name == “5”)//Dynamic1 Website Name
    {
    DirectoryEntry newsiteentry = e.Children.Find(“Root”, “IIsWebVirtualDir”);

    //creates new website by specifying site name and host header
    newSite = newsiteentry.Children.Add(“6”, “IIsWebVirtualDir”);
    newSite.Properties[“ServerComment”].Value = “Dynamic1_1”;
    newSite.Properties[“ServerBindings”].Value = hosts;
    newSite.Invoke(“Put”, “ServerAutoStart”, 1);
    newSite.Invoke(“Put”, “ServerSize”, 1);
    newSite.CommitChanges();
    }

    }
    }

  21. Madhvi Gupta

    Hi Sandeep , your article really awesom, but I want one help from you is that – I want to host one asp.net web api application project (this is my web api project) into IIS programmtically and why I wnat to do this is because very frequently I need to host my application into production server IIS and for that I have to labour things which is not good as a developer perspective. Thanks!!!!!

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s