title: Serialising SOAP parameters in C#
body: <p>I'm trying to write a .Net client to a vendor's SOAP Service, but I'm having trouble getting the parameters to the SOAP messages to serialise to a form that the service recognises.</p>
  
  <p>Using wsdl.exe I generated a service proxy class which works fine in itself.  However, one of the messages takes an argument which is an array of key/value pairs - this is the bit I'm having problems with.</p>
  
  <p>The WSDL for the message is:</p>
  
  <pre><code>  &lt;message name='Execute'&gt;
      &lt;part name='ContextHandle' type='xsd:string'/&gt;
      &lt;part name='ScriptLanguage' type='xsd:string'/&gt;
      &lt;part name='Script' type='xsd:string'/&gt;
      &lt;part name='Params' type='xsd:anyType'/&gt;
    &lt;/message&gt;
  </code></pre>
  
  <p>The service proxy class has this code:</p>
  
  <pre><code>[System.Web.Services.WebServiceBindingAttribute(Name="EngineSoapBinding", Namespace="http://www.smarteam.com/dev/ns/iplatform/embeddedscripts/wsdl/")]
  internal partial class Service : System.Web.Services.Protocols.SoapHttpClientProtocol {
  
      ....
  
      [System.Web.Services.Protocols.SoapRpcMethodAttribute("http://www.smarteam.com/dev/ns/iplatform/embeddedscripts/action/Execute", RequestNamespace="http://www.smarteam.com/dev/ns/iplatform/embeddedscripts", ResponseNamespace="http://www.smarteam.com/dev/ns/iplatform/embeddedscripts", Use=SoapBindingUse.Literal)]
      [return: System.Xml.Serialization.SoapElementAttribute("Result")]
      public object Execute(string ContextHandle, string ScriptLanguage, string Script, object Params) {
          object[] results = this.Invoke("Execute", new object[] {
                      ContextHandle,
                      ScriptLanguage,
                      Script,
                      Params});
          return ((object)(results[0]));
      }
  
      ....
  
  }
  </code></pre>
  
  <p>In the vendor's documentation the Params argument should be an array of key/value pairs.</p>
  
  <p>I've been able to capture network traffic from another working client to this service and got the following example of a message that the service recognises (SOAP envelope removed and formatted for clarity):</p>
  
  <pre><code>&lt;STES:Execute xmlns:STES="http://www.smarteam.com/dev/ns/iplatform/embeddedscripts" xmlns:sof="http://www.smarteam.com/dev/ns/SOF/2.0"&gt;
      &lt;ContextHandle&gt;0019469#00228&lt;/ContextHandle&gt;
      &lt;ScriptLanguage&gt;javascript&lt;/ScriptLanguage&gt;
      &lt;Script&gt;&lt;![CDATA[Context.Result = Context.Params("Number");]]&gt;&lt;/Script&gt;
      &lt;Params SOAP-ENC:arrayType="sof:DictionaryItem[2]"&gt;
          &lt;sof:DictionaryItem&gt;
              &lt;key xsi:type="xsd:string"&gt;Number&lt;/key&gt;
              &lt;value xsi:type="xsd:int"&gt;10&lt;/value&gt;
          &lt;/sof:DictionaryItem&gt;
          &lt;sof:DictionaryItem&gt;
              &lt;key xsi:type="xsd:string"&gt;Hello&lt;/key&gt;
              &lt;value xsi:type="xsd:string"&gt;World&lt;/value&gt;
          &lt;/sof:DictionaryItem&gt;
      &lt;/Params&gt;
  &lt;/STES:Execute&gt;
  </code></pre>
  
  <p>I've tried various data structures for the Params argument, but nothing I've tried gives anything close to this XML serialisation.  </p>
  
  <p>The closest I've been able to get is to write a <code>DictionaryItem</code> class which implements <code>IXmlSerializable</code> with the following <code>WriteXml</code> method:</p>
  
  <pre><code>    public void WriteXml(XmlWriter writer)
      {
          writer.WriteStartElement("key");
          writer.WriteValue(Key);
          writer.WriteEndElement();
          writer.WriteStartElement("value");
          writer.WriteValue(Value);
          writer.WriteEndElement();
      }
  </code></pre>
  
  <p>I then give the <code>Params</code> argument a <code>List&lt;DictionaryItem&gt;</code> which results in the following serialization on the wire.</p>
  
  <pre><code>&lt;Execute xmlns="http://www.smarteam.com/dev/ns/iplatform/embeddedscripts"&gt;
      &lt;ContextHandle xmlns=""&gt;0022541#00228&lt;/ContextHandle&gt;
      &lt;ScriptLanguage xmlns=""&gt;javascript&lt;/ScriptLanguage&gt;
      &lt;Script xmlns=""&gt;Context.Result = Context.Params("Number");&lt;/Script&gt;
      &lt;Params xmlns=""&gt;
          &lt;DictionaryItem xmlns="http://www.smarteam.com/dev/ns/iplatform/embeddedscripts"&gt;
              &lt;key&gt;Number&lt;/key&gt;
              &lt;value&gt;10&lt;/value&gt;
          &lt;/DictionaryItem&gt;
          &lt;DictionaryItem xmlns="http://www.smarteam.com/dev/ns/iplatform/embeddedscripts"&gt;
              &lt;key&gt;Hello&lt;/key&gt;
              &lt;value&gt;World&lt;/value&gt;
          &lt;/DictionaryItem&gt;
      &lt;/Params&gt;
  &lt;/Execute&gt;
  </code></pre>
  
  <p>Can anyone point me in the right direction to get this working?</p>
  
  <p>** Update **</p>
  
  <p>It doesn't surprise me in the slightest that this vendor is using a deprecated message format.  Their whole product is a mess, and I'd gladly ditch it if I could.  It's written in .Net, but has a COM API and this web service in a deprecated format.  They do supply a client library for the web service, but it's writtn in Java.  Huh?  </p>
  
  <p>I'm going to go back to my original idea and write a wrapper around the Java client, using ikvmc.  At least I know I can get that to work, even if all the type conversion will be messy.</p>
  
  <p>As for picking an answer @Cheeso and @Aaronaught have both been very helpful, so I've flipped a coin and given it to @Cheeso.</p>