2

Context

Currently I am creating an Extract, Transform and Load (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.

EDIT

From this Stackoverflow question, I gather that the Task class is invariant. If I have understood it correctly, this makes my goal of casting the Delegate to another signature directly impossible. The workarounds mentioned there do not seem to be relevant for my specific case. I am going to look into this further, any help is still greatly appreciated.

Fluous
  • 2,075
  • 2
  • 17
  • 29

0 Answers0