Archive

Archive for March, 2011

JSON and the DLR

March 1, 2011 1 comment

JavaScript is a dynamic language, and with the DLR, C# can be as well. There have been more than a few times that I’ve wanted to pass JavaScript objects over to my C# code, but my object models didn’t match up, so I couldn’t easily deserialize them for server side processing. With the DLR, this is no longer a problem. We don’t need to modify a C# class to match the JavaScript object model. Instead, use the JavaScriptSerializer that ships with .NET 3.5 to get a Dictionary, then copy those elements into a DynamicObject.

First, our DynamicObject:

public class JsonDynamicObject : DynamicObject
{
	private Dictionary<string,object> properties = new Dictionary<string, object>();
	
	public override bool TryGetMember (GetMemberBinder binder, out object result)
	{
		object value;
		if(properties.TryGetValue(binder.Name, out value)) {
			result = value;
			return true;
		}
		else {
			result = null;
			return false;
		}
	}
	
	public override bool TrySetMember (SetMemberBinder binder, object value)
	{
		if(properties.ContainsKey(binder.Name)) {
			properties[binder.Name] = value;
		}
		else {
			properties.Add(binder.Name, value);
		}
		return true;
	}
	
	public override IEnumerable<string> GetDynamicMemberNames ()
	{
		return properties.Keys;
	}
}

Next, use the JavaScriptSerializer to parse a string of JSON into a Dictionary<string,object>, and build an instance of our JsonDynamicObject from that:

public static JsonDynamicObject Parse(string json) {
	var s = new System.Web.Script.Serialization.JavaScriptSerializer();
	return buildDynamicObject((Dictionary<string,object>)s.DeserializeObject(json));
}

private static JsonDynamicObject buildDynamicObject(Dictionary<string,object> props) {
	if(props != null) {
		JsonDynamicObject dynObj = new JsonDynamicObject();
		foreach(var kvp in props) {
			Dictionary<string, object> subProps = kvp.Value as Dictionary<string, object>;
			if(subProps != null) {
				dynObj.properties.Add(kvp.Key, buildDynamicObject(subProps));
			}
			else {
				dynObj.properties.Add(kvp.Key, kvp.Value);
			}
		}
		return dynObj;
	}
	else {
		return null;
	}

In the end, we have an object that is fully compatible with the DLR and can even be passed on to other dynamic languages, such as IronPython running in the server:

dynamic d = JsonDynamicObject.Parse("{'UserID':23, 'User':{'Name':'Billy', 'Age':28}}");
Console.WriteLine(d.Blah);
Console.WriteLine(d.Test.What);
var scriptEngine = Python.CreateEngine();
var scope = scriptEngine.CreateScope();
scope.SetVariable("jsObj", d);
var source = scriptEngine.CreateScriptSourceFromString("print jsObj.User.Age * 10");
source.Execute(scope);

An object defined in JavaScript passed to C# then on to IronPython all in just a few lines of code!

Categories: DLR, IronPython Tags: , ,