2017-03-09 6 views
0

Als Teil meiner Arbeit, ich schreibe einen SOAP 1.2-basierten Webservice, der XML-Anfragen empfängt und verarbeitet. Beim Testen mit dem Remote-Client stieß ich jedoch auf ein ziemlich verwirrendes und inkonsistentes Problem. C# SOAP-Service-Methode empfängt Null-Parameter anstelle von

Dies ist die Unterschrift eines der aufrufbaren Methoden des Service:

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

Das Problem ist folgende:

  • Wenn das Verfahren von einer minimalistischen Testanwendung aufgerufen wird, ich schrieb, es funktioniert richtig.
  • Wenn die php-basierte Anwendung meines Clients die Methode aufruft, wird der Methode ein Null request übergeben und dementsprechend wird ein NullReferenceException auf der ganzen Linie ausgelöst, wenn die Anwendung versucht, ihren Inhalt in Datei zu schreiben. Es spielt keine Rolle, was der Client tatsächlich gesendet hat. Wenn Sie Visual Studio an den IIS-Prozess anhängen, wird die Methode mit null request aufgerufen, wobei der tatsächlich gesendete Client irgendwo auf der .NET-Ebene verloren gegangen ist.

Was ich versucht:

  • Unabhängige Tests. This erzeugt das gleiche Problem - aber die gleiche Anfrage in SoapUI kopiert wurde ordnungsgemäß empfangen. Deshalb habe ich oben gesagt, dass dieses Problem inkonsistent ist: Zwei von vier Anwendungen, jeweils auf verschiedenen Computern, reproduzieren das Problem, die anderen beiden nicht.
  • Offenbar kann dies geschehen, wenn der Server SOAP 1.2 erwartet, aber 1.1 erhält, und ich es reproduzieren konnte, indem ich die Anforderung absichtlich als 1.1 in SoapUI posten. So deaktivierte ich sowohl 1.1 als auch das grundlegende HTTP in web.config (das Verifizieren, dass beide aus WSDL verschwanden, nur die 1.2 verlassend) und den Client explizit Version 1.2 auf ihrer Seite definierte. Kein Würfel.
  • Nach dem Ändern des Dienstes wechselte die clientseitige WSDL-Definition der Methode abrupt von XmlDocument zu Linq XElement. Wenn Sie ein serverseitiges Deserialisierungsproblem aufgrund der Feststellung, dass WSDL die erwarteten Datentypen für Multiplatform-Kompatibilität abstrahiert, vermuten, habe ich den Parameter der Methode von XmlDocument in XElement geändert. Kein Würfel.

Inhalt von 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> 

man bedenkt, dass ich in der Lage war erfolgreich Anfrage senden von zwei separaten Computern in zwei separaten Anwendungen ohne manuelle Konfiguration, aber nicht von einer anderen zwei, das ist ein server- Nebenproblem oder eine clientseitige Fehlkonfiguration?

Antwort

0

Die Lösung gefunden und für den Fall gepostet, dass jemand anderes auf dieses Problem zugreift.

Es war ein serverseitiger Fehler. Wenn Sie bei der Unterzeichnung des Verfahrens aussehen ich gepostet oben:

public XmlDocument PostOrders(XmlDocument request) 

Das Problem war der Parameter eine XmlDocument zu sein. Da die Payload einer SOAP-Anfrage bereits in einem XML eingeschlossen ist, kann sie nicht als XmlDocument deserialisiert werden, da das Root-Element der Payload kein Root-Element ist, aus dem es stammt, sondern nur als XmlElement oder Linq XElement.Doch selbst das Ändern des Parametertyps funktionierte nicht - und das war der Zeitpunkt, an dem ich die WSDL betrachtete.

Wie sich herausstellte, weder .NET XML-Typen gearbeitet, denn selbst wenn ich eine serializable Klasse abgeholt (XmlElement/XElement) unabhängig von der WSDL erzeugt habe sie nicht erkannt und konnte nicht herausfinden, welche Art von Daten ist das Verfahren erwartet, also hat die WSDL den Datentyp des Parameters nicht deklariert. Wenn kein Datentyp in der WSDL deklariert wurde, wusste die clientseitige Anwendung nicht, was sie senden sollte. Daher löschte sie die Nutzlast und sendete nur den SOAP-Header. Ich weiß nicht, warum SOAP-Klassen von PHP so funktionieren, aber anscheinend tun sie es.

Ich habe es während des Tests nicht bemerkt, da meine Testanwendung auch .NET ist und automatisch weiß, was zu senden ist, während SoapUI Anfragen rohe Zeichenfolgen ohne jede Serialisierung vor dem Senden sind, so dass es weder den Datentyp noch benötigt.

Die Lösung war, den Parametertyp auf string zu ändern und grundlegende HTTP zu deaktivieren. Während das grundlegende HTTP aktiviert war, verursachte die Deserialisierung immer eine Ausnahme, wenn die Methode mit einem String-Parameter aufgerufen wurde, weshalb ich diese Lösung nicht früher gefunden habe.

Fazit: Wenn Sie einen .NET-Webservice nicht ausschließlich für .NET-Clients schreiben, verwenden Sie keine .NET-Klassen als Eingabeparameter, unabhängig davon, ob sie serialisierbar sind oder nicht. Verwenden Sie Zeichenfolgen. Sie werden sich eine Menge Kopfschmerzen ersparen.

Verwandte Themen