Interop with .Net issues

"Mike Jones" <[email protected]> Fri, 4 Jul 2003 14:38:28 -0700
Newsgroups gmane.comp.java.enhydra.ksoap
Message-ID <!~!UENERkVCMDkAAQACAAAAAAAAAAAAAAAAABgAAAAAAAAAq5r+Gdo6e0SOWnHo8vu74qKCAAAQAAAAeL+Hz4MXHUexVLoY+9sJ7AEAAAAA@woofumdust.com>
Hi,

I am having some trouble passing soap messages between ksoap and .Net
soap.

I am not trying to use Web Services or any kind of RPC. My goal is
simply to encode and decode objects. I have been able to create a ksoap
marshaler that uses reflection to find fields, and I can read and write
soap messages within ksoap.

The generated messages (.Net xml output) can be read via ksoap fine.
However, I can not get ksoap to generate xml soap text that .Net can
read. 

There is one small tag difference in what the ksoap soap formatter
produces vs. .Net. I am not a soap standard expert, so perhaps someone
can quickly point out the problem and recommend a fix.

My object is called Command and the ksoap generated xml is as follows:

<xsd:Command xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" id="o0"
SOAP-ENC:root="1">
 <foo1 xsi:type="xsd:int">4</foo1>
 <foo2 xsi:type="xsd:long">8</foo2>
 <foo3 xsi:type="xsd:boolean">true</foo3>
 <foo4 xsi:type="xsd:string">My or my!</foo4>
</xsd:Command>

Ksoap can read back this xml just fine.

---NOW COME THE DETAILS THAT SHOW WHAT .NET EXPECTS, BY LOOKING AT WHAT
.NET PRODUCES---

The Java class that was used to generate the xml is as follows:

public class Command
{
	public Command ()
	{
		foo1 = 4;
		foo2 = 8;
		foo3 = true;
		foo4 = "My or my!";
	}
	
	public int foo1;
	public long foo2;
	public boolean foo3;
	public String foo4;

}

Now, I have a C# class that matches this as follows:

	[Serializable]
	public class Command
	{
		public Command()
		{
			foo1 = 4;
			foo2 = 8;
			foo3 = true;
			foo4 = "My or my!";
		}

		public int foo1;
		public long foo2;
		public bool foo3;
		public string foo4;
	}

The C# code that can't deserialize this is as follows:

public static object Deserialize (string s){
	SoapFormatter formatter = new SoapFormatter();	
	formatter.AssemblyFormat =
System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
	formatter.TypeFormat =
System.Runtime.Serialization.Formatters.FormatterTypeStyle.TypesAlways |

	
System.Runtime.Serialization.Formatters.FormatterTypeStyle.XsdString;
	StringStream stream = new StringStream();
	// Serialize an object so we can strip the body and envelope
text and use it.
	string tmp = "";
	formatter.Serialize(stream, tmp);
	tmp = stream.Buffer;
	int beginning = tmp.IndexOf("<SOAP-ENV:Body>", 0, tmp.Length) +
15;
	int end = tmp.IndexOf("</SOAP-ENV:Body>", 0, tmp.Length);
	string header = tmp.Substring(0, beginning);
	string trailer = tmp.Substring(end, tmp.Length - end);
	stream.Buffer = header + s + trailer;
	// Deserialize the string.
	return formatter.Deserialize(stream);
}

Note that .Net wants to use body and envelope so my .Net code wraps the
ksoap xml in those tags and strips it off etc...

The C# code that serializes is as follows:

public static string Serialize (object o)
{
	SoapFormatter formatter = new SoapFormatter();
	formatter.AssemblyFormat =
System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
	formatter.TypeFormat =
System.Runtime.Serialization.Formatters.FormatterTypeStyle.TypesAlways |
	
	
System.Runtime.Serialization.Formatters.FormatterTypeStyle.XsdString;
	StringStream stream = new StringStream();
	formatter.Serialize(stream, o);
	string s = stream.Buffer;
	int beginning = s.IndexOf("<SOAP-ENV:Body>", 0, s.Length) + 15;
	int end = s.IndexOf("</SOAP-ENV:Body>", 0, s.Length);
	string result = s.Substring(beginning, end-beginning);
	return result;
}

This produces (.Net) the following xml:

<a1:Command id="ref-1"
xmlns:a1="http://schemas.microsoft.com/clr/nsassem/SoapEx
periment/SoapExperiment">
<foo1 xsi:type="xsd:int">4</foo1>
<foo2 xsi:type="xsd:long">8</foo2>
<foo3 xsi:type="xsd:boolean">true</foo3>
<foo4 xsi:type="xsd:string">My or my!</foo4>
</a1:Command>

If I make the assumption that .Net wants to deserialize xml in this
form, then we have to look at the difference between this xml and ksoap
xml:

.NET

<a1:Command id="ref-1"
xmlns:a1="http://schemas.microsoft.com/clr/nsassem/SoapExperiment/SoapEx
periment">

KSOAP

<xsd:Command xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" id="o0"
SOAP-ENC:root="1">

.Net adds a new prefix called a1 and defines it based on the project
name of the code. When .Net sees the xsd prefix, it gets in a tizzy. The
error from the exception is:

Parse Error, xsd type not valid: Command. 

Note: that the deserialize code does wrap the xml show here with the
envelope and body tags before deserializing.

Should the .Net deserializer be able to handle the xsd prefix when in
the body? Is the problem that the Command tab should be differently
constructed when in a Body? Or is .Net just plain screwed up?

If the .Net expectation is within the spec, is there a way to convince
ksoap to produce the tag in the form .Net likes? I certainly did not see
one.

It seems odd that there is an asymmetry in that ksoap can read the .Net
xml, but .Net can not read the ksoap xml.

Any ideas?

Mike

PS, I would be happy to post the ksoap marshaler if anyone wants to use
it.