1

让我先描述我的意图是什么,然后进入我的问题。

我正在尝试构建一个与 SOAP 服务通信的系统,其中 SOAP 请求在运行时有些未知。最终我需要做的是从未知对象生成一个 SOAP 请求。我将使用适当的属性和属性从头开始动态创建对象,然后将其传递给我的服务“请求”方法以发送到 SOAP 服务。这是我一直在使用的代码,然后是我收到的错误。

SOAP 客户端:

/// <summary>
/// GOSService proxy class
/// </summary>
[DebuggerStepThroughAttribute()]
[DesignerCategoryAttribute("code")]
[WebServiceBindingAttribute(Name = "ServiceSoapBinding", Namespace = "service.domain.com", ConformsTo = WsiProfiles.None)]
[SoapRpcService(RoutingStyle = SoapServiceRoutingStyle.RequestElement)]
public partial class TestService : SoapHttpClientProtocol
{
    /// <summary>
    /// Initializes a new instance of the TestService class.
    /// </summary>
    public TestService()
    {
        this.Url = "https://restsv01.domain.com/ServiceTest/services/TestService";
        ServicePointManager.Expect100Continue = true;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
        ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(OnRemoteCertificateValidationCallback);
    }

    /// <summary>
    /// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication.
    /// </summary>
    /// <param name="sender">An object that contains state information for this validation.</param>
    /// <param name="certificate">The certificate used to authenticate the remote party.</param>
    /// <param name="chain">The chain of certificate authorities associated with the remote certificate.</param>
    /// <param name="sslPolicyErrors">One or more errors associated with the remote certificate.</param>
    /// <returns>A Boolean value that determines whether the specified certificate is accepted for authentication.</returns>
    private bool OnRemoteCertificateValidationCallback(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        return true;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="order"></param>
    /// <returns></returns>
    [SoapRpcMethodAttribute("", RequestNamespace = "service.domain.com", ResponseNamespace = "service.domain.com")]
    [SampleSoap.LoggerSoapExtensionAttribute]
    [return: SoapElementAttribute("requestReturn")]
    public object request(object parm)
    {
        object[] results = this.Invoke("request", new object[] { parm });
        return ((object)(results[0]));
    }}

测试模型:(不会有任何预定义的模型,它们是动态生成的。但出于测试目的,我使用此模型进行测试)

    [SerializableAttribute()]
    [DebuggerStepThroughAttribute()]
    [DesignerCategoryAttribute("code")]
    [SoapTypeAttribute(Namespace = "http://entity.domain.com")]
    public class ParentNode
    {
        private string nameField = "1";
        [SoapElementAttribute(IsNullable = true)]
        public string Name
        {
            get { return this.nameField; }
            set { this.nameField = value; }
        }
    }

测试调用代码:

        Services.Soap.Models.ParentNode parent = new Services.Soap.Models.ParentNode();
        parent.Name = "John Doe";
        Services.Soap.TestService service = new Services.Soap.TestService();
        object resp = service.request(parent);

当我运行此代码时,此行出现错误:

object[] results = this.Invoke("request", new object[] { parm });

这是错误:

类型 Services.Soap.Models+ParentNode 不是预期的。使用 XmlInclude 或 SoapInclude 属性指定静态未知的类型。

现在,如果我将服务“请求”方法的参数更改为强类型,则请求构建良好并传递给 SOAP 服务,就像这样。

public object request(ParentNode parm)

我已经尝试了大约 50 种方法来让它工作,包括将类型作为参数传递给请求方法并创建要传递的对象的“动态”实例。

    public object request(object parm, Type t)
    {
        dynamic converted = Convert.ChangeType(parm, t);

        object[] results = this.Invoke("request", new object[] { converted });
        return ((object)(results[0]));
    } 

这不起作用,因为“已转换”仍被视为对象类型。

我还尝试在“GetWriterForMessage”方法中截取soap 信封,这样我就可以构建自己的信封,但我无法使用它。

所以我的问题是,如何使用参数类型的对象成功构建 SOAP 请求?我应该采取另一种方法来使我的架构正常工作吗?

4

1 回答 1

1

您对您正在实施的系统的描述对我来说不是很清楚。您提到您将向 SOAP 服务器发送“动态”请求?或者您是否正在使用“动态”操作创建一些服务。这些细节对我来说有点模糊,但我草草写下了一些想法。

简而言之,如果您想在 SOAP 中执行此操作,您将为自己打开一个痛苦的世界。REST 可能更合适,因为它没有 WSDL,但如果您使用 WADL、RAML 和这些新兴标准,您的使用量可能会有所不同。我不会尝试甚至为您回答技术问题,但会尝试让您了解为什么这是通往维护地狱的单程票。

此实现确实打破了 SOA 概念(特别是标准化服务合同),这可能不适用于您的情况,因为仅实现具有未知内容的动态 WSDL 会使体系结构不符合 SOA 的资格。这也与拥有 WSDL 的全部意义相矛盾。WSDL 是 XML 中的接口定义。因此,动态服务将需要一个动态接口,然后将其限定为非接口。因此,当您使用对象类型作为参数时,WSDL 和接口不匹配。

当其他系统使用您的 SOAP 服务时,它们将基于已发布的 WSDL 这样做。如果 WSDL 更改,他们的程序将因定义或 WSDL 与他们生成的数据类型不匹配而中断。在 HTTP 上工作并获取请求和发送回复并且没有 WSDL 的服务不是 SOAP 服务,它是使用 HTTP 端口的基于 XML 的服务。它们是根本不同的。您的服务提供商(即您请求数据的 SOAP 服务)是否没有 WSDL?如果不是,这些不是您正在寻找的机器人 :)

接口是约定的合同,应用程序可以使用它来查询服务。本质上,您在谈论结构化与非结构化数据对象(至少在运行时)。

如果你想要这种类型的模式,你需要查看一个发布订阅架构,比如使用轻量级的 MQTT,或者另一个例子是带有主题的 JMS。

如果您正在使用您提到的 Web 服务,那么将有一个 WSDL,您的 .Net 应用程序可以使用它来生成数据类型和关联的 C# 类。这些类将包括正在传输的数据和在服务上公开的操作。

在官方的 SOAP 世界中,没有动态服务之类的东西,因为它打破了我们同意服务器和客户端在操作期间通过这种形式的 XML 进行通信的整个范式。

于 2016-12-01T00:56:53.947 回答