Sunday, January 23, 2011

Hello world with Kayak and OWIN

Kayak is a lightweight opensource C# webserver which implements OWIN. OWIN stands for Open Web Interface for .NET.

Hello World

Hosting your own application using Kayak is relatively simple.

In this example I'm using a console application to run the Kayak webserver. This application has one dependency: the Kayak project.

First create a new instance of the DotNetServer. This class is an IKayakServer implementation using System.NET.Sockets.Socket. Once the instance is created you can call the Start() method. This method returns an IDisposable, which needs to be disposed once the server should stop listening. Once the server is started you can host your OwinApplication, which is a delegate with three arguments.

   1:  static void Main() {
   2:      var server = new DotNetServer();
   3:      var pipe = server.Start();
   4:   
   5:      server.Host(HelloWorldOwinApp);
   6:   
   7:      Console.WriteLine(string.Format("Listening on {0}..", server.ListenEndPoint));
   8:      Console.ReadLine();
   9:   
  10:      pipe.Dispose();
  11:  }

The first argument is an environment dictionary which represents the request the application needs to process. The second argument is a response callback which defines the status, headers and bodydata of the HTTP response. The final argument is the error callback which can be used to trap internal errors and return an appropriate response.

In this example, I'm reading the path from the environment dictionary and I'm only returning a simple "Hello world" HTTP response when it equals "/HelloWorld".

   1:  public static void HelloWorldOwinApp(IDictionary<string, object> env,
   2:      Action<string, IDictionary<string, IList<string>>, IEnumerable<object>> response,
   3:      Action<Exception> error) {
   4:          var path = env["Owin.RequestUri"] as string;
   5:   
   6:          if (path.Equals("/HelloWorld", StringComparison.OrdinalIgnoreCase)) {
   7:              var status = "200 OK";
   8:              var headers = new Dictionary<string, IList<string>>(){
   9:                                  { "Content-Type", new string[] {"text/plain"}}
  10:                              };
  11:              var bodyData = new object[] { Encoding.ASCII.GetBytes("Hello world!") };
  12:   
  13:              response(status, headers, bodyData);
  14:          }               
  15:  }


If you run this example you should be able to browse to http://localhost:1111/HelloWorld and get a response.


Conclusion

I thinks it's great we can start building our own lightweight webservers where the abstractions are in the perfect size to give us full control, without getting too complicated. I foresee a promising future for the OWIN initiative and the Kayak project.

Download the source

You can download the source of this example here.

Saturday, January 22, 2011

Book review: The Art of Non-Conformity

The book The Art of Non-Conformity: Set Your Own Rules, Live the Life You Want, and Change the World was written by Chris Guillebeau.

I learned about this book through Chris' blog. He hosts a very popular blog where he writes on lifehacking, entrepreneurship and his goal to travel to each country in the world.

In this book Chris tries to show the reader that you don't have the live your life the way other people expect you to. As long as you are open to new ideas, are dissatisfied with the status quo and are willing to work hard, you should be able to live the life of your dreams.

The first part of this book was an eye-opener for me. Once you find something that you really enjoy doing, your passion, make a commitment and be dedicated to use it to make a positive change. For yourself and for the world. Don't be afraid to be somehow different, a lot of great things have been accomplished outside the status quo. If living the life you want, takes it for you to be unconventional and nonconformist, overcome your fear, and pursue it.

In the second and last part of the book, Chris lost most of my interest. In the second part he shares his personal experience with education, building an army of followers and financing a noncomformist lifestyle. The last part of this book is on building a legacy.

Throughout the book Chris shares his personal stories and aneckdotes. There are also dozens of stories about other people changing their lifes for the better. I especially enjoyed the latter. In his personal stories some of his achievements are repeated throughout the book, which sometimes gives the impression he wrote the book to brag and to promote the AONC brand. Another letdown of this book is that some of the advice isn't useful for most of us. Frequent flyer miles anyone?

I enjoyed the first part of the book a lot. Too bad the other parts mostly failed in keeping me interested.

My rating: 3/5.

Saturday, January 15, 2011

Book review: Got Fight?

I rarely review books with non-technical content here, but I just felt like I had to with this one.

The book Got Fight? was written by Forrest Griffin, assisted by Erich Krauss.

Forrest Griffin is one of the toughest light-heavyweight mixed martial artists competing in the UFC. If you are unfamiliar with MMA and UFC, I encourage you to watch one of the Forrest Griffin tribute videos on Youtube.


This book touches several subjects. Forrest talks about the path he followed to become a professional fighter and what made him who he is today. Forrest also shares a bunch of advice on fighting and non-fighting topics. The last part of the book contains a series of how-to MMA techniques. All these topics are talked together in the form of hilarious, and sometimes offending (to some of you), ramblings. After all, the main goal to read this book shouldn't be to learn, but to be entertained, and maybe learn something along the way!

Below you can find some quotes taken from the book, which will probably tell you a lot more than my small summary above.

Forrest on..

.. sphincter control
Back in the day, when I first met a chick, there was no way I would let one rip. I would wait until at least the second or third date before I introduced her to my Love Potion 109.

.. advice for the fat and tremendously out-of-shape fighter
Steroids, steroids, steroids. This magic elixir can replace all forms of training and will add to your intimidating appearance.

.. cheating
When asked about the tactic after the fight, Tito said, 'If you ain't cheating, you ain't trying'. I would have to agree with him. I would rather be known as a cheater than a loser. Seriously, I have this deep hatred of losing.

.. fear
A black eye will dissapear and a broken nose can be mended. Fear is a good thing because it keeps you alive, but it becomes so great that it hinders you from doing what you want, you need to confront it head-on.

.. eating challenges
I kept mumbling over and over, 'Oh God, I made a mistake', and vociferously promised sweet baby Jesus I would never accept an eating challenge again.

.. being humble
Although it can be depressing to admit to yourself that you will never be the best, it is liberating at the same time. Instead of trying to be better than everyone else, which is existentially arrogant, you can focus on being the best that you can be.

My rating: 4/5. This is probably the funniest book I have ever read.

Photo credit: ESPN

Wednesday, January 12, 2011

HTML5: The WebSockets prototype with Silverlight, HTML Bridges and JavaScript

Last weekend, I blogged on installing the WebSockets prototype and rebuilding the WebSockets chat server. In this post I will try to decompose the client-side chat sample to get a better feel of what's going on in the browser.

If you have installed the WebSockets prototype, you should be able to browse to http://localhost/chat/wsdemo.html and stroll through the internals with me.


Dependencies

The chat sample has four script dependencies:
  • jquery-1.4.2.min.js
  • json2.js
  • jquery.slws.js
  • h5utils.js

Because there is no sense in having a look inside a minified version of jQuery, I'll only look at the three others: json2.js, jquery.slws.js and h5utils.js.

Json2.js

This script creates a global JSON object, if it does not already exist, containing two methods: stringify and parse.

The stringify() method turns a JavaScript value into a JSON text and, oh suprise, the parse() method parses a JSON text to a JavaScript value.

jQuery.slws.js

This script is where the biggest part of the WebSockets prototype magic happens. This script dynamically loads a Silverlight component into your page. This Silverlight component exposes a bunch of methods through an HTML Bridge which can be used to talk to the WebSockets server.

jQuery(function ($) {
    if (!$.slws) $.slws = {};
    else if (typeof ($.slws) != "object") {
        throw new Error("Cannot create jQuery.slws namespace: it already exists and is not an object.");
    }
 
    $(document).ready(function () {
        var script = document.createElement("script");
        document.body.appendChild(script);
        script.src = 'js/Silverlight.js';
        var slhost = document.createElement("div");
        document.body.insertBefore(slhost, document.body.firstChild);     
        slhost.innerHTML =
        '<div align=center>' +
        '<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="600" height="70">' +
            '<param name="source" value="ClientBin/Microsoft.ServiceModel.Websockets.xap"/>' +
            '<param name="onError" value="onSilverlightError" />' +
            '<param name="background" value="white" />' +
            '<param name="minRuntimeVersion" value="4.0.50401.0" />' +
            '<param name="autoUpgrade" value="true" />' +
            '<param name="onLoad" value="pluginLoaded" />' +
            '<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50401.0" style="text-decoration:none">' +
                 '<img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>' +
            '</a>' +
        '</object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div>';
    });
 
    $.slws._callbacks = [];
 
    $.slws.ready = function (callback) {
        if (callback) {
            if ($.slws._loaded) {
                callback();
            }
            else {
                $.slws._callbacks.push(callback);
            }
        }
    }
});

When the Silverlight component has finished loading, a global WebSocketDraft object is created wrapping all the functions that are exposed through the HTML Bridge of the Silverlight component.

function pluginLoaded(sender, args) {
    var slCtl = sender.getHost();
 
    window.WebSocketDraft = function (url) {
        this.slws = slCtl.Content.services.createObject("websocket");
        this.slws.Url = url;
        this.readyState = this.slws.ReadyState;
        var thisWs = this;
        this.slws.OnOpen = function (sender, args) {
            thisWs.readyState = thisWs.slws.ReadyState;
            if (thisWs.onopen) thisWs.onopen();
        };
        this.slws.OnMessage = function (sender, args) {
            if (String(args.Message).charAt(0) == '"' && thisWs.onmessage)
                thisWs.onmessage({ data: String(args.Message) });
        };
        this.slws.OnClose = function (sender, args) {
            thisWs.readyState = thisWs.slws.ReadyState;
            if (thisWs.onclose) thisWs.onclose();
        };
        this.slws.Open();
    };
 
    window.WebSocketDraft.prototype.send = function (message) {
        if (message.charAt(0) != '"')
            message = '"' + message + '"';
        this.slws.Send(message);
    };
 
    window.WebSocketDraft.prototype.close = function() {
        this.slws.Close();
    };
 
    $.slws._loaded = true;
    for (c in $.slws._callbacks) {
        $.slws._callbacks[c]();
    }
}

H5utils

This script forces IE to acknowledge all new HTML5 elements. More on this script can be found here.

Using the WebSockets

Now we have peeked at the script dependencies, we can have a look at the actual usage of the WebSockets API.

Opening a WebSocket

Opening a connection to a WebSocket is very straightforward. Simply create a new WebSocketDraft instance and pass in the endpoint to your WebSockets server.

conn = new WebSocketDraft('ws://' + window.location.hostname + ':4502/chat');

Handling events

Events that are handled in this sample are onopen, onmessage and onclose.

conn.onopen = function () {
    state.className = 'success';
    state.innerHTML = 'Socket open';
};
 
conn.onmessage = function (event) {
    var message = JSON.parse(event.data);
    if (typeof message == 'string') {
        log.innerHTML = '<li class="them">' + 
                        message.replace(/[<>&]/g, function (m) { return entities[m]; }) + 
                        '</li>' + log.innerHTML;
    } else {
        connected.innerHTML = message;
    }
};
 
conn.onclose = function (event) {
    state.className = 'fail';
    state.innerHTML = 'Socket closed';
};

Sending a message

You can send a message using the send() method. Pass in a JSON text.

if (conn.readyState === 1) {
    conn.send(JSON.stringify(chat.value));    
}

Conclusions

The Silverlight solution is a creative hack which allows us to play client-side with the WebSockets prototype until it is natively implemented by IE.

I am satisfied with the WebSocket API specifications, very simple to use. What are your thoughts on the API?

Sunday, January 9, 2011

HTML5: Rebuilding the WebSockets Server prototype

Yesterday I blogged on installing the Microsoft WebSockets prototype with the Chat sample. The Chat sample needs a ChatService to broadcast the messages to all active sessions. The source code of this ChatService is not included in the package, that's why I decompiled the executable using Reflector and rebuilt it.

In this post you can find how to rebuild the Chat Websockets Server.

Class diagram

Once we are finished, our class diagram should look like this.


The server

The server will be hosted in a .NET 4.0 console application.

Dependencies

The server has a few dependencies which are not in the .NET 4.0 Framework:
  • Microsoft.Runtime.Serialization.Json.dll
  • Microsoft.ServiceModel.WebSockets.dll
  • Microsoft.ServiceModel.Tcp.dll

You can find these assemblies in the %ProgramFiles%\Microsoft SDKs\WCF WebSockets\10.12.16\bin folder. Make sure you have installed the Microsoft WebSockets prototype.

The service

The Service class needs to inherit from the abstract WebSocketsService class.

class Service : WebSocketsService 

The abstract WebSocketsService class has following properties and methods.

public abstract class WebSocketsService : IWebSockets, IDisposable {
    protected WebSocketsService();
 
    protected WebHeaderCollection HttpRequestHeaders { get; }
    protected Uri HttpRequestUri { get; }
 
    protected void Close();
    public void Dispose();
    protected virtual void Dispose(bool disposing);
    protected virtual void OnClose(object sender, EventArgs e);
    protected virtual void OnError(object sender, EventArgs e);
    public virtual void OnMessage(JsonValue jsonValue);
    public virtual void OnOpen();
    public void Send(JsonValue jsonValue);
}

The Service class needs to be decorated with a ServiceBehavior attribute. The InstanceContextMode property defines that a new instance of the service needs to be created per session. The ConcurrencyMode defines that the service instances are multithreaded. No synchronization guarantees are made, so synchronization should be handled manually.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, 
                ConcurrencyMode = ConcurrencyMode.Multiple)]

This class needs two static private fields:
  • static int m_globalId: This field holds a global id, which can be used to create a unique id for each new service instance.
  • static Sessions m_sessions: This field contains an instance of the Sessions object, which is used to manage all active service instances.

private static int m_globalId;
private static Sessions m_sessions = new Sessions();

Next to the static private fields, this class also needs one private instance field:
  • int m_id: This field holds an id used as a hash to identify the service instance.
private int m_id = Interlocked.Increment(ref m_globalId);

In the constructor we add the new service instance to the collection of already existing active service instances.

public Service() {
    if (!m_sessions.TryAdd(this)) {
        throw new InvalidOperationException("Can't add session.");
    }
}

The GetHashCode() method returns the unique id that is used to identify the service instance.

public override int GetHashCode() {
    return this.m_id;
}

When a service is closed, we remove the service from the collection of active service instances.

protected override void OnClose(object sender, EventArgs e) {            
    m_sessions.Remove(this);           
}

When the service receives a message, we call the RelayMessage() method on the Sessions instance.
public override void OnMessage(JsonValue jsonValue) {            
    m_sessions.RelayMessage(jsonValue);
}

ServiceCollection

This class is used to store a collection of services.

public class ServiceCollection<TService> : KeyedCollection<int, TService> where TService : class {
    protected override int GetKeyForItem(TService item) {
        return item.GetHashCode();
    }
}  

Sessions

This class is used to manage active service instances.

The internal Sessions class has two private instance fields:
  • ServiceCollection m_innerCache: This fields holds a collection of service instances.
  • ReaderWriterLockSlim m_thisLock: This lock is used throughout this class to thread-safely manage access to resources.
private ServiceCollection<Service> m_innerCache = new ServiceCollection<Service>();
private ReaderWriterLockSlim m_thisLock = new ReaderWriterLockSlim();

This class implements IDisposable. In the Dispose() method the ReaderWriterLockSlim is disposed.

public void Dispose() {
    this.m_thisLock.Dispose();
}

The TryAdd() method takes a service instance and tries to add the instance to the private collection of service instances.

public bool TryAdd(Service entry) {
    bool flag;
    this.m_thisLock.EnterUpgradeableReadLock();
    try {
        if (this.m_innerCache.Contains(entry)) {
            flag = false;
        } else {
            this.m_thisLock.EnterWriteLock();
            try {
                this.m_innerCache.Add(entry);
                flag = true;
            } finally {
                this.m_thisLock.ExitWriteLock();
            }
        }
    } finally {
        this.m_thisLock.ExitUpgradeableReadLock();
    }
    return flag;
}

The RelayMessage() method takes a JsonValue argument and makes all the services send it.

public void RelayMessage(JsonValue jsonValue) {
    List<Service> list = null;
    this.m_thisLock.EnterReadLock();
    try {
        foreach (Service service in this.m_innerCache) {
            try {
                service.Send(jsonValue);
                continue;
            } catch {
                if (list == null) {
                    list = new List<Service>();
                }
                list.Add(service);
                continue;
            }
        }
    } finally {
        this.m_thisLock.ExitReadLock();
    }
    if (list != null) {
        this.m_thisLock.EnterWriteLock();
        try {
            foreach (Service service2 in list) {
                this.m_innerCache.Remove(service2);
            }
        } finally {
            this.m_thisLock.ExitWriteLock();
        }
    }
}

The Remove() method takes a service instance and removes it asynchronously from the private collection of service instances.

public void Remove(Service entry) {
    ThreadPool.QueueUserWorkItem(new WaitCallback(this.RemoveInternal), entry);
}
 
private void RemoveInternal(object state) {
    var item = state as Service;
    if (item != null) {
        this.m_thisLock.EnterWriteLock();
        try {
            this.m_innerCache.Remove(item);
        } finally {
            this.m_thisLock.ExitWriteLock();
        }
    }
}

Almost there

To finish the WebSockets Server we need to set up the WebSocketsHost in Program.cs.

Create a new instance of the WebSocketsHost<Service> class passing in a baseaddress. Add an endpoint and finally open the host.

static void Main(string[] args) {
    var host = new WebSocketsHost<Service>(new Uri[] { new Uri(string.Format("ws://{0}:4502/chat", Environment.MachineName)) });
    host.AddWebSocketsEndpoint();
    host.Open();
 
    Console.WriteLine("Websocket server listening on " + host.Description.Endpoints[0].Address.Uri.AbsoluteUri);
    Console.WriteLine();
  
    using (ManualResetEvent mre = new ManualResetEvent(false)) {
        mre.WaitOne();
    }
    host.Close();
}

That should be it. You can now run your own implementation of the Chat WebSockets Server and use Visual Studio to step through the flow of the server.

Download the source

You can download the source here.

Saturday, January 8, 2011

HTML5: Installing the Microsoft WebSockets prototype

In December Microsoft launched the HTML5 Labs for experimental HTML5 technologies still under development. With the launch, they also released a WebSockets prototype.

In this post I will lead you through the process of installing the WebSockets prototype on your machine. By the end of this tutorial you should have a working chat web application sample.

Download

First you need to download and run the WebSockets prototype installer.

This package installs the binaries and samples in the %ProgramFiles%\Microsoft SDKs\WCF WebSockets\10.12.16 folder.

Enable IIS

Make sure IIS is enabled on your machine. You can verify this by using the Windows feature configuration tool.


Configure the Windows Firewall

You need to allow incoming TCP traffic on port 4502 in the Windows Firewall.

Open the Windows Firewall and add a new inbound rule.


To add a new inbound rule you need to follow the five steps of the wizard.

First you need to define the type of rule you want to create: Port.


The protocol you need to use is TCP and the specific port you want to open is 4502.


When connections are attempted through the port we specified, they should be allowed.


This rule should always be applied (for me).


Finalize the wizard by specifying a name for the rule.


Deploy the client access policy

Copy the %ProgramFiles%\Microsoft SDKs\WCF WebSockets\10.12.16\bin\clientaccesspolicy.xml file to the %SystemDrive%\inetpub\wwwroot folder.

Make sure the file is accessible by navigating to http://localhost/clientaccesspolicy.xml.

Start the ChatService

Start %ProgramFiles%\Microsoft SDKs\WCF WebSockets\10.12.16\bin\ChatService.exe.

Because the ChatService assembly is delay signed, and not fully signed, it will throw an unhandled System.Security.SecurityException: Strong name validation failed.


To turn off strong name signing for this assembly you can use sn.exe. Execute the following command:
sn -Vr "%ProgramFiles%\Microsoft SDKs\WCF WebSockets\10.12.16\bin\ChatService.exe"

Pay attention:
  • The command arguments are case sensitive. It's -Vr.
  • If you are running a 64 bit OS you have to use the 64 bit version of the tool. I used the Visual Studio x64 Win64 Command Prompt (2010).
  • If you are using the Visual Studio Command Prompt you need to run it as an administrator.


Once these problems are fixed, you can finally start the ChatService.


Deploy the Chat web application

Create a chat virtual directory in IIS mapped to the %ProgramFiles%\Microsoft SDKs\WCF WebSockets\10.12.16\web\chat directory.


Test the web application

If you followed all these steps, you should be able to navigate to http://localhost/chat/wsdemo.html and see the results of your efforts. Victory!


Problems?

If you are still facing some problems, feel free to let me know in the comments.

Thursday, January 6, 2011

Book review: Pro HTML5 Programming

The Apress book Pro HTML5 Programming was written by three authors: Peter Lubbers, Brian Albers and Frank Salim. In this book the authors introduce the reader to the most popular and useful features of HTML5.

The book contains 11 concise chapters: An overview of HTML5, the Canvas API, audio and video, the Geolocation API, the Communication API, the WebSocket API, Forms, the Web Workers API, the Web Storage API, Offline Web Applications and the future of HTML5.

This book succeeds in breaking the myth that HTML5 will not be applicable until 2022. The authors demonstrate this by accompanying all theory with a ton of examples based on realistic scenarios. The examples are not to complex, and most of the time, cut in well sized pieces, which makes them easy to digest. The authors show you how to detect whether a certain feature is supported by the hosting browser. They do not provide information on fallback mechanismes though, which I think is a good thing, because it would only break the tight scoping of the book.

Developers who are new to HTML and JavaScript should pick up other books first, some experience with client-side webdevelopement is adviced.

I think this book is a good read and can serve as an excellent introduction to HTML5. You should get it before it's obsolete ;).

My rating: 4/5. What is yours?

Some of my articles on HTML5:

Saturday, January 1, 2011

Happy New Year

Happy New Year!

I would like to thank you for being so awesome in 2010 and I hope we will be able to make 2011 an even better year!


Photo credit: My girlfriend

PS: This post was scheduled. If everything went ok, I should be tipsy by now and celebrating the New Year with my closest friends.