mardi 21 août 2018

Dynamically cast delegate to signature with interface at runtime

Context

Currently I am creating an Extract Load and Transform (ETL) application written in C# with .NET Core. The source of the ETL application is a Soap webservice, which contains a multitude of methods. Each entity (Employee, Company, etc) and way of retrieving (ByKey, ByQuery, etc) has its own Soap webservice method. For example if I were to retrieve the entity 'Employee' by executing a query, I would call the GetEmployeeByQuery method. All methods return a string with XML.

Visual Studio generated proxy classes of this webservice by its WSDL file (generated indirectly through dotnet-svcutil). Unfortunately the proxy classes generated for this service seem to be generated according to a message contract pattern. This means that the proxy method GetEmployeeByQuery returns the GetEmployeeByQueryResponse partial class, which has a field Body that contains the GetEmployeesByQueryResponseBody partial class. The actual result is located in a string field on the GetEmployeeByQueryResponseBody that has the name of GetEmployeeByQueryResult.

Ideally the ETL application is able to invoke Soap webservice methods through reflection and on the basis of application configuration. The configuration contains the method and parameters to call, and through some factories this results in a Delegate that will be used as a strategy elsewhere in the application. This delegate should be generic and not tied to any specific entity.

The Problem

Currently I have created a delegate with a signature that solely consists of the concrete type implementations. This is necessary because the Delegate.CreateDelegate method requires this in order to bind the actual method to the delegate. The signature is Func<string, string, string, string, Task<GetEmployeeByQueryResponse>>. This signature however is tied to a specific entity, which is what I am trying to prevent.

Therefore I am trying to cast this delegate to the signature Func<string, string, string, string, Task<IMessageResult<string>>> where the IMessageResult<string> is an interface implemented on the generated proxy code through a partial class.

Method that tries to retrieve more generic delegate

public static TMethodSignatureInterfaced GetMethodDelegate<TMethodSignatureInterfaced>(object classInstance, string methodName, Type methodSignatureTyped)
    where TMethodSignatureInterfaced : class
{
    //Another way of casting, same result.
    //TMethodSignatureInterfaced method = (TMethodSignatureInterfaced)(object)Delegate
    //    .CreateDelegate(methodSignatureTyped, classInstance, methodName) as TMethodSignatureInterfaced;

    TMethodSignatureInterfaced method = Delegate
        .CreateDelegate(methodSignatureTyped, classInstance, methodName) as TMethodSignatureInterfaced;

    if (method == null)
        throw new InvalidCastException($"Method {methodName} could not be cast into a delegate. The given method signature could not be found.");

    return method;
}

Unfortunately it seems that casting the delegate to another signature is not possibly dynamically. The code either throws an error (with the first casting technique) or returns null. In other posts I have seen cases where if the interface is specified casting a delegate is possible. I was wondering whether someone would know a way around this.





Aucun commentaire:

Enregistrer un commentaire