当使用包含接口的函数签名调用 Delegate.CreateDelegate 时出现 ArgumentException。

ArgumentException when Delegate.CreateDelegate is called with a function signature that contains an interface.

上下文

目前我正在创建一个使用 C# 和 .NET Core 编写的提取加载和转换 (ETL) 应用程序。 ETL 应用程序的源是一个 Soap Web 服务,其中包含大量方法。每个实体(员工、公司等)和检索方式(ByKey、ByQuery 等)都有自己的 Soap web 服务方法。例如,如果我要通过执行查询来检索实体 'Employee',我会调用 GetEmployeeByQuery 方法。所有方法 return 一个带有 XML.

的字符串

Visual Studio 通过其 WSDL 文件(通过 dotnet-svcutil 间接生成)生成了此 Web 服务的代理 classes。不幸的是,为此服务生成的代理 classes 似乎是根据消息契约模式生成的。这意味着代理方法 GetEmployeeByQuery return 是 GetEmployeeByQueryResponse 部分 class,它有一个字段 Body 包含 GetEmployeesByQueryResponseBody 部分 class。实际结果位于 GetEmployeeByQueryResponseBody 上名称为 GetEmployeeByQueryResult.

的字符串字段中

调整代码生成以生成不遵守消息契约模式的代理 classes 的尝试并未取得成果。调整 'ConnectedService.json' 文件中的选项 GenerateMessageContract 或直接使用 dotnet-svcutil.exe 工具都没有导致生成的代码发生任何变化。

注意:在 .NET Framework 中,生成的代码不遵循消息约定模式。

目标

理想情况下,ETL 应用程序能够通过反射并在其配置的基础上调用 Soap web 服务方法。配置包含要调用的方法和参数,并且通过一些工厂,这会产生一个可以在应用程序的其他地方调用的委托(或类似于 MethodInfo 对象的东西)。该委托应该是通用的,不与任何特定实体绑定。

动态调用生成的 Soap 网络服务方法,由于消息协定(部分)classes '...Response' 和 '...ResponseBody' 而变得相当复杂。而不是为每个生成的代理方法使用最相似的方法签名(参数和 return 类型始终是字符串)。我现在为每个生成的代理方法以及每个实体都有不同的方法签名。

我希望多个方法具有相同委托的原因是因为每个实体类型执行的操作实际上是相同的。我不想为每个单独的实体编写代码,而是希望以独立于实体的方式来编写代码。

问题

我目前的解决方案是创建一个实体独立委托。为了确保委托具有相同的方法签名,在生成的 classes 上放置了一个接口。生成的 ...Response...ResponseBody class 是部分的。我在另一个文件中扩展了这些 classes 并在其上实现了一个接口。此接口允许我检索结果,而不管它是哪种实体类型。

界面

public interface IMessageResult<T>
{
    T GetResult();
}

接口实现

public partial class GetUDICByQueryResponse : IMessageResult<string>
{
    public string GetResult()
    {
        return Body.GetUDICByQueryResult;
    }
}

很遗憾,我无法成功创建委托。每当我尝试通过 Delegate.CreateDelegate 创建委托时,我都会收到以下错误:

Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.

当我使用具体 class 而不是界面时,不会发生这种情况。

创建委托的助手

public static TMethodSignature GetLocalMethod<TMethodSignature>(object classInstance, string methodName)
        where TMethodSignature : class
    {
        Type methodSignature = typeof(TMethodSignature);

        TMethodSignature method = Delegate.CreateDelegate(
            methodSignature,
            classInstance,
            methodName) as TMethodSignature;

        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;
    }

调用辅助方法

var soapMethod = ReflectionUtils.GetLocalMethod<Func<string, string, string, string, Task<IMessageResult<string>>>>(Service, parameters.MethodName);

如有任何帮助,我们将不胜感激!

经过一些空闲时间,我明白了为什么这不起作用(一个愚蠢的错误)。我尝试检索的 Soap Web 服务方法具有仅使用特定(响应)class 类型定义的签名。在使用接口定义响应的地方没有定义方法。因此 Delegate.CreateDelegate() 方法无法绑定目标方法。

我面临的更大问题是如何通过应用程序配置通过反射调用 Soap web 服务方法,但是仍然存在。