Archive

Archive for January, 2011

Embedding PowerShell 2 in IronPython

January 25, 2011 1 comment

PowerShell 2 makes the process of embedding PowerShell scripts inside other languages quite a bit simpler than in previous versions:

import clr
clr.AddReference("System.Management.Automation")
from System.Management.Automation import PowerShell
with PowerShell.Create() as ps:
   script = ps.AddScript("param([System.String]$pname)\r\nGet-Process -name $pname")
   script.AddParameters({"pname" : "devenv"})
   output = [o.BaseObject for o in script.Invoke()]

# Now you can access the Process object returned from the PS script.
print output[0].VirtualMemorySize64

You should create the PowerShell instance within a “with” block to ensure it is properly disposed after use. To pass parameters into a PS script, you’ll need to make sure the script accepts a few named parameters using the PS param() statement. Then you create a dict() of the name value pairs and add it as the parameters to the script. A Python list comprehension makes quick work of unwrapping the CLR objects from the PS output collection.

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