WebSockets – metro style app

Building the metro app. To our existing solution I’ll add an empty Windows Store Application. As I mentioned earlier the WebSockets support is built in the WinRT so there are no nuget packages to install, we just need to include the Windows.Networking.Sockets namespace.

On my main page I’ll have a stack panel called Container, which sits inside a scroll viewer, and in that container I’ll be adding different custom controls. There is also a text block where we can watch the messages that we send and receive similar to what we did on the HTML5 page.

The programming model for the client is very similar to what we saw on the server and in HTML5. There are 2 important events that we need to handle (MessageReceived and Closed); to open a connection we call ConnectAnync() method and to send and receive messages we use a DataReader and a DataWriter to read and write to and from the input and output streams. I’ll create a simple class that will wrap all this complexity and expose a couple of more convenient methods and events.

using Windows.Networking.Sockets;
using Windows.Storage.Streams;

public class Socket
{
    private MessageWebSocket socket;

    private DataWriter writer;

    public event MessageDelegate OnConnected;

    public event MessageDelegate OnDisconnected;

    public event MessageDelegate OnMessage;

    public event MessageDelegate OnStatus;

    public Socket()
    {
        this.socket = new MessageWebSocket();
        this.socket.Control.MessageType = SocketMessageType.Utf8;

        this.socket.MessageReceived += (sender, args) =>
        {
            var reader = args.GetDataReader();
            var message = reader.ReadString(reader.UnconsumedBufferLength);

            // remove ""
            message = message.Remove(message.Length - 1).Remove(0, 1); 

            Status("<<< " + message);             

            if (OnMessage != null) OnMessage(message);         
        };

        this.socket.Closed += (sender, args) =>
        {
            Status("Disconnected");

            this.socket.Dispose();
            this.socket = null;

            if (OnDisconnected != null) OnDisconnected(null);
        };
    }

    public async void Connect(string url)
    {
        Status("Connecting to " + url + " ...");
        await socket.ConnectAsync(new Uri(url));
        writer = new DataWriter(socket.OutputStream);
        Status("Connected");

        if (OnConnected != null) OnConnected(null);
    }

    public async Task Send(string message)
    {
        Status(">>> " + message);

        writer.WriteString(message);
        await writer.StoreAsync();
    }

    public void Disconnect()
    {
        Status("Disconnecting...");
        socket.Close(1000, "user request");
    }

    void Status(string status)
    {
        if (OnStatus != null) OnStatus(status);
    }
}

The next thing I’ll need is a helper class that will dispatch the messages between the different controls on the main page. All controls will implement a simple IChatControl interface. It contains one method to receive a message and two events to send a message and to send a local message. Also there is a reference property so we know who we are talking to.

public interface IChatControl
{
    string Reference { set; } 

    event MessageDelegate SendMessage;

    event MessageDelegate SendLocalMessage;

    void ReceiveMessage(string message);
}

In my helper class ControlManager I’ll have a collection (dictionary) of controls. There is a single public method that sends a message to the correct control. Each message has a sender, a command and a body. What the method does, it finds the right control to receive the message and sends it to that control. If a control like that does not exist it creates a new one and adds it to the container.

public class ControlsManager
{
    Dictionary<string, UIElement> controls;
    Panel container;

    public event MessageDelegate SendMessage;

    public event MessageDelegate SendLocalMessage;

    public ControlsManager(Panel container)
    {
        this.controls = new Dictionary<string, UIElement>();
        this.container = container;
    }

    public void SendMessageToControl(string sender, string command, string message)
    {
        var control = FindControl(command, sender);
        if (control != null)
            ((IChatControl)control).ReceiveMessage(message);
    }

    private UIElement FindControl(string command, string reference)
    {
        UIElement control = null;
        string key = command + "_" + reference;

        if (controls.ContainsKey(key))
        {
            control = controls[key];
        }
        else
        {
            Type t = GetType(command);
            if (t != null)
            {
                control = (UIElement)Activator.CreateInstance(t);
                ((IChatControl)control).Reference = reference;
                ((IChatControl)control).SendMessage += (message) => 
                    { if (SendMessage != null) SendMessage(message); };
                ((IChatControl)control).SendLocalMessage += (message) => 
                    { if (SendLocalMessage != null) SendLocalMessage(message); };

                controls.Add(key, control);
                container.Children.Add(control);
            }
        }

        return control;
    }

    private Type GetType(string command)
    {
        switch (command)
        {
            case "#CHAT":
                return typeof(ChatControl);
            case "#FRIEND":
                return typeof(FriendsControl);
            case "#TICTACTOE":
                return typeof(TicTacToeControl);
            default:
                return null;
        }
    }
}

The last thing before we get to business is a class that will parse the messages that we receive. Every message has a sender, a command and a body, the sender is marked with @ and the command with # (just like twitter) so a typical message would be “@John #tictactoe 1 1” which means that I’m playing tic tac toe with John and I put an X in the middle square, more about that later on…

Now let’s look at our controls. All of them will implement the IChatControl interface.

First the FriendsControl. In the middle of the control there is a listbox that is databound to a collection of Friends. At the bottom, there is a text box and a button to add a new friend. When the button is pressed we send a message “FOLLOW name”. Also, at the top, there is a text box and a button to set the user’s status, when the button is pressed we send a “STATUS status” message. The type of message the control expects is with a name of a friend and that friend’s status so when a message like that is received we update the friend’s status or add a new friend. That control is initialized a bit different than the other controls. Let’s see how it works…

Now the ChatControl… it is a lot simpler than the FriendsControl. There is a scroll viewer where we put chat “bubbles”. When a message is received all we do is to add a bubble with the text of the message. There is a text box and a Send button where we can compose our own message and when the button is pressed the message is send and another bubble is added. One important thing to notice is that we can have multiple conversations with different people and all the messages get send to the right person and delivered to the right control. Demo…

In the next post we’ll look at the tic tac toe game…

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 )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s