2009-03-21 6 views
2

Une répartition systématique du problème suit. [Réécriture!]Impossible d'utiliser la définition WSDL

Le code client

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

// This is a "sanitized" version of the real deal, of course. In reality I also require to 
// sign all incomming and outgoing messages and com. over SSL. The basic model is the same 
// though and the sanitized WSDL captures the problem in its minimal form. 

namespace MissileDefenseSystem 
{ 
    using MissileDefenseSystemServiceReference; 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      try 
      { 
       var client = new TestPortTypeClient(); 
       var req = "just do it"; 
       Console.WriteLine("request>" + req + "<"); 
       var rsp = client.LaunchMissiles(req); 
       Console.WriteLine("response>" + rsp + "<"); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine("exception>" + e.Message + "<"); 
       Console.WriteLine(e.StackTrace); 
      } 
     } 
    } 
} 

Le WSDL

<?xml version="1.0" encoding="ISO-8859-1"?> 
<definitions targetNamespace="java:bla.bla.bla.bla" 
      xmlns="http://schemas.xmlsoap.org/wsdl/" 
      xmlns:tns="java:bla.bla.bla.bla" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
      xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"> 
    <types> 
    <schema targetNamespace='java:bla.bla.bla.bla' xmlns='http://www.w3.org/2001/XMLSchema'/> 
    </types> 
    <message name="TestRequest"> 
    <part name="arg0" type="xsd:string"/> 
    </message> 
    <message name="TestResponse"> 
    <part name="return" type="xsd:string"/> 
    </message> 
    <portType name="TestPortType"> 
    <operation name="LaunchMissiles"> 
     <input message="tns:TestRequest"/> 
     <output message="tns:TestResponse"/> 
    </operation> 
    <operation name="AbortMission"> 
     <input message="tns:TestRequest"/> 
     <output message="tns:TestResponse"/> 
    </operation> 
    </portType> 
    <binding name="TestBinding" type="tns:TestPortType"> 
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> 
    <operation name="LaunchMissiles"> 
     <soap:operation soapAction="urn:LaunchMissiles"/> 
     <input> 
     <soap:body use="encoded" namespace='urn:Test' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> 
     </input> 
     <output> 
     <soap:body use="encoded" namespace='urn:Test' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> 
     </output> 
    </operation> 
    <operation name="AbortMission"> 
     <soap:operation soapAction="urn:AbortMission"/> 
     <input> 
     <soap:body use="encoded" namespace='urn:Test' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> 
     </input> 
     <output> 
     <soap:body use="encoded" namespace='urn:Test' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> 
     </output> 
    </operation> 
    </binding> 
    <service name="Test"> 
    <documentation>todo</documentation> 
    <port name="TestPort" binding="tns:TestBinding"> 
     <soap:address location="https://demo.blablablablablabla.com:123/Bla"/> 
    </port> 
    </service> 
</definitions> 

La trace d'erreur

request>just do it< 
exception>RPC Message LaunchMissilesRequest in operation AbortMission has an invalid body name LaunchMissiles. It must be AbortMission< 
    at System.ServiceModel.Description.XmlSerializerOperationBehavior.Reflector.OperationReflector.EnsureMessageInfos() 
    at System.ServiceModel.Description.XmlSerializerOperationBehavior.Reflector.EnsureMessageInfos() 
    at System.ServiceModel.Description.XmlSerializerOperationBehavior.Reflector.OperationReflector.get_Request() 
    at System.ServiceModel.Description.XmlSerializerOperationBehavior.CreateFormatter() 
    at System.ServiceModel.Description.XmlSerializerOperationBehavior.System.ServiceModel.Description.IOperationBehavior.ApplyClientBehavior(OperationDescription description, ClientOperation proxy) 
    at System.ServiceModel.Description.DispatcherBuilder.BindOperations(ContractDescription contract, ClientRuntime proxy, DispatchRuntime dispatch) 
    at System.ServiceModel.Description.DispatcherBuilder.ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime clientRuntime) 
    at System.ServiceModel.Description.DispatcherBuilder.BuildProxyBehavior(ServiceEndpoint serviceEndpoint, BindingParameterCollection& parameters) 
    at System.ServiceModel.Channels.ServiceChannelFactory.BuildChannelFactory(ServiceEndpoint serviceEndpoint) 
    at System.ServiceModel.ChannelFactory.CreateFactory() 
    at System.ServiceModel.ChannelFactory.OnOpening() 
    at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) 
    at System.ServiceModel.ChannelFactory.EnsureOpened() 
    at System.ServiceModel.ChannelFactory`1.CreateChannel(EndpointAddress address, Uri via) 
    at System.ServiceModel.ChannelFactory`1.CreateChannel() 
    at System.ServiceModel.ClientBase`1.CreateChannel() 
    at System.ServiceModel.ClientBase`1.CreateChannelInternal() 
    at System.ServiceModel.ClientBase`1.get_Channel() 
    at MissileDefenseSystem.MissileDefenseSystemServiceReference.TestPortTypeClient.MissileDefenseSystem.MissileDefenseSystemServiceReference.TestPortType.LaunchMissiles(LaunchMissilesRequest request) in C:\Users\bra\Documents\Visual Studio 2008\Projects\MissileDefenseSystem\MissileDefenseSystem\Service References\MissileDefenseSystemServiceReference\Reference.cs:line 90 
    at MissileDefenseSystem.MissileDefenseSystemServiceReference.TestPortTypeClient.LaunchMissiles(String arg0) in C:\Users\bra\Documents\Visual Studio 2008\Projects\MissileDefenseSystem\MissileDefenseSystem\Service References\MissileDefenseSystemServiceReference\Reference.cs:line 96 
    at MissileDefenseSystem.Program.Main(String[] args) in C:\Users\bra\Documents\Visual Studio 2008\Projects\MissileDefenseSystem\MissileDefenseSystem\Program.cs:line 22 

Le a généré le code de proxy à l'aide de Visual Studio 2008 (SvcUtil.exe).

//------------------------------------------------------------------------------ 
// <auto-generated> 
//  This code was generated by a tool. 
//  Runtime Version:2.0.50727.3074 
// 
//  Changes to this file may cause incorrect behavior and will be lost if 
//  the code is regenerated. 
// </auto-generated> 
//------------------------------------------------------------------------------ 



[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] 
[System.ServiceModel.ServiceContractAttribute(Namespace="java:bla.bla.bla.bla", ConfigurationName="TestPortType")] 
public interface TestPortType 
{ 

    // CODEGEN: Generating message contract since the wrapper namespace (urn:Test) of message LaunchMissilesRequest does not match the default value (java:bla.bla.bla.bla) 
    [System.ServiceModel.OperationContractAttribute(Action="urn:LaunchMissiles", ReplyAction="*")] 
    [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, Use=System.ServiceModel.OperationFormatUse.Encoded)] 
    LaunchMissilesResponse LaunchMissiles(LaunchMissilesRequest request); 

    // CODEGEN: Generating message contract since the wrapper namespace (urn:Test) of message AbortMissionRequest does not match the default value (java:bla.bla.bla.bla) 
    [System.ServiceModel.OperationContractAttribute(Action="urn:AbortMission", ReplyAction="*")] 
    [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, Use=System.ServiceModel.OperationFormatUse.Encoded)] 
    LaunchMissilesResponse AbortMission(LaunchMissilesRequest request); 
} 

[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] 
[System.ServiceModel.MessageContractAttribute(WrapperName="LaunchMissiles", WrapperNamespace="urn:Test", IsWrapped=true)] 
public partial class LaunchMissilesRequest 
{ 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=0)] 
    public string arg0; 

    public LaunchMissilesRequest() 
    { 
    } 

    public LaunchMissilesRequest(string arg0) 
    { 
     this.arg0 = arg0; 
    } 
} 

[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] 
[System.ServiceModel.MessageContractAttribute(WrapperName="LaunchMissilesResponse", WrapperNamespace="urn:Test", IsWrapped=true)] 
public partial class LaunchMissilesResponse 
{ 

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=0)] 
    public string @return; 

    public LaunchMissilesResponse() 
    { 
    } 

    public LaunchMissilesResponse(string @return) 
    { 
     [email protected] = @return; 
    } 
} 

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] 
public interface TestPortTypeChannel : TestPortType, System.ServiceModel.IClientChannel 
{ 
} 

[System.Diagnostics.DebuggerStepThroughAttribute()] 
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] 
public partial class TestPortTypeClient : System.ServiceModel.ClientBase<TestPortType>, TestPortType 
{ 

    public TestPortTypeClient() 
    { 
    } 

    public TestPortTypeClient(string endpointConfigurationName) : 
      base(endpointConfigurationName) 
    { 
    } 

    public TestPortTypeClient(string endpointConfigurationName, string remoteAddress) : 
      base(endpointConfigurationName, remoteAddress) 
    { 
    } 

    public TestPortTypeClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
      base(endpointConfigurationName, remoteAddress) 
    { 
    } 

    public TestPortTypeClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
      base(binding, remoteAddress) 
    { 
    } 

    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] 
    LaunchMissilesResponse TestPortType.LaunchMissiles(LaunchMissilesRequest request) 
    { 
     return base.Channel.LaunchMissiles(request); 
    } 

    public string LaunchMissiles(string arg0) 
    { 
     LaunchMissilesRequest inValue = new LaunchMissilesRequest(); 
     inValue.arg0 = arg0; 
     LaunchMissilesResponse retVal = ((TestPortType)(this)).LaunchMissiles(inValue); 
     return [email protected]; 
    } 

    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] 
    LaunchMissilesResponse TestPortType.AbortMission(LaunchMissilesRequest request) 
    { 
     return base.Channel.AbortMission(request); 
    } 

    public string AbortMission(string arg0) 
    { 
     LaunchMissilesRequest inValue = new LaunchMissilesRequest(); 
     inValue.arg0 = arg0; 
     LaunchMissilesResponse retVal = ((TestPortType)(this)).AbortMission(inValue); 
     return [email protected]; 
    } 
} 

est d'utiliser le code proxy généré par SvcUtil.exe.

Télécharger le projet Visual Studio fichiers ici:

http://dl.getdropbox.com/u/797094/MissileDefenseSystem.zip

Maintenant, je viens d'essayer de nouveau en utilisant le WSDL.exe. Cela fonctionne mieux, mais maintenant le prochain problème se dresse c'est laide tête. Le fichier app.config pour WCF n'est pas utilisé. J'ai donc besoin de configurer la classe proxy pour utiliser un certificat. Pour WCF Je dis simplement

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.serviceModel> 
     <bindings> 
      <basicHttpBinding> 
       <binding name="TestBinding"/> 
      </basicHttpBinding> 
     </bindings> 
     <client> 
      <endpoint address="https://demo.blablablablablabla.com:123/Bla" 
       binding="basicHttpBinding" bindingConfiguration="TestBinding" 
       contract="MissileDefenseSystemServiceReference.TestPortType" 
       name="TestPort"> 
       <identity> 
        <certificateReference storeLocation="CurrentUser" x509FindType="FindByThumbprint" 
         findValue="the thumbprint to be used" /> 
       </identity> 
      </endpoint> 
     </client> 
    </system.serviceModel> 
</configuration> 

OK, en utilisant maintenant un morceau de code pour fournir des signatures

proxy.ClientCertificates.Add(cert); 

Ce fonctionne maintenant presque, sauf qu'il ne peut pas décoder la réponse.

+0

pour la clarification sur demande/réponse - voir ma mise à jour pour ce que génère wsdl.exe; semble beaucoup plus raisonnable. Version courte: utilisez wsdl.exe pour cela! –

+0

BTW, je n'étais pas au courant que java: était un espace de noms XML valide. Est-ce que quelqu'un l'a enregistré, et si oui, une URL pour le format? –

+0

Il doit s'agir d'un URI absolu valide, qui est la seule exigence pour tout espace de noms XML. Le schéma URI est propriétaire, mais cela ne devrait pas avoir d'importance. Aucune idée sur les inscriptions possibles. –

Répondre

2

Cela dépend de ce que vous attendez. Cela est reflété sur la façon dont vous définissez le wsdl. Par exemple, si vous remplacez tout "urn: Test" par java: bla.bla.bla.bla, vous obtenez une définition plus simple qui ne reçoit/retourne que des chaînes.

Si vous voulez toujours obtenir 2 différents types de demande/réponse, vous pouvez utiliser cette définition:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<definitions targetNamespace="java:bla.bla.bla.bla" 
      xmlns="http://schemas.xmlsoap.org/wsdl/" 
      xmlns:tns="java:bla.bla.bla.bla" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
      xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"> 
    <types> 
    <schema targetNamespace='java:bla.bla.bla.bla' xmlns='http://www.w3.org/2001/XMLSchema'/> 
    </types> 
    <message name="AbortTestRequest"> 
    <part name="arg0" type="xsd:string"/> 
    </message> 
    <message name="AbortTestResponse"> 
    <part name="return" type="xsd:string"/> 
    </message> 
    <message name="LaunchTestRequest"> 
    <part name="arg0" type="xsd:string"/> 
    </message> 
    <message name="LaunchTestResponse"> 
    <part name="return" type="xsd:string"/> 
    </message> 
    <portType name="TestPortType"> 
    <operation name="LaunchMissiles"> 
     <input message="tns:LaunchTestRequest"/> 
     <output message="tns:LaunchTestResponse"/> 
    </operation> 
    <operation name="AbortMission"> 
     <input message="tns:AbortTestRequest"/> 
     <output message="tns:AbortTestResponse"/> 
    </operation> 
    </portType> 
    <binding name="TestBinding" type="tns:TestPortType"> 
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> 
    <operation name="LaunchMissiles"> 
     <soap:operation soapAction="urn:LaunchMissiles"/> 
     <input> 
     <soap:body use="encoded" namespace='java:bla.bla.bla.bla/launch' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> 
     </input> 
     <output> 
     <soap:body use="encoded" namespace='java:bla.bla.bla.bla/launch' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> 
     </output> 
    </operation> 
    <operation name="AbortMission"> 
     <soap:operation soapAction="urn:AbortMission"/> 
     <input> 
     <soap:body use="encoded" namespace='java:bla.bla.bla.bla/launch' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> 
     </input> 
     <output> 
     <soap:body use="encoded" namespace='java:bla.bla.bla.bla/launch' encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> 
     </output> 
    </operation> 
    </binding> 
    <service name="Test"> 
    <documentation>todo</documentation> 
    <port name="TestPort" binding="tns:TestBinding"> 
     <soap:address location="https://demo.blablablablablabla.com:123/Bla"/> 
    </port> 
    </service> 
</definitions> 

Ps. Comme vous semblez vouloir des documents de demande/réponse pour toutes les opérations/méthodes, vous voudrez peut-être passer complètement au style de document.


À propos des commentaires ne pouvant pas apporter de modifications de rupture. Modifier les espaces de noms ou les noms des éléments de message sont des changements de rupture. Cela dit, si vous êtes seulement intéressé à le faire fonctionner (et ne vous souciez pas de la forme des classes que vous obtenez), vous pouvez utiliser la version que vous avez. Peu importe que les classes générées utilisent LaunchMissileResponse pour les deux méthodes, car le XML sous-jacent sera le même (un TestResponse). Rappelez-vous également que vous avez une version qui reçoit/envoie des chaînes simples:

public string AbortMission(string arg0) 
+0

Vos commentaires sur mon message (maintenant invisible, je supprime ma réponse) étaient tous bons. +1 –

+0

Si je me souviens bien, en fait SOAPUI est capable de créer des requêtes de test correctes à partir du WSDL que j'ai posté, en regardant le XML qu'il crée - mais c'est un outil Java. Tous les outils .Net que j'essaie ne semblent pas pouvoir le couper. –

+0

Marc, je peux faire des changements "non-bris" au WSDL que je veux, mais je ne contrôle pas la définition, je dois juste interopérer avec ce service. Mais je vais tester cela plus tard aujourd'hui et rendre compte. Merci pour votre aide jusqu'à maintenant. –

Questions connexes