C# SOAP 服务方法接收空参数而不是

C# SOAP service method receives null parameter instead of

作为我工作的一部分,我要编写一个基于 SOAP 1.2 的 Web 服务来接收和处理 XML 请求。然而,在使用远程客户端进行测试期间,我 运行 遇到了一个相当令人费解且不一致的问题。

这是服务的可调用方法之一的签名:

[WebMethod]
[ScriptMethod(UseHttpGet = false, ResponseFormat = ResponseFormat.Xml)]
public XmlDocument PostOrders(XmlDocument request)

这里的问题是:

我尝试了什么:

web.config 的内容:

<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.5.2" />
    <httpRuntime />
    <webServices>
      <protocols>
        <remove name="HttpGet" />
        <remove name="HttpPost" />
        <remove name="HttpSoap"/>     <!-- disables SOAP 1.1 -->
      </protocols>
      <conformanceWarnings>
        <remove name='BasicProfile1_1'/>
      </conformanceWarnings>
    </webServices>
    <globalization uiCulture="en-US" />
    <customErrors mode="Off" />
    <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID" />
    <httpModules>
      <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" />
    </httpModules>
  </system.web>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
          <providerOption name="CompilerVersion" value="v4.0" />
      </compiler>
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.VisualBasic.VBCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
    </compilers>
  </system.codedom>
  <system.webServer>
    <modules>
      <remove name="ApplicationInsightsWebTracking" />
      <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler" />
    </modules>
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
    <validation validateIntegratedModeConfiguration="false" />
  </system.webServer>
  <system.serviceModel>
    <bindings />
    <client />
  </system.serviceModel>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

考虑到我能够在两个单独的应用程序中从两台单独的计算机成功发送请求而无需任何手动配置,但不是来自另外两个,这是服务器端问题还是客户端配置错误?

找到解决方案并发布它以防其他人遇到此问题。

这是一个 server-side 错误。如果您查看我上面发布的方法的签名:

public XmlDocument PostOrders(XmlDocument request)

问题是参数是 XmlDocument。由于 SOAP 请求的有效负载已经封装在 XML 中,因此无法将其反序列化为 XmlDocument,因为有效负载的根元素不是它来自的根元素,只能作为 XmlElement 或 Linq XElement。然而,即使更改参数类型也不起作用 - 那是我查看 WSDL 的时候。

事实证明,.NET XML 类型都不起作用,因为即使我选择了可​​序列化的 class (XmlElement/XElement) 生成的 WSDL 也没有无法识别它们并且无法弄清楚该方法需要什么样的数据,因此 WSDL 没有声明参数的数据类型。由于没有在 WSDL 中声明数据类型,client-side 应用程序也不知道要发送什么,因此它切断了有效负载并仅发送 SOAP header。我不知道为什么 php 的 SOAP class 会那样工作,但他们显然是这样。

我在测试期间没有注意到它,因为我的测试应用程序也是 .NET,因此自动知道要发送什么,而 SoapUI 的请求是原始字符串,在发送之前没有任何序列化,所以它既不需要也不关心数据类型.

解决方案是将参数类型更改为 string 并禁用基本 HTTP。虽然启用了基本 HTTP,但当使用字符串参数调用方法时,反序列化总是抛出异常,因此我没有早点找到这个解决方案。

底线:如果您编写的 .NET Web 服务并非专门用于 .NET 客户端,请不要使用 .NET classes 作为输入参数,无论它们是否可序列化。使用字符串。你会省去很多头痛的事情。