deniszykov / msgpack-unity3d

MessagePack and JSON serializer for Unity3D
MIT License
102 stars 14 forks source link

Failed to read value for member. #13

Open Janry opened 7 years ago

Janry commented 7 years ago

Hi, I have some problem with deserialization on ios.

System.Runtime.Serialization.SerializationException: Failed to read value for member 'Decorations' of 'Info' type. More detailed information in inner exception. ---> System.TypeLoadException: A type load exception has occurred. at System.Type.GetType (System.String typeName, Boolean throwOnError, Boolean ignoreCase) [0x00000] in :0 at GameDevWare.Serialization.SerializationContext.GetType (System.String name, Boolean throwOnError, Boolean ignoreCase) [0x00000] in :0 at GameDevWare.Serialization.Serializers.ObjectSerializer.DeserializeMembers (IJsonReader reader, GameDevWare.Serialization.IndexedDictionary2 container, GameDevWare.Serialization.Serializers.ObjectSerializer& serializerOverride) [0x00000] in <filename unknown>:0 at GameDevWare.Serialization.Serializers.ObjectSerializer.Deserialize (IJsonReader reader) [0x00000] in <filename unknown>:0 at GameDevWare.Serialization.JsonReaderExtentions.ReadValue (IJsonReader reader, System.Type valueType, Boolean nextToken) [0x00000] in <filename unknown>:0 at GameDevWare.Serialization.Serializers.ArraySerializer.Deserialize (IJsonReader reader) [0x00000] in <filename unknown>:0 at GameDevWare.Serialization.JsonReaderExtentions.ReadValue (IJsonReader reader, System.Type valueType, Boolean nextToken) [0x00000] in <filename unknown>:0 at GameDevWare.Serialization.Serializers.ObjectSerializer.DeserializeMembers (IJsonReader reader, GameDevWare.Serialization.IndexedDictionary2 container, GameDevWare.Serialization.Serializers.ObjectSerializer& serializerOverride) [0x00000] in :0 at GameDevWare.Serialization.Serializers.ObjectSerializer.DeserializeMembers (IJsonReader reader, GameDevWare.Serialization.IndexedDictionary`2 container, GameDevWare.Serialization.Serializers.ObjectSerializer& serializerOverride) [0x00000] in :0 at GameDevWare.Serialization.Serializers.ObjectSerializer.Deserialize (IJsonReader reader) [0x00000] in :0 at GameDevWare.Serialization.JsonReaderExtentions.ReadValue (IJsonReader reader, System.Type valueType, Boolean nextToken) [0x00000] in :0 at GameDevWare.Serialization.MsgPack.Deserialize[T] (System.IO.Stream msgPackInput, GameDevWare.Serialization.SerializationContext context) [0x00000] in :0

[Serializable]
public class Info
{
    public Decoration[] Decorations;
}

[Serializable]
public class Decoration
{
    public Point<byte> Position;
}

[Serializable]
public class Point<TCoord> where TCoord : struct
{
    public TCoord X;
    public TCoord Y;
}

For fixed it the problem I added custom serializer and registered it in Json.DefaultSerializers.

public sealed class PointByteSerializer : TypeSerializer
{
    public override Type SerializedType { get { return typeof(Point<byte>); } }

    public override object Deserialize(IJsonReader reader)
    {
        if (reader == null) throw new ArgumentNullException("reader");

        if (reader.Token == JsonToken.Null)
            return null;

        var value = new Point<byte>();

        reader.ReadObjectBegin();
        while (reader.Token != JsonToken.EndOfObject)
        {
            var memberName = reader.ReadMember();
            switch (memberName)
            {
                case "X": value.X = reader.ReadByte(); break;
                case "Y": value.Y = reader.ReadByte(); break;
                default: reader.ReadValue(typeof(object)); break;
            }
        }
        reader.ReadObjectEnd(nextToken: false);
        return value;
    }

    public override void Serialize(IJsonWriter writer, object value)
    {
        if (writer == null) throw new ArgumentNullException("writer");
        if (value == null) throw new ArgumentNullException("value");

        var point = (Point<byte>)value;
        writer.WriteObjectBegin(2);
        writer.WriteMember("X");
        writer.Write(point.X);
        writer.WriteMember("Y");
        writer.Write(point.Y);
        writer.WriteObjectEnd();
    }
}

but it didn't solve. Can you help, please?

deniszykov commented 7 years ago

Hi, probably you have different BCL assemblies on serialization and de-serialization endpoints. Are you using .NET Core or some WinRT runtime?

Janry commented 7 years ago

Unity (5.6.2f1) Project Settings for ios build: Scripting Backend: IL2CPP Api Compatibility Level: .NET 2.0

Server: .NET Framework 3.5

deniszykov commented 7 years ago

Hmmm. Could you provide MessagePack serialized data for test? The same which gives you exception above.

deniszykov commented 7 years ago

Also could you try this commit 268ef86f3aece2e19608473a01f1cd39322f916a (last one in this repository)?

Janry commented 7 years ago

So, about serialized data for the test.

ErrorSystem.Exception: Can`t parse packet, length:138 new byte[] { 131, 165, 95, 116, 121, 112, 101, 187, 80, 114, 111, 116, 111, 99, 111, 108, 46, 84, 101, 115, 116, 73, 110, 102, 111, 44, 32, 80, 114, 111, 116, 111, 99, 111, 108, 163, 85, 73, 68, 217, 36, 101, 52, 56, 51, 52, 54, 99, 99, 45, 101, 54, 52, 49, 45, 52, 102, 55, 52, 45, 57, 99, 55, 100, 45, 51, 57, 52, 54, 54, 51, 99, 102, 55, 56, 55, 51, 171, 68, 101, 99, 111, 114, 97, 116, 105, 111, 110, 115, 145, 130, 165, 95, 116, 121, 112, 101, 184, 80, 114, 111, 116, 111, 99, 111, 108, 46, 68, 101, 99, 111, 114, 44, 32, 80, 114, 111, 116, 111, 99, 111, 108, 168, 80, 111, 115, 105, 116, 105, 111, 110, 130, 161, 88, 0, 161, 89, 13 } ---> System.Runtime.Serialization.SerializationException: Failed to read value for member 'Decorations' of 'TestInfo' type.

public class Point<TCoord> where TCoord : struct
{
    public TCoord X;
    public TCoord Y;
}

public class Decor
{
    public Point<byte> Position;
}

public class TestInfo : ServerPacket
{
    public Decor[] Decorations;
}

Decor and TestInfo have a Protocol namespace and Point - Protocol.Types.

{ "$type": "Protocol.TestInfo, Protocol", "Decorations": [ { "$type": "Protocol.Decor, Protocol", "Position": { "$type": "Protocol.Types.Point`1[[System.Byte, mscorlib]], Protocol", "X": 0, "Y": 13 } } ] }

deniszykov commented 7 years ago

Thanks for test data! I will check it.

deniszykov commented 7 years ago

Actually in your test data there is no type information for Point type. Here is ASCII: "??_type?Protocol.TestInfo, Protocol?UID?$e48346cc-e641-4f74-9c7d-394663cf7873?Decorations???_type?Protocol.Decor, Protocol?Position??X\u0000?Y\u000D".

As workaround you could suppress all type information in your messages until inheritance or serialization by the base type (like object values in dictionaries) being involved. This will be faster and safer from security concern.

MsgPack.Serialize(... SerializationOptions.SuppressTypeInformation);

Janry commented 7 years ago

There is no type information for Point type because I used custom serializer, I think.

Here's the example which gives the exception too.

public class Decoration
{
    public int BuildingId;
    public Point<byte> Position;
}

namespace Protocol.CityBuilder

[131][165]_type[217])Protocol.CityBuilder.Decoration, Protocol[170]BuildingId[209][1][245][168]Position[131][165]_type[217]9Protocol.Types.Point`1[[System.Byte, mscorlib]], Protocol[161]X[0][161]Y[13]

{131, 165, 95, 116, 121, 112, 101, 217, 41, 80, 114, 111, 116, 111, 99, 111, 108, 46, 67, 105, 116, 121, 66, 117, 105, 108, 100, 101, 114, 46, 68, 101, 99, 111, 114, 97, 116, 105, 111, 110, 44, 32, 80, 114, 111, 116, 111, 99, 111, 108, 170, 66, 117, 105, 108, 100, 105, 110, 103, 73, 100, 209, 1, 245, 168, 80, 111, 115, 105, 116, 105, 111, 110, 131, 165, 95, 116, 121, 112, 101, 217, 57, 80, 114, 111, 116, 111, 99, 111, 108, 46, 84, 121, 112, 101, 115, 46, 80, 111, 105, 110, 116, 96, 49, 91, 91, 83, 121, 115, 116, 101, 109, 46, 66, 121, 116, 101, 44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 93, 93, 44, 32, 80, 114, 111, 116, 111, 99, 111, 108, 161, 88, 0, 161, 89, 13}

deniszykov commented 7 years ago

I can't repoduce it on iOS and IL2CPP. Are you sure Packet types are not stripped ('Protocol' assembly is specified in link.xml) and strong linked (has references) to Unity's project assembles?

Janry commented 7 years ago

'Protocol' assembly didn't specify in link.xml. I have problem just with generic type Point. I will try it and write about a result.

Janry commented 7 years ago

Should I use your last commit for the check is it stable changes?

deniszykov commented 7 years ago

Try last one. It has better error messages.

-----Original Message----- From: "Vladimir" notifications@github.com Sent: ‎10/‎9/‎2017 3:58 PM To: "deniszykov/msgpack-unity3d" msgpack-unity3d@noreply.github.com Cc: "deniszykov" deniszykov@gmail.com; "Comment" comment@noreply.github.com Subject: Re: [deniszykov/msgpack-unity3d] Failed to read value for member.(#13)

Should I use your last commit for the check is it stable changes? — You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

Janry commented 7 years ago

May you show the example how should correctly Packet types link with Unity project? Also how correctly build dll with your last commit for Unity project?

Just add info into link.xml like this?

<linker>
  <assembly fullname="Protocol">
    <type fullname="Protocol.Types.Point" preserve="all" />
    <namespace fullname="Protocol.Types" preserve="all" />
  </assembly>
</linker>