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); } } }

Tuesday, July 04, 2006

Resting?

I've just become aware of a new term: REST. It stands for Representational State Transfer. It's kinda like a 'back to basics' movement about web standards and how the internet is developing. As time goes on, protocols have been layered on top of protocols. In the begining was IP, then HTTP got layered on top, subsequently SOAP was layered on top of HTTP and now we have a whole load of WS-* protocols being layered on top of SOAP. The REST people are basically saying that a lot of the new protocols are duplicating stuff that the older lower level protocols do already. Why have a SOAP action when HTTP already gives you CRUD verbs; GET, POST, PUT, DELETE? Why do we need to have identifiers when we already have the URL? A RESTafarian (I didn't make that up) would say you can do web services without SOAP or any of that WS-* stuff. Say I want to get a customer. All I'd need to do is carry out an HTTP GET for this URL: http://www.thecompany.com/enterprise/customer/0123456 That would return me a POX (Plain Old Xml, didn't make that up either) representation of my customer. RESTafarians would also argue that my customer resource should only have stuff about the customer itself, related resources (orders, invoices) should be represented by links to those resources. If it all seems slightly familiar, it is, of course, just how the simple HTML web works and the simplicity of the model is the World Wide web's fundamental strength. It's a persuasive argument and a real challenge to the current dominance (at least in the Microsoft world that I live in) of SOAP RPC style web services. Now, can REST be done with WCF, that's a question!