Simple message dispatcher using event delegates


This post demonstrates a simple asynchronous message dispatcher that decouples message producers from consumers. It leverages event delegates.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;

namespace NetDispatcher
{
    public delegate void MessageHandler<U>(U message);

    public class MessageDispatcher<T, U>
    {
        static ConcurrentDictionary<T, System.Delegate> handlers =
            new ConcurrentDictionary<T, System.Delegate>();

        public static void Dispatch(T type, U message)
        {
            System.Delegate eventHandlers;
            handlers.TryGetValue(type, out eventHandlers);
            if (eventHandlers != null)
            {
                try
                {
                    List<Task> taskList = new List<Task>();
                    foreach (Delegate eventHandler in eventHandlers.GetInvocationList())
                    {
                        taskList.Add(Task.Run(delegate
                        {
                            ((MessageHandler<U>)eventHandler)(message);
                        }));
                    }
                    Task.WaitAll(taskList.ToArray());
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                    Debug.WriteLine(ex.StackTrace);
                }
            }
        }

        public static void RegisterHandler(T type, MessageHandler<U> handler)
        {
            Delegate d;
            handlers.TryGetValue(type, out d);

            if (d == null)
            {
                handlers[type] = null;
            }

            handlers[type] = (MessageHandler<U>)handlers[type] + handler;
        }

        public static void DeregisterHandler(T type, MessageHandler<U> handler)
        {
            Delegate d;
            handlers.TryGetValue(type, out d);

            if (d != null)
            {
                handlers[type] = (MessageHandler<U>)handlers[type] - handler;
            }
        }
    }
}

This is how the message dispatcher may be used

        // Register a handler for "foo" that accepts messages of type string
        MessageDispatcher<string, string>.RegisterHandler("foo", delegate (string message)
        {
            // ...
        });

        // Dispatch a message
        MessageDispatcher<string, string>.Dispatch("foo", "bar");

The use of static methods with generic types allows it to be used for multiple message payload types.

See code and unit tests at GitHub.

JSON-RPC


If your HTML5 application requires RPC (remote procedure call) semantics, JSON-RPC is an easy specification to implement. The code below allows sending requests and receiving responses, and leverages JQuery’s custom events to raise notifications (requests sent by server without an id).

        var nextId = 1;
        var messages = new Array();

        function Request(method, data) {
            this.method = method;
            // params is a C# keyword hence it is called data
            if (data)
                this.data = data;
        }

        Request.prototype.execute = function (callback) {
            if (callback) {
                this.id = nextId++;
                messages[this.id] = callback;
            }
            // Implement send so that the request gets sent to a server
            send(JSON.stringify(this));
        }

        // Whoever receives a stringified message from server must call dispatchMessage
        function dispatchMessage(message) {
            var o = JSON.parse(message);

            if (Array.isArray(o)) {
                dispatchBatch(o);
            } else {
                dispatch(o);
            }
        }

        function dispatchBatch(array) {
            array.forEach(function (message) {
                dispatch(message);
            })
        }

        function dispatch(message) {
            if (message.method) {
                // request
                $(document).trigger(message.method, message);
            } else {
                // response
                var callback = messages[message.id];
                if (callback) {
                    messages = messages.filter(function (elem) {
                        return elem.id == message.id; // remove
                    });
                    callback(message);
                } else {
                    console.log("Unknown response " + JSON.stringify(message));
                }
            }
        }

The following snippet shows how to handle a notification called foo, sent by the server

        $(document).on("foo", function (e, request) {
            // do something with request.data
        });

The following code demonstrates how to send a new request for a method called bar, and handle the corresponding response

            // data is some object that will be stringified
            var request = new Request("bar", data);
            request.execute(function (response) {
                // do something with response.error or response.result
            })

I’ll leave the server-side code to handle JSON-RPC as an exercise to the reader, or for a post in the future.

Using hints inside text fields instead of labels


The following code example demonstrates replacing labels with hints that appear as temporary values within text fields; akin to placeholder attribute in HTML5.

A custom attribute called data-hint-value contains the hint value to which a text field gets initialized. That value represents what typically would be the value of a label associated with the text field. It is cleared when the text field receives focus, and filled with hint value if text field is empty on blur.

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title></title>
    <link rel="shortcut icon" href="favicon.ico">
    <script type="text/javascript" src="js/jquery-2.1.4.min.js"></script>
</head>
<body>
    <input id="name" type="text" data-hint-value="your name" />
    <script type="text/javascript">

        function setAllTextToHint() {
            $(":text").each(function (index) {
                hint = $(this).attr("data-hint-value");
                if (hint) $(this).val(hint);
            });
        }

        function isTextValueValid(id) {
            var ret = false;
            $(":text").each(function (index) {
                thisId = $(this).attr("id");
                if (thisId == id) {
                    hint = $(this).attr("data-hint-value");
                    value = $(this).val();
                    if (value == hint || value == "") {
                        alert("Please specify " + hint);
                        $(this).val(hint);
                        $(this).focus();
                        return;
                    } else {
                        ret = true;
                        return;
                    }
                }
            });
            return ret;
        }

        $(":text").focus(function () {
            hint = $(this).attr("data-hint-value");
            if ($(this).val() == hint)
                $(this).val("");
        });

        $(":text").blur(function () {
            hint = $(this).attr("data-hint-value");
            if ($(this).val() == "") {
                $(this).val(hint);
            }
        });
    </script>

setAllTextToHint is a helper function that sets all text fields to their hint values. isTextValueValid may be used to check whether a text field contains some value, and alerts the user when it does not. Tweak these as you see fit.