complex types in a Web service

W

William F. Kinsley

I'm trying to use complex types in a Web service as follows:

// In Some Util Library
[Serializable]
public class PatientFilter
{
....
}

[Serializable]
public class PatientCollection : IEnumerable
{
....
}

// In the webservice asmx.cs
[WebMethod]
public PatientCollection GetPatients(PatientFilter filter)
{
....
}


So this all works great, except that on the client side, after adding a web
reference, two things happen that aren't so good.

The first is that another PatientFilter class is auto generated in the
Reverence.cs in the WebReference namespace. This causes type problems
between the original PatientFilter class and the one in the Reference.cs. A
solution to this is to delete the auto generated class in Reference.cs and
everything works, but this is annoying as the class is constantly being
regenerated and I'm pretty sure there's a better way. When using a DataSet
class as a parameter, the auto generating tool does not make a new class in
Reference.cs. As best I can guess this is because the WSDL defines the
DataSet parameter as:

<s:complexType>
<s:sequence>
<s:element ref="s:schema" />
<s:any />
</s:sequence>
</s:complexType>


So my 1st question is how do I get my class to do the same, or similar thing
so that a new class does not get auto generated in Reference.cs


The second thing that happens that is annoying is that the GetPatients()
returns an object[] instead of a PatientCollection in the WebReference
class. Again, editing the Reference.cs and replacing the object[] return
parameter with PatientCollection fixes the problem and everything works.
The WSDL for this return value ends up being:
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetPatientsResult"
type="tns:ArrayOfAnyType" />
</s:sequence>
</s:complexType>

So my second question is how do I get the method to return a
PatientCollection instead of an ArrayOfAnyType automatically in the auto
generated class.
 
S

Steven Cheng[MSFT]

Hi William,

Welcome to the MSDN newsgroup.

As for the two question you mentioned, here are some of my understanding
and suggestion:

1.So my 1st question is how do I get my class to do the same, or similar
thing
so that a new class does not get auto generated in Reference.cs
===============================
This is a bit hard since the client webservice proxy generate the types
according to the webservice's WSDL document. And WSDL document use XML
schema's standard types to represent different object types used in
webservice methods, this is for interop consideration since the webservice
will be consumed by different client platform (c++, java, php.....). And
for list/collection like type, WSDL will always use SOAP Array to represent
it, thus the .NET client proxy will generate the Array for such
objects(parameter or return type). If you do need to use .NET specific
type, you need to manually change the client genernated proxy code.


2.So my second question is how do I get the method to return a
PatientCollection instead of an ArrayOfAnyType automatically in the auto
generated class.
===============================
I think this is likely caused by the custom collection class you used only
implement IEnumerable interface which is not sufficient to let the ASP.NET
webservice engine automatically use SOAP Array to represent it in WSDL. I
think you can consider the following means:

1) Instead of only implment IEnumerable, you can consider make the
colleciton class derived from CollectionBase class and implements those
methods. Such collectionbase derived class will be represend by SOAP
Array(of certain custom class type) automatically in WSDL document.


2) You can also try explicitly apply the following attribute in your
webmethod to indicate that the return type of the webmethod is an Array
(and the Array item's type). For example:

[WebMethod]
[return:XmlArray()]
[return:XmlArrayItem(typeof(User))]
public UserCollection GetWebUsers(int count)
{
...............
}


Hope this helps.

Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
W

William F. Kinsley

Hi Steven,

I understand that the WSDL specifies the complex types for interop purposes,
however it does not do this for the DataSet type, yet the Reference.cs file
still manages to type it to a DataSet. So my question #1 is really how do I
do what the DataSet (and some other .net types) are doing?

As for question #2, having it return an array of Patients types isn't what
I'm looking for, I want the return type in the Reference.cs to actually be
my original type (without of course another proxy class from question #1,
but that's a separate issue). So is there an attribute that will change the
return type to be my class in the WSDL?

Thanks





Steven Cheng said:
Hi William,

Welcome to the MSDN newsgroup.

As for the two question you mentioned, here are some of my understanding
and suggestion:

1.So my 1st question is how do I get my class to do the same, or similar
thing
so that a new class does not get auto generated in Reference.cs
===============================
This is a bit hard since the client webservice proxy generate the types
according to the webservice's WSDL document. And WSDL document use XML
schema's standard types to represent different object types used in
webservice methods, this is for interop consideration since the webservice
will be consumed by different client platform (c++, java, php.....). And
for list/collection like type, WSDL will always use SOAP Array to
represent
it, thus the .NET client proxy will generate the Array for such
objects(parameter or return type). If you do need to use .NET specific
type, you need to manually change the client genernated proxy code.


2.So my second question is how do I get the method to return a
PatientCollection instead of an ArrayOfAnyType automatically in the auto
generated class.
===============================
I think this is likely caused by the custom collection class you used only
implement IEnumerable interface which is not sufficient to let the ASP.NET
webservice engine automatically use SOAP Array to represent it in WSDL.
I
think you can consider the following means:

1) Instead of only implment IEnumerable, you can consider make the
colleciton class derived from CollectionBase class and implements those
methods. Such collectionbase derived class will be represend by SOAP
Array(of certain custom class type) automatically in WSDL document.


2) You can also try explicitly apply the following attribute in your
webmethod to indicate that the return type of the webmethod is an Array
(and the Array item's type). For example:

[WebMethod]
[return:XmlArray()]
[return:XmlArrayItem(typeof(User))]
public UserCollection GetWebUsers(int count)
{
...............
}


Hope this helps.

Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
S

Steven Cheng[MSFT]

Thanks for your response William,

So the further question you mentioned all aims at make the autogenerated
client proxy use our custom class type(.NET specific). I'm afraid this is
not available through the buildin webservice client proxy genenration
tool(wsdl.exe). The DataSet class you mentioned is a particular class(which
is somewhat hardcoded in the wsdl.exe tool's generation logic since there
is not particular attributes in description for DataSet as we can see).
I've tried DataTable class also which can not be recognized.
I think for your scenario, it is more likely that you're going to build a
custom webservice client proxy generation tool rather than extend the
current one. Anyway, currently the simplest means is to modify the
autogenerated proxy class code.

Regards,

Steven Cheng
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
J

Javier G. Lozano

Have you tried controlling the XML serialization for your classes using
the attributes under the System.Xml.Serialization namespace? I've
written web services that return lists and are represented as arrays on
the client (why? You're actually exchange a contract (collection of
objects) rather than a type (IEnumerable)).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,815
Latest member
treekmostly22

Latest Threads

Top