IXmlSerializable: return type & difference IE / webservice

T

Thomas D.

Hello all,

I'm using the IXmlSerializable interface for a project and encounter some
problems when testing my webservice in a client application. I know this
interface is undocumented and not intended for use, but I think this is the
only solution for my situation. I searched the web, in the hope finding the
answer, without any luck, so my final hope is with you.

Let me explain the situation:
I have an 'export'-wrapper to my regular objects. For each regular object
there is also an export object. An export object derives from the regular
object and has for each property in the base object an extra boolean
property. That extra property tells wether to include the base property in
the final export (= webservice) or not. That is because not all the
properties may be exposed all the time (depending on who is requesting it).
To implement this I have used the IXmlSerializable interface on the export
objects. Another reason I used the IXmlSerializable interface is that I can
choose the xml element names, especially for the collections (so I don't get
ArrayOf.....). The webservice returns export collection objects (implementing
IXmlSerializable).

To test my webservice I created a simple WinForms application which calls
one of the webmethods. But when adding the Web Reference to my test
application the proxy is not well generated. The return type of the webmethod
is not my export collection type, but a DataSet. I can work around that issue
if I let my webmethod only return a 'single' object instead of a collection:
I just changed the return type in the generated proxy to my custom collection
type. But then I needed to add an extra reference to my project; that is a
reference to the assambly which holds the export objects.

I've tried the same thing to return my custom collection, but that does not
work unless I do not implement the IXmlSerializable interface on the
collection. If I do that, I lose the ability to choose a custom xml element
name. When I implement the IXmlSerializable interface I get this error:
An unhandled exception of type 'System.InvalidOperationException' occurred
in system.web.services.dll
Additional information: Method Export.GetTest can not be reflected.

I do not understand why this does not work. I get the correct results when I
open the .asmx page in Internet Explorer, even with the IXmlSerializable
interface implemented on the collections. If it works in IE, why does it not
work when generating the proxy? Does someone knows what is going wrong here
or what I am doing wrong? This problem holds me from going to the next phase
of the project. Any help is appreciated!

Below you can find a stripped code example of my situation.


Thanks in advance and best regards,
Thomas



My code:
---------------------------
I have stripped down the code here for simplicity. My export class does not
derive from any base class, nor does it have the booleans. However when I try
the code below I still have the same problem.


// this is the export object which normally derives from 'Test'.
[Serializable]
public class TestExport : IXmlSerializable
{
private string name;
private string email;

public TestExport()
{
}

public string Name
{
get { return name; }
set { name = value; }
}

public string Email
{
get { return email; }
set { email = value; }
}

#region IXmlSerializable
public XmlSchema GetSchema()
{
return null;
}

public void ReadXml(XmlReader reader)
{
// Read the opening tag of the encapsulating element
reader.ReadStartElement();

// Open the root element for our object
reader.ReadStartElement("Test");

reader.ReadStartElement("Name");
this.Name = reader.ReadString();
reader.ReadEndElement();

reader.ReadStartElement("Email");
this.Email = reader.ReadString();
reader.ReadEndElement();

// Close the root element for our object
reader.ReadEndElement();

// Read the end tag of the encapsulating element
reader.ReadEndElement();
}

public void WriteXml(XmlWriter writer)
{
writer.WriteStartElement("Test");
writer.WriteElementString("Name", this.Name);
writer.WriteElementString("Email", this.Email);
writer.WriteEndElement();
}
#endregion
}


[Serializable]
public class TestenExport : CollectionBase, IXmlSerializable
{
public TestenExport()
{
}

#region IXmlSerializable
public XmlSchema GetSchema()
{
return null;
}

public void ReadXml(XmlReader reader)
{
// Read the opening tag of the encapsulating element
reader.ReadStartElement();

// Open the root element for our object
reader.ReadStartElement("Tests");

foreach(TestExport item in this)
{
item.ReadXml(reader);
}

// Close the root element for our object
reader.ReadEndElement();

// Read the end tag of the encapsulating element
reader.ReadEndElement();
}

public void WriteXml(XmlWriter writer)
{
writer.WriteStartElement("Tests");
foreach(TestExport item in this)
{
item.WriteXml(writer);
}
writer.WriteEndElement();
}
#endregion

#region CollectionBase
public int Add(TestExport @value)
{
return List.Add(@value);
}

public TestExport this[int index]
{
get
{
return (TestExport)(List[index]);
}
set
{
List[index] = value;
}
}
#endregion
}
 
T

Thomas D.

[SNIP]
I've tried the same thing to return my custom collection, but that does not
work unless I do not implement the IXmlSerializable interface on the
collection. If I do that, I lose the ability to choose a custom xml element
name. When I implement the IXmlSerializable interface I get this error:
An unhandled exception of type 'System.InvalidOperationException' occurred
in system.web.services.dll
Additional information: Method Export.GetTest can not be reflected.

I have found the problem for this. My ReadXml() method in the collection was
not correct. Here is what I use now:

public void ReadXml(XmlReader r)
{
r.Read(); // move past container
r.ReadStartElement("Testen");
while (r.NodeType != XmlNodeType.EndElement)
{
r.ReadStartElement("Test");
string name = r.ReadElementString("Name");
string email = r.ReadElementString("Email");
string company = r.ReadElementString("Company");
r.ReadEndElement();
this.Add(new TestExport(name, email, company));
}
r.ReadEndElement();
}

I still need to add a reference to my 'Export objects'-assembly and manually
change the return types in the proxy. The proxy does not recognize the used
types itself! This means I will need to manually change the proxy each time
the webservice changes. Anyone has a solution for this?
 

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,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top