Archive

Posts Tagged ‘dlr’

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: , ,

WCF Serialization of DLR dynamic types

January 1, 2011 24 comments

I’m a huge fan of the DLR, as it provides terrific interoperability between C# and dynamic languages like IronPython. To create a C# class that works with the DLR, the easiest thing to do is derive from DynamicObject. One limitation arises when trying to use a dynamic type in a WCF service. Trying to use a DynamicObject-derived type will result in a runtime exception when trying to serialize with WCF’s DataContractSerializer. This class (which fails serialization) was my first attempt:

[DataContract]
public class SerializableDynamicObject : DynamicObject
{
    [DataMember]
    private Dictionary<string, object> props = new Dictionary<string, object>();

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        return props.TryGetValue(binder.Name, out result);
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (props.ContainsKey(binder.Name))
            props[binder.Name] = value;
        else
            props.Add(binder.Name, value);
        return true;
    }
}

Trying to serialize an instance of SerializableDynamicObject results in the following exception:

Unhandled Exception: System.Runtime.Serialization.InvalidDataContractException:
Type ‘WCFDynamicObject.SerializableDynamicObject’ cannot inherit from a type that is not marked with DataContractAttribute or SerializableAttribute. Consider marking the base type ‘System.Dynamic.DynamicObject’ with DataContractAttribute or SerializableAttribute, or removing them from the derived type.

We can’t add attributes to DynamicObject, so we have to do this the *slightly* harder way by implementing IDynamicMetaObjectProvider rather than deriving from DynamicObject. The tricky part of this is creating the DynamicMetaObject which handles the evaluation of binding expressions. Luckily the DLR documentation on CodePlex has a great walkthrough for this.

The SerializableDynamicObject contains a dictionary of dynamic members and will serialize properly using WCF’s DataContractSerializer. Use it in place of DynamicObject when you want to be able to pass your dynamic types across WCF service boundaries.

[DataContract]
public class SerializableDynamicObject : IDynamicMetaObjectProvider
{
	[DataMember]
	private IDictionary<string,object> dynamicProperties = new Dictionary<string,object>();
	
	#region IDynamicMetaObjectProvider implementation
	public DynamicMetaObject GetMetaObject (Expression expression)
	{
		return new SerializableDynamicMetaObject(expression, 
			BindingRestrictions.GetInstanceRestriction(expression, this), this);
	}
	#endregion
	
	#region Helper methods for dynamic meta object support
	internal object setValue(string name, object value) 
	{
		dynamicProperties.Add(name, value);
		return value;
	}
	
	internal object getValue(string name) 
	{
		object value;
		if(!dynamicProperties.TryGetValue(name, out value)) {
			value = null;
		}
		return value;
	}
	
	internal IEnumerable<string> getDynamicMemberNames() 
	{
		return dynamicProperties.Keys;
	}
	#endregion
}


public class SerializableDynamicMetaObject : DynamicMetaObject
{
	Type objType;
	
	public SerializableDynamicMetaObject(Expression expression, BindingRestrictions restrictions, object value) 
		: base(expression, restrictions, value) 
	{
		objType = value.GetType();
	}
	
	public override DynamicMetaObject BindGetMember (GetMemberBinder binder)
	{
		var self = this.Expression;
		var dynObj = (SerializableDynamicObject)this.Value;
		var keyExpr = Expression.Constant(binder.Name);
		var getMethod = objType.GetMethod("getValue", BindingFlags.NonPublic | BindingFlags.Instance);
		var target = Expression.Call(Expression.Convert(self, objType),
		                             getMethod,
		                             keyExpr);
		return new DynamicMetaObject(target,
			BindingRestrictions.GetTypeRestriction(self, objType));
	}
	
	public override DynamicMetaObject BindSetMember (SetMemberBinder binder, DynamicMetaObject value)
	{
		var self = this.Expression;
		var keyExpr = Expression.Constant(binder.Name); 
		var valueExpr = Expression.Convert(value.Expression, typeof(object));
		var setMethod = objType.GetMethod("setValue", BindingFlags.NonPublic | BindingFlags.Instance);
		var target = Expression.Call(Expression.Convert(self, objType),
		setMethod, 
		keyExpr, 
		valueExpr);
		return new DynamicMetaObject(target,
			BindingRestrictions.GetTypeRestriction(self, objType));
	}
	
	public override IEnumerable<string> GetDynamicMemberNames ()
	{
		var dynObj = (SerializableDynamicObject)this.Value;
		return dynObj.getDynamicMemberNames();
	}
}

One warning, dynamic members can be anything, meaning at runtime someone could assign a method to one of these fields. If this is possible in your application, you’ll need to ensure any methods assigned to the dynamic type are not serialized. I’m leaving this as an exercise for the reader.

Categories: DLR, WCF Tags: , ,

DLR + IBatis – ORM mappings for dynamic objects

March 16, 2010 Leave a comment

I’m a big fan of using an ORM to hide the implementation details of the database from the people writing application logic. A lot of ORM’s depend on the structure of your object to determine what SQL they emit. That can be painful sometimes because you have to design your object model and database to fit the ORM. In the case of objects with dynamic members (like those supported by IronPython, IronRuby, and now the DLR in C# 4.0) the structure of your object isn’t necessarily determined at compile time. Instead, you have a backing collection like a Dictionary for your dynamic types that will get populated at runtime with any dynamic members. That dictionary can be full of more dynamic objects. As you can imagine, trying to persist a dynamic structure like this in a not-so-dynamic relational database can be tricky, but it also gives you some nice advantages. For one thing, you can change your database structure without having to deploy any code changes.

For an example of how to create a backing collection for dynamic types for .NET 4.0, follow the documentation on http://dlr.codeplex.com to derive from DynamicObject or implement IDynamicMetaObjectProvider. For IronPython in .NET 2.0, follow the steps regarding GetBoundMember and SetMemberAfter demonstrated in IronPython in Action for examples of how to do this.

Here’s an example to illustrate. I have a base class that all my entities derive from named DynamicBase. This class has the backing collection for any dynamic members, so if I’m in IronPython or dynamic C#, I can arbitrarily add properties to any class that derives from DynamicBase. In fact, if I didn’t want to derive any classes, I could probably stop with DynamicBase.

IronPython example:

simpleDynamicPerson = DynamicBase()
simpleDynamicPerson.Name = "Bill"
simpleDynamicPerson.Title = "Boss"
simpleDynamicPerson.Height = "6ft"

anotherDynamicPerson = DynamicBase()
anotherDynamicPerson.Name = "Mike"
anotherDynamicPerson.Title = "Assistant"
anotherDynamicPerson.YearsWorking = 4

complexDynamicTeam = DynamicBase()
complexDynamicTeam.Name = "MyTeam"
complexDynamicTeam.Leader = simpleDynamicPerson
complexDynamicTeam.Assistant = anotherDynamicPerson

After running this code, I have a DynamicBase instance, and in its DynamicProperties backing collection it has two entries: “Leader”, which contains the simpleDynamicPerson instance, and “Assistant”, which contains the anotherDynamicPerson instance. The simpleDynamicPerson instance’s DynamicProperties collection has entries for “Name”, “Title” and “Height” that are populated at runtime as well.

There aren’t really any classes to map here. There are just dictionaries of dictionaries that are holding all the data. using the IBatis DataMapper, I could run a statement like this:

Mapper.Instance().Insert("StoreDynamicTeam", complexDynamicTeam)

StoreDynamicTeam needs to be the name of an statement loaded in one of the SqlMap files loaded by SqlMap.config. The ORM mapping is the only thing that needs to know about the structure of the dynamic object, or at least the fields that need to be persisted.

<insert id="StoreDynamicTeam">
BEGIN TRAN
DECLARE @teamID INT
INSERT INTO TEAM (NAME) VALUES (#DynamicProperties.Name#)
SET @teamID = SCOPE_IDENTITY()
INSERT INTO PEOPLE (NAME, TITLE, HEIGHT, YEARSWORKING, TEAM_ID) 
VALUES (#Leader.DynamicProperties.Name#, 
#Leader.DynamicProperties.Title#, 
#Leader.DynamicProperties.Height#, 
#Leader.DynamicProperties.YearsWorking#,
@teamID)
INSERT INTO PEOPLE (NAME, TITLE, HEIGHT, YEARSWORKING, TEAM_ID) 
VALUES (#Assistant.DynamicProperties.Name#, 
#Assistant.DynamicProperties.Title#, 
#Assistant.DynamicProperties.Height#, 
#Assistant.DynamicProperties.YearsWorking#,
@teamID)
COMMIT
</insert>

Getting that data back out isn’t much more difficult.

dynamicPeople = Mapper.Instance().QueryForList("GetDynamicTeam", teamID)

My statement and the resultMap need to deal with the dynamic parameters:

<select id="GetDynamicTeam" parameterClass="int" resultMap="DynamicTeamResult">
SELECT p.NAME AS PERON_NAME, 
p.TITLE AS TITLE, 
p.HEIGHT AS HEIGHT, 
p.YEARSWORKING AS YEARSWORKING
FROM TEAM t
INNER JOIN PEOPLE p ON p.TEAM_ID = t.TEAM_ID
WHERE t.TEAM_ID = #value#
</select>

<resultMap id="DynamicPersonResult" class="MyClassLib.DynamicBase,MyClassLib">
   <result property="DynamicProperties" resultMapping="DynamicPropertiesResult" />
</resultMap>

<resultMap id="DynamicPropertiesResult" class="System.Collections.Generic.Dictionary`2[[System.String,mscorlib], [System.Object,mscorlib]], mscorlib">
   <result property="Name" column="PERSON_NAME" />
   <result property="Title" column="TITLE" />
   <result property="Height" column="HEIGHT" />
   <result property="YearsWorking" column="YEARSWORKING" />
</resultMap>

When you execute it, dynamicPeople will be a collection of DynamicBase objects with their dynamic properties populated. What’s very cool about these properties being dynamic is that you could change your query in your mapping file to add some new fields from some other table, update the resultMap to use those fields, and they’ll show up on your dynamic object.

Categories: DLR Tags: , , ,