To make it easier for me to unit test a OData JavaScript library I am working, I created a small HTTP handler that will reply back to a AJAX request with the headers, HTTP verb and query string it received. My initial thought was to do this through a WCF service, and while this is certainly possible, I found it much easier just to create a simple HTTP handler.

The code for the AjaxPingHandler.cs handler:

using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web;

namespace ODataJS.services
{
    public class AjaxPingHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            var request = context.Request;
            var response = context.Response;

            // serialize PingReply object
            string jsonText = string.Empty;
            using (var ms = new MemoryStream())
            {
                var jsonSerializer = new DataContractJsonSerializer(typeof(PingReply));
                jsonSerializer.WriteObject(ms, new PingReply(request));
                jsonText = Encoding.Default.GetString(ms.ToArray());
            }

            // set content type to json
            response.ContentType = request.AcceptTypes.Contains("application/json") ? "application/json" : "text/javascript";

            // wrap in d object to avoid script injection
            jsonText = "{\"d\":{" + jsonText.Substring(1, jsonText.Length - 1) + "}";

            // output content
            response.Write(jsonText);
        }

        public bool IsReusable
        {
            // To enable pooling, return true here.
            // This keeps the handler in memory.
            get { return false; }
        }
    }
}

As you can see, it uses the native .net DataContractJsonSerializer to serialize a custom class called PingReply. The ContentType return header is determined by the AcceptTypes request header. If the AcceptTypes array contains “application/json” the ContentType header is set to the same, otherwise we set the ContentType header to “text/javascript”.

Just for good measure, the result data is wrapped in a dummy object { "d" : . }, just like .net’s JSON enabled services does it. It is not because I am terrible worried about script injection attacks when doing unit tests, but it makes the service behave more like other .net JSON services, which makes things consistent.

The PingReply.cs class:

using System.Linq;
using System.Runtime.Serialization;
using System.Web;

namespace ODataJS.services
{
    [DataContract]
    public class PingReply
    {
        [DataMember]
        public string HTTPVerb { get; set; }

        [DataMember]
        public JsonDictionary Headers { get; private set; }

        [DataMember]
        public JsonDictionary QueryString { get; private set; }

        public PingReply(HttpRequest request)
        {
            Headers = new JsonDictionary();
            QueryString = new JsonDictionary();
            foreach (var key in request.Headers.AllKeys.Where(x => x != null))
                Headers.Add(key, request.Headers[key]);

            foreach (var key in request.QueryString.AllKeys.Where(x => x != null))
                QueryString.Add(key, request.QueryString[key]);

            HTTPVerb = request.HttpMethod;
        }
    }
}

The only thing interesting about the PingReply class is that it uses the JsonDictionary class to return the headers and query string instead of the native .net Dictionary collection class. I decided to use the JsonDictionary class because it serializes to a proper JavaScript object, and not a array of one-element objects like the .net Dictionary. Carlos Figueira first published the JsonDictionary class over at the msdn forums.

The JsonDictionary.cs class:

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace ODataJS.services
{
    [Serializable]
    public class JsonDictionary : ISerializable
    {
        readonly Dictionary<string, object> _dict = new Dictionary<string, object>();
        public JsonDictionary() { }
        protected JsonDictionary(SerializationInfo info, StreamingContext context)
        {
            foreach (var entry in info)
            {
                _dict.Add(entry.Name, entry.Value);
            }
        }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            foreach (string key in _dict.Keys)
            {
                info.AddValue(key, _dict[key], _dict[key] == null ? typeof(object) : _dict[key].GetType());
            }
        }

        public void Add(string key, object value)
        {
            _dict.Add(key, value);
        }
    }
}

To make it all work, you simply need to add the following to your web.config file:

<configuration>
  <system.web>
    <httpHandlers>
      <add verb="*" path="AjaxPing.ashx"
        type="ODataJS.services.AjaxPingHandler"/>
    </httpHandlers>
  </system.web>
  <system.webServer>
    <handlers>
      <add verb="*" path="AjaxPing.ashx"
        name="AjaxUnittestService"
        type="ODataJS.services.AjaxPingHandler"/>
    </handlers>
  </system.webServer>
</configuration>

Then it is just a matter of querying AjaxPing.ashx and unit test against the reply from the service.

I hope this helps others who also want to produce better JavaScript code.