Tuesday, 13 January 2009

Web Client Software Factory (WCSF) Event Broker

To get the EventBroker to work with version 2.0 of the Web Client Software Factory read this blog.

Although the code change in the above blog entry allows the Event Broker to work you may still come across some problems, the one I recently encountered was related to generic method overloads.

Before generics you could not overload a method without changing its signature, but with generics you can alter the method signature with a type T return for example;

string Get(sting value1)

overload to;

T Get<T>(sting value1)

Now to the compiler the two methods are different, however when you use reflection to find methods and you use the Type.GetMethod, supplying the method name ‘Get’ with the correct types you will receive a ‘System.Reflection.AmbiguousMatchException’ exception. You receive this exception because to find the generic method you supply ‘Get’ and not ‘Get<T>’ which is also how you return the non-generic ‘Get’ method.

Due to the issue above when the Event Broker runs its sanity check by reflecting all your method the ‘System.Reflection.AmbiguousMatchException’ exception is raised when you have a generic overload to overcome this replace;

EventBrokerSanityCheck.cs, ln 147

interfaceInfo = @interface.GetMethod(subscribingMethodInfo.Name, types.ToArray());

With;

MethodInfo interfaceInfo=null;
try
{
    interfaceInfo = @interface.GetMethod(subscribingMethodInfo.Name, types.ToArray());
}
catch (System.Reflection.AmbiguousMatchException)
{
    //Bug fix for generic overloads
    interfaceInfo = @interface.GetMethods().Where(w =>
            w.Name == subscribingMethodInfo.Name
            && w.IsGenericMethod == subscribingMethodInfo.IsGenericMethod).First<MethodInfo>();

    ParameterInfo[] parametersInterface = interfaceInfo.GetParameters();

    if (types.ToArray().Length == parametersInterface.Length)
    {
        for (int i = 0; i < parameters.Length; i++)
        {
            if (parametersInterface[i].ParameterType != types[i])
            {
                interfaceInfo = null; //clear the interface info as we did not find the method
                break;
            }
        }
    }
    else
    {
        interfaceInfo = null; //clear the interface info as we did not find the method
    }
}

[Disclamer : I give no warranty to the correctness of this solution or that there is not a better way to do it, I just hope I help you out of a hole as it did with me]