Wednesday, July 05, 2006

Playing with HTTP.SYS

I've been having fun playing with HTTP.SYS and the HttpListener (NET 2.0) class in System.Net. HTTP.SYS is the new kernel mode http listener that replaces winsock in 2003 Server and XP SP2 and the HttpListener class is a nice managed interface for the HTTP.SYS API. It's really easy to write your own web server and do cool things like URL mangling. Basically you just create a new instance of HttpListener and then tell it to hand you any requests that match the urls you give it. It's easy to imgaine writing a RESTfull service (see my previous post on this) using HttpListener. You could just write a windows service to receive any requests, say 'http://mikehadlow.com/restapp/' and then parse the local address part of the url to tell you which object to get from your database. So, say we got the url 'http://mikehadlow.com/restapp/customer/1234', we'd parse the local address 'restapp/customer/1234', grap 'customer' and '1234' and go to our database and 'select * from customer where id = 1234', serialise our customer object as xml and return that xml in the response. You can also host the ASP.NET pipeline in your own application using HttpListener. There's a really good MSDN article on this here. This means you no longer have to worry about having IIS installed on a machine to make your application response to http requests, any app can do it including windows forms apps, console apps and windows services. Here's some code for a little console app, showing how you use HttpListener. It's just a slight re-working of the example code from the help file. Just start up the app and browse to 'http://localhost:1234/something/else/here?somekey=somevalue&someotherkey=someothervalue' and you'll see it echo back the local address and the query string parameters.
using System;
using System.Net;

namespace HttpListenerTest
{
    class Program
    {
        HttpListener _listener = new HttpListener();

        static void Main(string[] args)
        {
            Program program = new Program();
            program.Start();
        }

        public void Start()
        {
            _listener.Prefixes.Add("http://*:1234/");
            _listener.Start();
            Console.WriteLine("Listening, hit enter to stop");
            _listener.BeginGetContext(new AsyncCallback(GetContextCallback), null);
            Console.ReadLine();
            _listener.Stop();
        }

        public void GetContextCallback(IAsyncResult result)
        {
            HttpListenerContext context = _listener.EndGetContext(result);
            HttpListenerRequest request = context.Request;
            HttpListenerResponse response = context.Response;

            System.Text.StringBuilder sb = new System.Text.StringBuilder();

            sb.Append("");
            sb.Append(string.Format("HttpMethod: {0}
", request.HttpMethod)); sb.Append(string.Format("Uri: {0}
", request.Url.AbsoluteUri)); sb.Append(string.Format("LocalPath: {0}
", request.Url.LocalPath)); foreach (string key in request.QueryString.Keys) { sb.Append(string.Format("Query: {0} = {1}
", key, request.QueryString[key])); } sb.Append(""); string responseString = sb.ToString(); byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString); response.ContentLength64 = buffer.Length; using (System.IO.Stream outputStream = response.OutputStream) { outputStream.Write(buffer, 0, buffer.Length); } _listener.BeginGetContext(new AsyncCallback(GetContextCallback), null); } } }

1 comment:

Anonymous said...

Thanks for posting this! This was really instructive in trying to figure how reporting services work without IIS running