Question

A systematic breakdown of the problem follows. [Rewritten!]

The client code

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);
            }
        }
    }
}

The 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>

The error trace

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

The generated proxy code using 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)
    {
        this.@return = @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 retVal.@return;
    }

    [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 retVal.@return;
    }
}

This is using the proxy code generated by SvcUtil.exe.

Download full Visual Studio project files here:

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

Now, I just tried using the WSDL.exe again. This works better, but now the next problem rears it's ugly head. The app.config for WCF is not used. So I need to configure the proxy class to use a certificate. For WCF I just say

<?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, now using a piece of code to provide signatures

    proxy.ClientCertificates.Add(cert);

This now almost works, except it can't decode the response.

Was it helpful?

Solution

It depends on what you expect to get. That is mirrored on how you define the wsdl. For example if you replace all "urn:Test" with java:bla.bla.bla.bla you get a simpler definition that just receives/returns strings.

If you still want to get 2 different request/response types, you can use this definition:

<?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. as you seem to want request/response documents for all the operations/methods, you might want to switch completely to document style.


About comments not being able to make breaking changes. Changing namespaces or names of the message elements are breaking changes.

That said, if you are only interested in making it work (and don't care on the form of the classes you are getting) you can use the version you have. It doesn't matter the generated classes use LaunchMissileResponse for both methods, as the underlying XML will be the same (a TestResponse). Also for the calling code, remember you have a version that receives/sends simple strings:

public string AbortMission(string arg0)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top