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

时间:2017-03-09 17:46:39

标签: c# soap wsdl nullreferenceexception

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

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

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

问题在于:

  • 当我从我编写的极简主义测试应用程序调用该方法时,它可以正常工作。
  • 当我的客户端基于php的应用程序调用该方法时,该方法将传递null request,并在应用程序尝试将其内容写入时向下抛出NullReferenceException行文件。客户端实际发送的内容并不重要,将Visual Studio附加到IIS进程会显示该方法是使用null request调用的,客户端实际发送的内容已在.NET级别的某处丢失

我尝试了什么:

  • 独立测试。 This产生同样的问题 - 但是正确接收了在SoapUI中复制的相同请求。这就是为什么我在上面说过这个问题是不一致的:四个应用程序中的两个,每个都在不同的计算机上,重现问题,另外两个不应该。
  • 显然,如果服务器需要SOAP 1.2但收到1.1,就会发生这种情况,我可以通过故意在SoapUI中将请求发布为1.1来重现它。所以我在web.config中禁用了1.1和基本HTTP(验证两者都从WSDL中消失,只剩下1.2)并让客户端明确定义版本1.2。没有骰子。
  • 修改服务后,方法的客户端WSDL定义突然从XmlDocument切换到Linq XElement。由于发现WSDL抽象出了多平台兼容性的预期数据类型,怀疑服务器端反序列化问题,我将方法的参数从XmlDocument更改为XElement。没有骰子。

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>

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

1 个答案:

答案 0 :(得分:0)

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

这是服务器端错误。如果你看一下我在上面发布的方法的签名:

a = c

问题是参数为public XmlDocument PostOrders(XmlDocument request) 。由于SOAP请求的有效负载已经包含在XML中,因此无法将其反序列化为XmlDocument,因为有效负载的根元素不是它来自的根元素,仅作为XmlDocument或Linq XmlElement。然而,即使更改参数类型也不起作用 - 就在我查看WSDL时。

事实证明,.NET XML类型都不起作用,因为即使我选择了一个可序列化的类(XElement / XmlElement),无论生成什么WSDL都无法识别它们并且无法弄清楚该方法期望什么样的数据,因此WSDL没有声明参数的数据类型。由于WSDL中没有声明数据类型,因此客户端应用程序也不知道要发送什么,因此它会删除有效负载并仅发送SOAP标头。我不知道为什么php的SOAP类就像那样工作,但它们显然是这样做的。

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

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

结论:如果您不是专门为.NET客户端编写.NET Web服务,请不要使用.NET类作为输入参数,无论它们是否可序列化。使用字符串。你会为自己省下很多头痛。