views:

196

answers:

2

Hi!

I want to be able to send a XmlSerializer class (which is generated obvious in remote C# application) over a WebService that will then deserialize it into a class. (I didnt know it its possible either)

My class is:

SystemInfo

I'm serializing it this way:

        XmlSerializer mySerializer = new XmlSerializer(typeof(SystemInfo));
        StreamWriter myWriter = new StreamWriter(textBox1.Text);
        mySerializer.Serialize(myWriter, sysinfo);

How can i build the WebService?

    [WebMethod]
    public void Reports(XmlSerializer xmlSerializer)
    {
      .
      .
      .
    }

Can anyone help me out?

Regards

+3  A: 

First I assume you want to pass arbitrary types to a single web method, where the types are shared by the client and the server.

There is not much point in sending the XmlSerializer, it only has the logic to serialize/deserialize. It does not have the actual data, that is either read/written to a stream. What you should do is pass either a string or and XmlNode.

The caller of the web service can then a client side instance of XmlSerializer and serialize the object to a string, then call the web method passing the string as an argument. The web method it self can then create an instance of a XmlSerializer and deserialize the string back into an object. Of course to create the server size instance of the serializer you will need to know the root type to create the serializer for, you can pass this as a type name and use Type.GetType() to get the correct type to pass to the XmlSerializer.

If you know upfront which types you are going to be passing then you could also declare your web method more strongly typed and explicitly create methods for the types you expect to recieve.

If the wire format is not too much of a concern, you could also user SoapFormatter or a BinaryFormatter to handle the serialization/deserialization. In the later case of the BinaryFormatter you would declare your web method to take a byte[] argument, the advantage of these formatters (serializers) is that they do not need additional info on the type when you create the instance of the formatter, but they can be slower than an XmlSerializer

Update: Added some simple examples (Untested)

Example using an XmlSerializer, here you will need to pass the type name from the client side, so I made it an additional argument.

[WebMethod]
public void Reports(string xml, string typeName)
{
  XmlSerializer xs = new XmlSerializer(Type.GetType(typeName));
  object obj = xs.Deserialize(new StringReader(xml));
  // use the deserialize object
}

Example using a BinaryFormatter, no type name needed but you the class types will need to be serializable

[WebMethod]
public void Reports(byte[] data)
{
  BinaryFormatter bf = new BinaryFormatter();
  object obj = bf.Deserialize(new MemoryStream(data));
  // use the deserialized object
}

On the client side you would use something like the following to serialize using the BinaryFormatter.

  // initialize the SystemInfo instance that you want to pass to the server
  SystemInfo si = new SystemInfo() { SystemName = "My System" };

  // Serialize to a memory stream
  BinaryFormatter bf = new BinaryFormatter();
  MemoryStream ms = new MemoryStream();
  bf.Serialize(ms, si);

  // Call the service, passing the array from the memory stream
  ws.Reports(ms.ToArray());
Chris Taylor
Hmm, makes sense now :) can you give me an example of doing that after the serialize being done?
pee2002
@pee2002, sorry was editing when your comment came in, I will add some simple examples now.
Chris Taylor
Sorry, didnt work :\ It gives me the error: "The input stream is not a valid binary format. The starting contents (in bytes) are: 3C-3F-78-6D-6C-20-76-65-72-73-69-6F-6E-3D-22-31-2E ..."
pee2002
@pee2002, you will need to share your serialization code, I added a quick sample of how to use the BinaryFormatter on the client side.
Chris Taylor
A: 

Chris, thanks for helping me out. It was a major step forward.

I solved the problem sending the xml string:

        SystemInfo sysinfo = new SystemInfo();
        sysinfo.RUN();

        XmlSerializer mySerializer = new XmlSerializer(typeof(SystemInfo));

        MemoryStream memStream = new MemoryStream();
            mySerializer.Serialize(memStream, sysinfo);
            memStream.Seek(0, System.IO.SeekOrigin.Begin);
            XmlDocument doc = new XmlDocument();
            doc.Load(memStream);
        memStream.Close();

        localhost.WS_Agente dasdsa = new localhost.WS_Agente();
        dasdsa.Reports(doc.InnerXml);

And the WebService:

    [WebMethod]
    public void Reports(string xml)
    {
        XmlSerializer mySerializer = new XmlSerializer(typeof(SystemInfo));
        SystemInfo obj = (SystemInfo)mySerializer.Deserialize(new StringReader(xml));
    }

Its working like a charm now :)

My question is: Can i improve the code?

Thanks

pee2002
Looking at your solution, I think this points to the question in my answer "If you know upfront which types you are going to be passing then you could also declare your web method more strongly typed and explicitly create methods for the types you expect to recieve". Since your code is hardcoded to work with SystemInfo, why now just make the method accept an argument of that type? [WebMethod] public void Reports(SystemInfo si) {...}. You should only need the serialization if the argument was dynamic in nature?
Chris Taylor
To answer your other question, your client code could be a little simpler by using a StringWriter. Like this XmlSerializer xs = new XmlSerializer(typeof(SystemInfo)); StringWriter sw = new StringWriter(); xs.Serialize(sw, si); ws.Reports(sw.ToString());
Chris Taylor
Thank you so much! Now its great! You are the man!
pee2002
@pee2002, it is a pleasure. I am glad this helped!
Chris Taylor