使用包含接口的函数签名调用Delegate.CreateDelegate时发生ArgumentException。

时间:2018-08-17 13:35:48

标签: c# soap delegates .net-core wsdl

上下文

当前,我正在使用.NET Core创建用C#编写的提取加载和转换(ETL)应用程序。 ETL应用程序的源代码是Soap Web服务,其中包含多种方法。每个实体(员工,公司等)和检索方式(ByKey,ByQuery等)都有自己的Soap Web服务方法。例如,如果我要通过执行查询来检索实体“ Employee”,则将调用GetEmployeeByQuery方法。所有方法都返回带有XML的字符串。

Visual Studio通过其WSDL文件(通过dotnet-svcutil间接生成)生成了该Web服务的代理类。不幸的是,为该服务生成的代理类似乎是根据消息契约模式生成的。这意味着代理方法GetEmployeeByQuery返回GetEmployeeByQueryResponse子类,该子类具有包含Body子类的字段GetEmployeesByQueryResponseBody。实际结果位于GetEmployeeByQueryResponseBody名称为GetEmployeeByQueryResult的字符串字段中。

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

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

目标

理想情况下,ETL应用程序能够通过反射并基于其配置来调用Soap Webservice方法。该配置包含要调用的方法和参数,并且通过某些工厂,这导致可以在应用程序中的其他位置调用Delegate(或类似MethodInfo对象之类的东西)。此委托应该是通用的,不应与任何特定实体绑定。

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

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

问题

我当前的解决方案是创建一个独立于实体的委托。为了确保委托具有相同的方法签名,在生成的类上放置了一个接口。生成的...Response...ResponseBody类是局部的。我将这些类扩展到另一个文件中,并在它们上实现一个接口。无论使用哪种实体类型,该界面都使我能够检索结果。

接口

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.

当我使用具体的类而不是接口时,不会发生这种情况。

用于创建代表的助手

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

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

经过一段闲暇时间,我终于明白了为什么它不起作用(一个愚蠢的错误)。我尝试检索的Soap Webservice方法具有仅使用特定(响应)类Type定义的签名。没有定义使用接口定义响应的方法。因此,Delegate.CreateDelegate()方法无法绑定目标方法。

我面临的更大的问题仍然是如何通过应用程序配置的反射来调用Soap Webservice方法。