HttpListener Series – 2 – Websiting   1 comment

The series index here.

One of the most common uses of IIS is to host websites through a file system folder where relative paths are used for resources. There isn’t much to it but some string prefix handling and some stream copying but I’ll provide a simple implementation of what it needs to be done to run a simple static website.

Let’s say we have a folder containing a website looking like this:

WebSiteFolder

The content of the files is as follows…

Page.htm:

<!DOCTYPE HTML>
<html>
<head>
    <title>HttpListener Demo HTML Page</title>
    <link rel="stylesheet" type="text/css" href="Files/Styles.css" />
</head>
<body>
    <p>
        Here is the HTML page.</p>
    <input type="button" id="aButton" value="Click to Run Script" />
</body>
</html>
<script type="text/javascript" src="Files/Scripts.js"></script>

Files/Styles.css:

p
{
    font-size: 20px;
    font-weight: bold;
}

input
{
    border: 2px solid blue;
    font-style: italic;
}

Files/Scripts.js:

document.getElementById("aButton").onclick = function () {
    alert("You clicked the button");
};

The implementation of this website hosting would be something like so:

string baseFolder = @"C:\WebSite\";

var listener = new HttpListener();
listener.Prefixes.Add("http://+/HLD/");

listener.Start();
Console.WriteLine("Listening ...");

while (true)
{
    var context = listener.GetContext();

    Console.WriteLine("Request received for: " + context.Request.Url.AbsoluteUri);

    var baseUrl = "http://+/HLD/".Replace("+", context.Request.Url.Authority);
    var resourceRelativePath = context.Request.Url.AbsoluteUri.Substring(baseUrl.Length);
    var resourceFullPath = Path.Combine(baseFolder, resourceRelativePath);

    if (File.Exists(resourceFullPath))
    {
        context.Response.StatusCode = 200;
        context.Response.StatusDescription = "OK";

        string contentType = "application/octet-stream"; // just to have a default
        switch (Path.GetExtension(resourceFullPath))
        {
            case ".htm":
                contentType = "text/html";
                break;
            case ".css":
                contentType = "text/css";
                break;
            case ".js":
                contentType = "application/x-javascript";
                break;
        }
        context.Response.ContentType = contentType;

        var fileStream = File.OpenRead(resourceFullPath);
        context.Response.ContentLength64 = fileStream.Length;
        fileStream.CopyTo(context.Response.OutputStream, 64*1024);
        fileStream.Close();
    }
    else
    {
        context.Response.StatusCode = 404;
        context.Response.StatusDescription = "Not Found";
        var writer = new StreamWriter(context.Response.OutputStream);
        writer.Write(string.Format("<!DOCTYPE HTML><html><head><title>Resource Not Found</title></head><body><b>Error 404 - Resource Not Found</b> - There resource ('{0}') requested was not found.</body></html>",
            resourceRelativePath));
        writer.Close();
    }

    context.Response.Close();
}

A little bit of string comparison and we’re all done. Now you can access “http://localhost/HLD/Page.htm”.

Notes:

  • The functionality of a default document can be easily be implemented by responding to an empty resourceRelativePath with a predefined document.
  • Response.ContentType must be set before beginning to send the resource stream, otherwise it will not be taken in account.
  • 64KB (64B * 1024) of buffering to copy the resource stream should be enough. Play with and find what it implies in the speed of the delivery and find your own buffer size.
Advertisements

Posted 2012/07/09 by Bigsby in Hands On

One response to “HttpListener Series – 2 – Websiting

Subscribe to comments with RSS.

  1. Pingback: HttpListener Series « Bigsby Spot

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

%d bloggers like this: