views:

288

answers:

2

I have a problem when attempting to serialize class on a server, send it to the client and deserialize is on the destination.

On the server I have the following two classes:

[XmlRoot("StatusUpdate")]
public class GameStatusUpdate
{
    public GameStatusUpdate()
    {}

    public GameStatusUpdate(Player[] players, Command command)
    {
        this.Players = players;
        this.Update = command;
    }

    [XmlArray("Players")]
    public Player[] Players { get; set; }

    [XmlElement("Command")]
    public Command Update { get; set; }
}

and

[XmlRoot("Player")]
public class Player
{
    public Player()
    {}

    public Player(PlayerColors color)
    {
        Color = color;
        ...
    }

    [XmlAttribute("Color")]
    public PlayerColors Color { get; set; }

    [XmlAttribute("X")]
    public int X { get; set; }

    [XmlAttribute("Y")]
    public int Y { get; set; }
}

(The missing types are all enums).

This generates the following XML on serialization:

<?xml version="1.0" encoding="utf-16"?>
<StatusUpdate>
  <Players>
    <Player Color="Cyan" X="67" Y="32" />
  </Players>
  <Command>StartGame</Command>
</StatusUpdate>

On the client side, I'm attempting to deserialize that into following classes:

[XmlRoot("StatusUpdate")]
public class StatusUpdate
{
    public StatusUpdate()
    {

    }

    [XmlArray("Players")]
    [XmlArrayItem("Player")]
    public PlayerInfo[] Players { get; set; }

    [XmlElement("Command")]
    public Command Update { get; set; }
}

and

[XmlRoot("Player")]
public class PlayerInfo
{
    public PlayerInfo()
    {
    }

    [XmlAttribute("X")]
    public int X { get; set; }

    [XmlAttribute("Y")]
    public int Y { get; set; }

    [XmlAttribute("Color")]
    public PlayerColor Color { get; set; }
}

However, the deserializer throws an exception:

There is an error in XML document (2, 2).
<StatusUpdate xmlns=''> was not expected.

What am I missing or doing wrong?

EDIT:

On request I'm also adding code used to serialize and deserialize:

Server:

    public static byte[] SerializeObject(Object obj)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());
        StringWriter writer = new StringWriter();

        // Clear pre-defined namespaces
        XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
        xsn.Add("", "");

        xmlSerializer.Serialize(writer, obj, xsn);
        writer.Flush();

        // Send as little-endian UTF-16 string because the Serializer denotes XML as 
        // utf-18 which cannot be easly changed
        UnicodeEncoding encoder = new UnicodeEncoding(false, false);
        return encoder.GetBytes(writer.ToString());
    }

Client:

    public static object DeserializeXml(string xmlData, Type type)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(type);


        StringReader reader = new StringReader(xmlData);
        object obj = xmlSerializer.Deserialize(reader);

        return obj;
    }

Deserialization is invoked with

StatusUpdate update = (StatusUpdate) Util.DeserializeXml(xmlData, typeof (StatusUpdate));
A: 

That's actually highly unusual to see when using the XmlSerializer. The root element should always look like this:

<MyClass 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;

(Correction: The XmlSerializer does appear to work without these on deserialization, but it always adds them on serialization, so something's fishy if they're missing.)

Second edit:

I strongly suspect that your issue is encoding-related. I don't know why you have to mess with the serialization so much and can't just use the default UTF-8 encoding, but regardless, the following code works without any errors:

MyClass m = new MyClass() { X = 4, Y = 8 };
byte[] data = SerializeObject(m);
string xml = Encoding.Unicode.GetString(data);
Console.WriteLine(xml);
m = (MyClass)DeserializeXml(xml, typeof(MyClass));

So if something is failing for you, it's very likely going wrong during the conversion of byte array to XML string on the client side. That's the only code you still haven't posted.

Aaronaught
A: 

After alot of testing I have finally found an error. It was not an encoding problem, neither was the problem in the other code nor it was the missing namespace.

The missing part was the annotation for type of objects in the array when deserializing.

So I had to change my StatusUpdate class to

[XmlRoot("StatusUpdate")]
public class StatusUpdate
{
    public StatusUpdate()
    {

    }

    [XmlArray("Players"), XmlArrayItem(ElementName = "Player", Type = typeof(PlayerInfo))]
    public PlayerInfo[] Players { get; set; }

    [XmlElement("Command")]
    public ServerCommand Update { get; set; }
}

and serialization started working perfectly.

I hope that helps someone else.

Mavrik