Category: C#


Generate HTML e-mail body in C# using templates

Almost a year ago, I answered a question on StackOverflow, about if there’s a better way to generate HTML e-mails in C# than using a StringBuilder and just appending strings one by one.

I think that any modern piece of software today, needs to send e-mail. Whether it being password recovery e-mails, rich reports, newsletters or anything else – being able to easily see and customize the look and feel of your e-mails is vital.

So, the worst way I could think of is having your HTML hidden away in some StringBuilder.Append() hell. The best solution (in my opinion) would be, if you could have plain old HTML files with parameters like <#FirstName#> so you could dynamically replace those at runtime.

The MailDefinition class

Luckily, there’s a class for that! If you read the comments on my answer on StackOverflow, you’ll notice that none of them was familiar with that class and it came as a bit of a surprise. It did for me too, I actually wrote my own “MailDefinition” class that did just about the same thing. A complete waste of time, and it only tells me that us, developers, are sometimes too trigger happy on the keyboard instead of doing some research first. A quick search in the MSDN documentation would have saved me some work here and there.

Using the MailDefinition class is pretty straight forward. You use the MailDefinition class to create an instance of MailMessage, which you can send straightaway:

MailDefinition md = new MailDefinition();
md.From = "test@domain.com";
md.IsBodyHtml = true;
md.Subject = "Test of MailDefinition";

ListDictionary replacements = new ListDictionary();
replacements.Add("<%Name%>", "Martin");
replacements.Add("<%Country%>", "Denmark");

string body = "<html><head><title>E-mail</title></head><body><div>Hello <b><%Name%>"+
    "</b><br /><br />You're from <%Country%>.</div></body></html>";

MailMessage msg = md.CreateMailMessage("you@anywhere.com", replacements,
    body, new System.Web.UI.Control());


Instead of having the HTML inside the code, you could easily have it in your database or as a file on the computer. That will also enable you to edit the look and feel of the HTML template at any time, without having to rebuild and deploy your application.

MailDefinition is located in the System.Web assembly, so don’t forget to add reference to that from your project.

I love the new model validation features in System.ComponentModel.DataAnnotations. One thing I don’t like though, is that the ErrorMessageResourceName is loosely typed. The ErrorMessageResourceType, however, is a System.Type which will be strongly typed by assigning its value using the typeof(Namespace.ResourceSetType) method.

Since there’s no build-breaking reference between a resource file and the value of the ErrorMessageResourceName on all classes where you use it, I thought it would be cool to have a unit test that verifies the existence of all referenced resource keys.

Remember to add a reference to System.ComponentModel.DataAnnotations.

Code

/// <summary>
/// Verifies that all properties that are decorated with validation data-annotations, refers to 
/// an existing resource. This will make sure, that missing resources are not referenced.
/// </summary>
[TestMethod]
public void All_Properties_With_Validation_Annotations_Must_Refer_To_Existing_Resource()
{
    Assembly assembly = Assembly.Load(new AssemblyName("MyApp.Model.Namespace"));
    var types = assembly.GetTypes().Where<Type>(t => t.IsClass && !t.IsAbstract);

    foreach (var type in types)
    {
        var properties = type.GetProperties();

        foreach (PropertyInfo property in properties)
        {
            var attributes = property.GetCustomAttributes(true);

            foreach (var item in attributes)
            {
                if (item is ValidationAttribute)
                {
                    ValidationAttribute val = item as ValidationAttribute;

                    Assert.IsNotNull(val);

                    if (val.ErrorMessageResourceType != null)
                    {
                        Assert.AreNotEqual(String.Empty, val.ErrorMessageResourceName,
                            String.Format(@"Validation Error Resource specified on property:
                        {0}.{1} is empty!", type.ToString(), property.Name));

                        try
                        {
                            ResourceManager rm = new ResourceManager(val.ErrorMessageResourceType);
                            string resourceValue = rm.GetString(val.ErrorMessageResourceName);
                            Assert.IsFalse(String.IsNullOrEmpty(resourceValue),
                                String.Format(@"The value of the Validation Error Resource specified on property:
                            {0}.{1} is empty!", type.ToString(), property.Name));
                        }
                        catch (MissingManifestResourceException)
                        {
                            Assert.Fail(String.Format(@"Validation Error Resource specified on property:
                            {0}.{1} could not be found!", type.ToString(), property.Name));
                        }
                    }
                }
            }
        }
    }
}

Multiple SSL certificates on IIS using host headers

In IIS SSL sites have seemed to be limited to only one site per network interface, since you (from IIS Manager) cannot specify a host header binding on the HTTPS protocol.

It turns out, that it is only a limitation in the UI. So to have e.g. two sites with their own dedicated SSL certificate we need to add a host header binding on port 443 from either appcmd, managed code or by editing the applicationHosts.config file.

I like managed code the most, so I’ve written a small method in C# that does the trick. You need to have two SSL certificates named www.ssl1.com and www.ssl2.com installed on the machine. I just created a self signed certificate for both of them using the IIS Manager.

using System.Security.Cryptography.X509Certificates;
using Microsoft.Web.Administration;

namespace IisSsl
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ServerManager _serverManager = new ServerManager())
            {
                string siteName = "SSL2";
                string certName = "www.ssl2.com";

                X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
                store.Open(OpenFlags.ReadOnly);

                X509Certificate2 certificate = store.Certificates[0];

                Site site = _serverManager.Sites[siteName];

                if (site != null)
                {
                    site.Bindings.Add("*:443:" + certName,
                        certificate.GetCertHash(), store.Name);
                }
                store.Close();

                _serverManager.CommitChanges();
            }
        }
    }
}

Remember to add a reference to C:\Windows\System32\inetsrv\Microsoft.Web.Administration.dll in order to use the ServerManager class.

Search Twitter from C# using LINQ to XML

In some applications, it could be cool to have a feature that enabled the user to quickly get a glimpse of what people are saying on Twitter about the user or their product, service, company etc.

For instance, a service like GetSatisfaction.com has a feature just like that. They call it Overheard, and this is what it looks like:

overheard

There’s nothing like Twitter to give you feedback. I think MediaTemple felt the effect of unhappy customers on Twitter when their servers broke down, and stayed there for more than two days!

Anyway. I wanted to search from C#, and get back a DataTable. Here’s how it’s done:

    /// <summary>
    /// Searches Twitter for the specified query.
    /// </summary>
    /// <param name="query">The query.</param>
    /// <returns>Returns the search results as a DataTable</returns>
    public DataTable Search(string query)
    {
      DataTable dt = new DataTable();
      dt.Columns.Add("text");
      dt.Columns.Add("html");
      dt.Columns.Add("pubdate");
      dt.Columns.Add("id");
      dt.Columns.Add("link");
      dt.Columns.Add("authorname");
      dt.Columns.Add("authorlink");

      XDocument tweetResults = XDocument.Load(String.Format(
      "http://search.twitter.com/search.atom?q={0}", HttpUtility.UrlEncode(query)));
      XNamespace atomNS = "http://www.w3.org/2005/Atom";
      var q = from tweet in tweetResults.Descendants(atomNS + "entry")
              select new
              {
                Text = (string)tweet.Element(atomNS + "title"),
                Html = (string)tweet.Element(atomNS + "content"),
                DatePublished = DateTime.Parse((string)tweet.Element(atomNS + "published")),
                Id = (string)tweet.Element(atomNS + "id"),
                Link = (string)tweet.Elements(atomNS + "link")
                .Where(link => (string)link.Attribute("rel") == "alternate")
                .Select(link => (string)link.Attribute("href"))
                .First(),
                Author = (from author in tweet.Descendants(atomNS + "author")
                          select new
                          {
                            Name = (string)author.Element(atomNS + "name"),
                            Uri = (string)author.Element(atomNS + "uri"),
                          }).First()
              };

      foreach (var item in q)
      {
        dt.Rows.Add(item.Text, item.Html, item.DatePublished, item.Id, item.Link,
                    item.Author.Name, item.Author.Uri);
      }

      return dt;
    }

Yesterday, I blogged about how you can use Google Translate to translate a string in C#. To make it more useful than just a simple translator, and because I need to translate some Global Resource files for an E-commerce website that I’m working on, I wanted to create a small Windows Application in C# that could read a Global Resource file (.resx) and translate it into a selected language using the method for translating a word in C# that i blogged about yesterday.

image

This is how it looks so far. You simply select the resource file you want to translate. Select the current language of the resource file in the middle box, and select the language you want to translate it to in the last box. Click Translate at it should work. The new resource file will be saved in the same location as the application itself.

Translate text in C#, using Google Translate

Sometimes, it would be great to be able to translate a text from e.g. English to Danish directly from C#. This could be useful when you want to translate a Resource file into another language.

Google Translate is awesome. There’s also Windows Live Translator, but Microsoft are far behind Google (also) in this game.

Code:

using System;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;

namespace Utilities
{
  public static class Translator
  {
    /// <summary>
    /// Translates the text.
    /// </summary>
    /// <param name="input">The input.</param>
    /// <param name="languagePair">The language pair.</param>
    /// <returns></returns>
    public static string TranslateText(string input, string languagePair)
    {
      return TranslateText(input, languagePair, System.Text.Encoding.UTF7);
    }

    /// <summary>
    /// Translate Text using Google Translate
    /// </summary>
    /// <param name="input">The string you want translated</param>
    /// <param name="languagePair">2 letter Language Pair, delimited by "|". 
    /// e.g. "en|da" language pair means to translate from English to Danish</param>
    /// <param name="encoding">The encoding.</param>
    /// <returns>Translated to String</returns>
    public static string TranslateText(string input, string languagePair, Encoding encoding)
    {
      string url = String.Format("http://www.google.com/translate_t?hl=en&ie=UTF8&text={0}&langpair={1}", input, languagePair);

      string result = String.Empty;

      using (WebClient webClient = new WebClient())
      {
        webClient.Encoding = encoding;
        result = webClient.DownloadString(url);
      }

      Match m = Regex.Match(result, "(?<=<div id=result_box dir=\"ltr\">)(.*?)(?=</div>)");

      if (m.Success)
        result = m.Value;

      return result;
    }
  }
}

The translated string is fetched by the RegEx close to the bottom. This could of course change, and you have to keep it up to date.

C# TwitPic API client

I’ve spent some time lately, playing around with the Twitter API. And along with that belongs the TwitPic’s API. I’m using Twitter a lot, to stay in touch with tech news, other developers and just for fun. But it’s getting more and more used for a lot of different things, and I needed it to integrate with an E-commerce platform I’m developing.

The code for post a picture to TwitPic looks like this:

    /// <summary>
    /// URL for the TwitPic API's upload method
    /// </summary>
    private const string TWITPIC_UPLADO_API_URL = "http://twitpic.com/api/upload";

    /// <summary>
    /// URL for the TwitPic API's upload and post method
    /// </summary>
    private const string TWITPIC_UPLOAD_AND_POST_API_URL = "http://twitpic.com/api/uploadAndPost";

    /// <summary>
    /// Uploads the photo and sends a new Tweet
    /// </summary>
    /// <param name="binaryImageData">The binary image data.</param>
    /// <param name="tweetMessage">The tweet message.</param>
    /// <param name="filename">The filename.</param>
    /// <returns>Return true, if the operation was succeded.</returns>
    public bool UploadPhoto(byte[] binaryImageData, string tweetMessage, string filename)
    {
      // Documentation: http://www.twitpic.com/api.do
      string boundary = Guid.NewGuid().ToString();
      string requestUrl = String.IsNullOrEmpty(tweetMessage) ? TWITPIC_UPLADO_API_URL : TWITPIC_UPLOAD_AND_POST_API_URL;
      HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl);
      string encoding = "iso-8859-1";

      request.PreAuthenticate = true;
      request.AllowWriteStreamBuffering = true;
      request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
      request.Method = "POST";

      string header = string.Format("--{0}", boundary);
      string footer = string.Format("--{0}--", boundary);

      StringBuilder contents = new StringBuilder();
      contents.AppendLine(header);

      string fileContentType = GetImageContentType(filename);
      string fileHeader = String.Format("Content-Disposition: file; name=\"{0}\"; filename=\"{1}\"", "media", filename);
      string fileData = Encoding.GetEncoding(encoding).GetString(binaryImageData);

      contents.AppendLine(fileHeader);
      contents.AppendLine(String.Format("Content-Type: {0}", fileContentType));
      contents.AppendLine();
      contents.AppendLine(fileData);

      contents.AppendLine(header);
      contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "username"));
      contents.AppendLine();
      contents.AppendLine(this.Username);

      contents.AppendLine(header);
      contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "password"));
      contents.AppendLine();
      contents.AppendLine(this.Password.ToInsecureString());

      if (!String.IsNullOrEmpty(tweetMessage))
      {
        contents.AppendLine(header);
        contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "message"));
        contents.AppendLine();
        contents.AppendLine(tweetMessage);
      }

      contents.AppendLine(footer);

      byte[] bytes = Encoding.GetEncoding(encoding).GetBytes(contents.ToString());
      request.ContentLength = bytes.Length;

      using (Stream requestStream = request.GetRequestStream())
      {
        requestStream.Write(bytes, 0, bytes.Length);

        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
          using (StreamReader reader = new StreamReader(response.GetResponseStream()))
          {
            string result = reader.ReadToEnd();

            XDocument doc = XDocument.Parse(result);

            XElement rsp = doc.Element("rsp");
            string status = rsp.Attribute(XName.Get("status")) != null ? rsp.Attribute(XName.Get("status")).Value : rsp.Attribute(XName.Get("stat")).Value;

            return status.ToUpperInvariant().Equals("OK");
          }
        }
      }
    }

Windows Live Development – Authenticating users via Windows Live ID

With so many online services out there, you nearly claim a new online identity somewhere every day. You tend to use the same username and password couple for all of them, but sometimes your preferred username is taken, or your password does not meet the sites’ password policy. I reckon I have well over 100 online identities out there – I rely on the same 3-4 combinations of username and password, and it’s really messy. In this blog post I’m going to cover how to authenticate users of an ASP.NET application against Windows Live, using the SDK for Windows Live ID. I’m going use the built-in ASP.NET Membership mechanism and go from there.

I could have gone the OpenID way, but Scott Hanselman already did an example on OpenID, so I thought I’d try out Windows Live. Jeff Atwood asked the question, if we really need another username and password in the pursuit of the best authentication model for stackoverflow.com.

Conceptual idea of using Windows Live ID

tmpF3A8Windows Live ID, is the technology you should be quite familiar with when authenticating on Microsoft web sites, and Messenger. If you want to know more about what Windows Live ID is, take a look at this video from Channel9.

When using Windows Live ID, you redirect the user to the Windows Live login-page, with a return URL specified. When the user authenticates, Windows Live will redirect the user back to your site, and delivering a user id and a token. Here’s an overview of how it looks:

image

Getting your application ID to use Windows Live ID

To get started using Windows Live ID, first of all you need an application ID. Basically you need to sign up for one, and register your application. Go to https://msm.live.com/app/default.aspx and click ‘Register an Application’. (You can find Microsoft’s guide to this here: http://msdn.microsoft.com/en-us/library/cc287659.aspx)

tmpF3F5

Leave Domain Name blank. Save your self-chosen Secret Key for later use, and submit the form. When you see the confirmation page, your application ID is shown. Copy that, as we’re going to use it later.

In the return URL field, type the URL of your application followed by a name of a page to handle the Windows Live ID communication, like http://localhost/demoapp/webauth-handler.aspx.

Download and install Windows Live ID Web Authentication SDK

Microsoft has made it quite easy for ASP.NET developers to get started, by providing an SDK. Download it here: http://www.microsoft.com/downloads/details.aspx?FamilyId=24195B4E-6335-4844-A71D-7D395D20E67B&displaylang=en and install the SDK. By default it is installed here: C:\Program Files\Windows Live ID\WebAuth

From the SDK we need a class called WindowsLiveLogin, located in the App_Code folder of the sample. Keep this file in mind for a few seconds.

Start coding – create a new website

Open Visual Studio 2005/2008 and create a new ASP.NET website the way you want it. First we will add the WindowsLiveLogin.cs file to our App_Code folder. (C:\Program Files\Windows Live ID\WebAuth\Sample\App_Code\WindowsLiveLogin.cs).

Leave the default.aspx page, and put the following HTML in the markup:

<html>
<head>
  <title>Windows Live&trade; ID</title>
</head>
<body>
  <iframe id="WebAuthControl" name="WebAuthControl" src="http://login.live.com/controls/WebAuth.htm?appid=<%=AppId%>&style=font-size%3A+10pt%3B+font-family%3A+verdana%3B+background%3A+white%3B"
    width="80px" height="20px" marginwidth="0" marginheight="0" align="middle" frameborder="0"
    scrolling="no"></iframe>
  <%
   1:  if (UserId == null)
   2:      {

%>
<p>
This application does not know who you are! Click the <b>Sign in</b> link above.</p>
<%

   1:  }
   2:      else
   3:      {

%>
<p>
Now this application knows that you are the user with ID = "<b><%

   1: =UserId

%></b>".</p>
<%

   1:  }

%>
</body>
</html>

And this piece of code in its code-behind class.

using System;
using System.Web;
using System.IO;
using WindowsLive;

public partial class DefaultPage : System.Web.UI.Page
{
  const string LoginCookie = "webauthtoken";

  // Initialize the WindowsLiveLogin class.
  private static WindowsLiveLogin wll = new WindowsLiveLogin(true);

  protected static string AppId = wll.AppId;
  protected string UserId;

  protected void Page_Load(object sender, EventArgs e)
  {
    HttpRequest req = HttpContext.Current.Request;
    HttpApplicationState app = HttpContext.Current.Application;

    HttpCookie loginCookie = req.Cookies[LoginCookie];

    if (loginCookie != null)
    {
      string token = loginCookie.Value;

      WindowsLiveLogin.User user = wll.ProcessToken(token);

      if (user != null)
      {
        UserId = user.Id;
      }
    }
  }
}

Default.aspx will work as a login page. Users click the Sign-in button, and is redirected to Windows Live. When they authenticate, they’re redirected back to our handler page, that we will now create…

Create a new aspx page, and name it webauth-handler.aspx. Recall that this was the page we provided as the return URL when we registered the application at Windows Live.

This page will serve as the handler page for the user, when Windows Live redirects back to your site. Windows Live will post authentication specific values for you to use. Because this page is never seen by a user (we will send the user back where they began), we can simply remove all the markup.

Put the following code in your code-behind class for webauth-handler.aspx.

using System;
using System.Web;
using System.IO;
using WindowsLive;

public partial class HandlerPage : System.Web.UI.Page
{
  // Relative path to the login- and logoutpage.
  const string LoginPage = "default.aspx";
  const string LogoutPage = "default.aspx";
  const string LoginCookie = "webauthtoken";
  static DateTime ExpireCookie = DateTime.Now.AddYears(-10);
  static DateTime PersistCookie = DateTime.Now.AddYears(10);

  // Initialize the WindowsLiveLogin class.
  static WindowsLiveLogin wll = new WindowsLiveLogin(true);

  protected void Page_Load(object sender, EventArgs e)
  {
    HttpRequest request = HttpContext.Current.Request;
    HttpResponse response = HttpContext.Current.Response;
    HttpApplicationState application = HttpContext.Current.Application;

    string action = request["action"];

    if (action == "logout")
    {
      HttpCookie loginCookie = new HttpCookie(LoginCookie);
      loginCookie.Expires = ExpireCookie;
      response.Cookies.Add(loginCookie);
      response.Redirect(LogoutPage);
      response.End();
    }
    else if (action == "clearcookie")
    {
      HttpCookie loginCookie = new HttpCookie(LoginCookie);
      loginCookie.Expires = ExpireCookie;
      response.Cookies.Add(loginCookie);

      string type;
      byte[] content;
      wll.GetClearCookieResponse(out type, out content);
      response.ContentType = type;
      response.OutputStream.Write(content, 0, content.Length);

      response.End();
    }
    else if (action == "login")
    {
      HttpCookie loginCookie = new HttpCookie(LoginCookie);

      WindowsLiveLogin.User user = wll.ProcessLogin(request.Form);

      if (user != null)
      {
        loginCookie.Value = user.Token;

        if (user.UsePersistentCookie)
        {
          loginCookie.Expires = PersistCookie;
        }
      }
      else
      {
        loginCookie.Expires = ExpireCookie;
      }

      response.Cookies.Add(loginCookie);
      response.Redirect(LoginPage);
      response.End();
    }
    else
    {
      response.Redirect(LoginPage);
      response.End();
    }
  }
}

The first login test

Now we’ve got everything setup as we should, and it should be possible to login using Windows Live. View the default.aspx page in your favorite browser, and let’s try.

First you will see out login page:
tmp9D6

Click the Sign in link, which will take you to Windows Live:
wlive_signin

Sign in with your Windows Live ID, and you will return to our login page – which will now welcome you and show your user ID:
wlive_signin

Now your user has authenticated against Windows Live, using the Windows Live ID. Now it’s up to you to handle the user’s Windows Live ID, which is what I’m going to blog about in part 2 of the Windows Live Development series here…


kick it on DotNetKicks.com

Designing for Internationalization

Web sites and Web Applications today, are very often exposed beyond the borders of your home country, and therefore users speak different languages, and has a different currency, date- and time formats etc. ASP.NET provides you with an entire namespace for handling things like this. That is the System.Globalization namespace, where you will find a lot of classes for handling your every day globalization tasks. I’m not going to cover anything in this namespace now, if you want to get your hands dirty take a look at this video: http://asp.net/learn/videos/video-40.aspx where you will see how to use local and global resources for your application.

Using a global resource file for a place to store display text on buttons, labels, validation controls etc. is fine. But if you have an e-commerce site, selling products in multiple regions with different languages, you need an extra level. That level is a way to globalize e.g. the name and description of your product. When a user changes language, the name and description of your “display product details page” should change accordingly.

For me, the ideal solution should not result in extra database columns like name_us, name_da, name_es. This would be a very static solution, as you would have to change your database whenever a new language is added to your application. Nor should it require extra tables, so you need to join like hell, when you need to select a product.

I’ve decided to store e.g. the Name values as XML in the database, and parse that XML into a Dictionary<string, string> property on my Product object, with the key of the Dictionary being the language code (en-US for US English). To me this seems to work just fine. My database design is not getting more complex, and I can get and set values quite easily.

The XML string that goes into my ProductName column in the database table, looks like this:

<cultures><culture code=”en-us”>Logitech SmartCam 124</culture></cultures>

On my Product object, the Name property is a Dictionary:

private Dictionary<string, string> _Name;

public Dictionary<string, string> Name
{
  get { return _Name; }
  set
  {
    if (_Name != value) MarkDirty("Name");
    _Name = value;
  }
}

When I need to get the US English value of the Product.Name property, I call:

p.Name["en-us"]

To get a Dictionary from my XML, I use this helper method:

public static Dictionary<string, string> GetDictionary(string xml)
{
  if (String.IsNullOrEmpty(xml))
    return new Dictionary<string, string>(owner);

  XmlDocument doc = new XmlDocument();
  doc.LoadXml(xml);

  Dictionary<string, string> dic = new Dictionary<string, string>();

  foreach (XmlNode node in doc.DocumentElement)
  {
    dic.Add(node.Attributes["code"].Value, node.InnerText);
  }

  return dic;
}

And when I want to update my database, after I change the Name of the Product, I convert to Dictionary to an XML string using this helper method:

public static string GetXmlDocument(Dictionary<string, string> dic)
{
  XmlDocument doc = new XmlDocument();
  XmlNode docElement = doc.CreateNode(XmlNodeType.Element, "cultures", "");

  foreach (string key in dic.Keys)
  {
    XmlNode node = doc.CreateNode(XmlNodeType.Element, "culture", "");
    XmlAttribute att = doc.CreateAttribute("code");
    att.Value = key;
    node.Attributes.Append(att);

    node.InnerText = dic[key];

    docElement.AppendChild(node);
  }

  doc.AppendChild(docElement);

  return doc.OuterXml;
}

If you need more information on this huge topic, take a look at the ASP.NET Wiki: http://wiki.asp.net/page.aspx/55/internationalization/

Adding a Website to IIS7 programmatically

Some time ago, I blogged about Adding an Application Pool to IIS7 programmatically. The result was a new Application Pool, that uses the Integrated Pipeline in IIS7.

In this post I will show you how to add a new Website, that uses the Application Pool from the other blog post.

I’ve loaded the Console Application I used to add the Application Pool, and moved the logic from Main to a method called AddApplicationPool, to split it up nicely. It is actually even easier to add a website programmatically. Below is the code for doing just that:

private static void AddWebSite()
{
  ServerManager mgr = new ServerManager();

  if (!Directory.Exists(@"c:\inetpub\wwwroot\iis7test"))
  {
    Directory.CreateDirectory(@"c:\inetpub\wwwroot\iis7test");
  }

  // Add a new Site to the server, configured to use our the iis7test home directory.
  Site site = mgr.Sites.Add("MyWebSite", @"c:\inetpub\wwwroot\iis7test", 80);

  // Set the application pool name of the site, to use the MyAppPool application pool.
  site.ApplicationDefaults.ApplicationPoolName = "MyAppPool";

  // Clear all bindings.
  site.Bindings.Clear();

  // Make the site listen to incoming HTTP requests using host header iis7test, on port 80.
  site.Bindings.Add("*:80:iis7test", "http");

  // Set auto start to true.
  site.ServerAutoStart = true;

  // Commit the changes
  mgr.CommitChanges();
}

Notice how we add Bindings to the website. Bindings is the information that tells IIS7 when to serve our website. We use this string to configure bindings: *:80:iis7test. The first * tells IIS to listen on all IP addresses on your system. 80 is the port number, and iis7test is the host header value for this site.

To browse our website, we need to add iis7test to the computers hosts file (located in %WINDIR%\System32\Drivers\etc), and point it to 127.0.0.1.


kick it on DotNetKicks.com

Powered by WordPress | Theme: Motion by 85ideas.