Monday, January 10, 2011

How C# new dynamic type can simplify access to late bound COM object

A couple of years ago I’ve got an interesting task. I had to develop a public web service which utilized internally a third-party COM object. Sounds easy, the concept of COM Interop exists in .NET since the first release, so I didn’t expect any difficulties on my way.

Just to be more specific let’s say we have a very simple VB6 COM object "MyProject.MyClass" having a single method Add, taking two Integer parameters and returning a sum of them:

Public Function Add(first As Integer, second As Integer) As Integer
Add = first + second
End Function


I’ve started a new Visual Studio project, added a reference to the COM object and wrote the following code:

using System;
namespace ComTest
{
class Program
{
static void Main(string[] args)
{
MyProject.MyClass comObject = new MyProject.MyClass();
short sum = comObject.Add(1,2);
Console.Out.WriteLine("Early binding. Sum = " + sum);
Console.ReadLine();
}
}
}


It worked. But after some time I realized that the third-party COM object is updated on nearly monthly basis. And the COM object has been probably developed in VB6 with no version compatibility settings, resulting in constantly changing GUIDs even when the interface signatures haven't changed. As a result my program started to crash showing the following message:

An unhandled exception of type 'System.InvalidCastException' occurred in ComTest.exe

I had two options: either to recompile my web service each time I receive a new COM object or to use late binding. Obviously I went to the last option.
My C# code looked like this:

using System;
using System.Reflection;

namespace ComTest
{
class Program
{
static void Main(string[] args)
{
System.Type objType = System.Type.GetTypeFromProgID("MyProject.MyClass");
object comObject = System.Activator.CreateInstance(objType);

object[] oParms = new Object[] { 1, 2 };
short sum = (short)objType.InvokeMember(
"Add", BindingFlags.InvokeMethod, null, comObject, oParms);
Console.Out.WriteLine(sum);
Console.ReadLine();
}
}
}


It worked, but imaging if you have not just one method in COM object but plenty of them. Building every time a parameter list and calling InvokeMember is not the most pleasant way to spend your time in the office. And there was no other option till Visual C# 2010. Thank to new dynamic type it is possible now to declare an object of type which bypasses static type checking. At compile time, an element that is typed as dynamic is assumed to support any operation. Therefore, we can write the following code now:

using System;
using System.Reflection;

namespace ComTest
{
class Program
{
static void Main(string[] args)
{
System.Type objType = System.Type.GetTypeFromProgID("MyProject.MyClass");
dynamic comObject = System.Activator.CreateInstance(objType);

short sum = comObject.add(1, 2);
Console.Out.WriteLine("Late binding with dynammic type. Sum = " + sum);
Console.ReadLine();
}
}
}


So we are using now the same method signatures as in first example without needs to use a call to InvokeMember. However, if the method signature is not valid, errors are caught at run time. How will it help me? Very simple. First I start developing my application by adding a reference to the COM object. It's so easy to use .NET wrappers, generated for you by Visual Studio. When I an almost ready to deploy, I remove the reference and use GetTypeFromProgID instead.

That's it.

No comments:

Post a Comment