Dear all,
I am having trouble generating a client proxy for a webservice whose
methods return a "complex" type. The type is complex in that it is a
class whose members are a mix of primitive types and of more elaborate
classes implementing IXmlSerializabl e. The resulting WSDL file for the
webservice has two separate schemas in its <types> sections, and the
client proxy (generated with wsdl.exe) is missing the definitions of
the IXmlSerializabl e types. More details follow.
I could reproduce the problem with a simple example. The webservice is
called WSTest.Service1 @ http://localhost/WSTest/Service1.asmx, and it
has a method called HelloWorld.
Here is the Service1.asmx file (hope the formatting won't go wild):
------------------------------------------------
using System;
using System.Collecti ons;
using System.Componen tModel;
using System.Data;
using System.Diagnost ics;
using System.Web;
using System.Web.Serv ices;
using System.Xml;
using System.Xml.Seri alization;
using System.Xml.Sche ma;
namespace WSTest
{
// This is the IXmlSerializabl e derivative, member of the webmethod's
actual return type
public class WSTestDetail: IXmlSerializabl e
{
// Class data
public string Code;
public string Description;
// IXmlSerializabl e implementation
public void WriteXml (XmlWriter writer)
{
// ...
}
public void ReadXml (XmlReader reader)
{
// ...
}
public XmlSchema GetSchema ()
{
XmlSchemaSequen ce seq = new XmlSchemaSequen ce ();
XmlSchemaElemen t element;
element = new XmlSchemaElemen t ();
element.Name = "Code";
element.SchemaT ypeName = new XmlQualifiedNam e ("string",
"http://www.w3.org/2001/XMLSchema");
element.MinOccu rs = 0;
element.MaxOccu rs = 1;
seq.Items.Add (element);
element = new XmlSchemaElemen t ();
element.Name = "Descriptio n";
element.SchemaT ypeName = new XmlQualifiedNam e ("string",
"http://www.w3.org/2001/XMLSchema");
element.MinOccu rs = 0;
element.MaxOccu rs = 1;
seq.Items.Add (element);
XmlSchemaComple xType type = new XmlSchemaComple xType ();
type.Particle = seq;
type.Name = "WSTestDetailTy pe";
XmlSchemaElemen t root = new XmlSchemaElemen t ();
root.Name = "WSTestDeta il";
root.SchemaType Name = new XmlQualifiedNam e ("WSTestDetailT ype",
"http://www.testme.org/types");
XmlSchema schema = new XmlSchema ();
schema.Id = "WSTestDetailSc hema";
schema.TargetNa mespace = "http://www.testme.org/types";
schema.Namespac es.Add ("xs", "http://www.w3.org/2001/XMLSchema");
schema.Items.Ad d (type);
schema.Items.Ad d (root);
return schema;
}
}
// This is the return type of the webmethod
public class WSTestResult
{
public WSTestDetail Detail;
public string Status;
}
/// <summary>
/// Summary description for Service1.
/// </summary>
[WebService(Name space="http://www.testme.org/ws")]
public class Service1 : System.Web.Serv ices.WebService
{
public Service1()
{
InitializeCompo nent();
}
#region Component Designer generated code
// ...
#endregion
[WebMethod]
public WSTestResult HelloWorld()
{
return new WSTestResult ();
}
}
}
------------------------------------------------
The WSDL document (Service1.wsdl) :
------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitio ns xmlns:s1="http://www.testme.org/types"
xmlns:http="htt p://schemas.xmlsoap .org/wsdl/http/"
xmlns:soap="htt p://schemas.xmlsoap .org/wsdl/soap/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soapenc=" http://schemas.xmlsoap .org/soap/encoding/"
xmlns:tns="http ://www.testme.org/ws"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:mime="htt p://schemas.xmlsoap .org/wsdl/mime/"
targetNamespace ="http://www.testme.org/ws"
xmlns:wsdl="htt p://schemas.xmlsoap .org/wsdl/">
<wsdl:types>
<s:schema elementFormDefa ult="qualified"
targetNamespace ="http://www.testme.org/ws">
<s:import namespace="http ://www.testme.org/types" />
<s:element name="HelloWorl d">
<s:complexTyp e />
</s:element>
<s:element name="HelloWorl dResponse">
<s:complexTyp e>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1"
name="HelloWorl dResult" type="tns:WSTes tResult" />
</s:sequence>
</s:complexType>
</s:element>
<s:complexTyp e name="WSTestRes ult">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="Detail">
<s:complexTyp e>
<s:sequence>
<s:any namespace="http ://www.testme.org/types" />
</s:sequence>
</s:complexType>
</s:element>
<s:element minOccurs="0" maxOccurs="1" name="Status"
type="s:string" />
</s:sequence>
</s:complexType>
</s:schema>
<s:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace ="http://www.testme.org/types" id="WSTestDetai lSchema">
<xs:complexTy pe name="WSTestDet ailType">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Code"
type="xs:string " />
<xs:element minOccurs="0" maxOccurs="1" name="Descripti on"
type="xs:string " />
</xs:sequence>
</xs:complexType>
<xs:element name="WSTestDet ail" type="s1:WSTest DetailType" />
</s:schema>
</wsdl:types>
<wsdl:message name="HelloWorl dSoapIn">
<wsdl:part name="parameter s" element="tns:He lloWorld" />
</wsdl:message>
<wsdl:message name="HelloWorl dSoapOut">
<wsdl:part name="parameter s" element="tns:He lloWorldRespons e" />
</wsdl:message>
<wsdl:portTyp e name="Service1S oap">
<wsdl:operati on name="HelloWorl d">
<wsdl:input message="tns:He lloWorldSoapIn" />
<wsdl:output message="tns:He lloWorldSoapOut " />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="Service1S oap" type="tns:Servi ce1Soap">
<soap:binding transport="http ://schemas.xmlsoap .org/soap/http"
style="document " />
<wsdl:operati on name="HelloWorl d">
<soap:operati on soapAction="htt p://www.testme.org/ws/HelloWorld"
style="document " />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="Service1" >
<documentatio n xmlns="http://schemas.xmlsoap .org/wsdl/" />
<wsdl:port name="Service1S oap" binding="tns:Se rvice1Soap">
<soap:address location="http://localhost/WSTest/Service1.asmx" />
</wsdl:port>
</wsdl:service>
</wsdl:definition s>
------------------------------------------------
As you can see, with WSTestDetail providing its own GetSchema()
implementation, we have 2 <schema>'s in the WSDL.
WSTestResult.De tail has a strange declaration: instead of the expected
<s:element name="Detail" type="s1:WSTest DetailType">, I get a
complexType/sequence/any specification. Why not; the 2nd schema has
only one toplevel element so I guess that's fine and leads to no
ambiguities.
Now the client proxy (wsdl.exe Service1.wsdl):
------------------------------------------------
using System.Diagnost ics;
using System.Xml.Seri alization;
using System;
using System.Web.Serv ices.Protocols;
using System.Componen tModel;
using System.Web.Serv ices;
/// <remarks/>
[System.Diagnost ics.DebuggerSte pThroughAttribu te()]
[System.Componen tModel.Designer CategoryAttribu te("code")]
[System.Web.Serv ices.WebService BindingAttribut e(Name="Service 1Soap",
Namespace="http ://www.testme.org/ws")]
public class Service1 :
System.Web.Serv ices.Protocols. SoapHttpClientP rotocol {
/// <remarks/>
public Service1() {
this.Url = "http://localhost/WSTest/Service1.asmx";
}
/// <remarks/>
[System.Web.Serv ices.Protocols. SoapDocumentMet hodAttribute("h ttp://www.testme.org/ws/HelloWorld",
RequestNamespac e="http://www.testme.org/ws",
ResponseNamespa ce="http://www.testme.org/ws",
Use=System.Web. Services.Descri ption.SoapBindi ngUse.Literal,
ParameterStyle= System.Web.Serv ices.Protocols. SoapParameterSt yle.Wrapped)]
public WSTestResult HelloWorld() {
object[] results = this.Invoke("He lloWorld", new object[0]);
return ((WSTestResult) (results[0]));
}
/// <remarks/>
public System.IAsyncRe sult BeginHelloWorld (System.AsyncCa llback
callback, object asyncState) {
return this.BeginInvok e("HelloWorld ", new object[0], callback,
asyncState);
}
/// <remarks/>
public WSTestResult EndHelloWorld(S ystem.IAsyncRes ult asyncResult)
{
object[] results = this.EndInvoke( asyncResult);
return ((WSTestResult) (results[0]));
}
}
/// <remarks/>
[System.Xml.Seri alization.XmlTy peAttribute(Nam espace="http://www.testme.org/ws")]
public class WSTestResult {
/// <remarks/>
public WSTestDetailSch ema Detail;
/// <remarks/>
public string Status;
}
------------------------------------------------
WSTestResult.De tail's type is named WSTestDetailSch ema (I would have
expected WSTestDetailTyp e), but again, why not. The missing type
declaration for WSTestDetailSch ema is much more annoying as this makes
the WSDL useless for clients.
Is there any reason why this is happening? Why do I have 2 schemas in
my WSDL? How can I ask that WSTestResult.De tail be of type
s1:WSTestDetail Type in the WSDL? Since the class in Service1.asmx
implements IXmlSerializabl e, I cannot use Xml serialization attributes
like XmlType. The interface is needed because we want to have fine
control on the serialization.
I hope the question is not too stupid. The thing is, I'm not too
familiar with schemas, namespaces and such. Also, we're in 1.1 and
IXmlSerializabl e is not very well documented.
Thanks in advance!
Best regards,
Thomas