Unity3d 5.3.0 introduced JsonUtility class which will help you with JSON serialization and deserialization. But this class has some limitation, and one of them: "You cannot serialize\deserialize System.Guid type"

That's a pity, especially if you're using System.Guid in your DTO objects. But, there are solutions:

  • You can change a data type, for example, use System.String or System.UInt32 instead of System.Guid. But if you have a lot of code which uses your DTO objects it might be painful to refactor all of it.
  • The second option is to create a wrapper type with an implicit conversion to and from System.Guid. So you do not need to change any code outside of your DTO.

Here is wrapper struct which has small GC allocation footprint (around 500B per conversion):

[Serializable]
public struct SerializableGuid: IComparable, IComparable<SerializableGuid>, IEquatable<SerializableGuid>
{
    public string Value;

    private SerializableGuid(string value)
    {
        Value = value;
    }

    public static implicit operator SerializableGuid(Guid guid)
    {
        return new SerializableGuid(guid.ToString());
    }

    public static implicit operator Guid(SerializableGuid serializableGuid)
    {
        return new Guid(serializableGuid.Value);
    }

    public int CompareTo(object value)
    {
        if (value == null)
            return 1;
        if (!(value is SerializableGuid))
            throw new ArgumentException("Must be SerializableGuid");
        SerializableGuid guid = (SerializableGuid)value;
        return guid.Value == Value ? 0 : 1;
    }

    public int CompareTo(SerializableGuid other)
    {
        return other.Value == Value ? 0 : 1;
    }

    public bool Equals(SerializableGuid other)
    {
        return Value == other.Value;
    }

    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }

    public override int GetHashCode()
    {
        return (Value != null ? Value.GetHashCode() : 0);
    }

    public override string ToString()
    {
        return (Value != null ? new Guid(Value).ToString() : string.Empty);
    }
}

Here is resulting JSON string:

{"Id":{"Value":"1bd8a973-3746-4f79-a277-eac5d0c093ff"},"Value":1.5,"Name":"Name","Users":[{"Id":{"Value":"44a928df-e451-4962-8e64-6143b7bf3dfa"},"UserName":"User1"},{"Id":{"Value":"71235d79-37f0-484e-9273-fc040d7ea059"},"UserName":"User2"}]}

Now you can replace Guid with SerializedGuid in DTO object:

[Serializable]
public class DTO
{
    public SerializableGuid Id;
    public float Value;
    public string Name;
    public List<User> Users;
}

But because of the implicit operators you do not need to change any other code:

var data = new Dto
{
    Id = Guid.NewGuid(),
    Value = 1.5f,
    Name = "Name",
    Users = new List<User>
    {
        new User {Id = Guid.NewGuid(), UserName = "User1"},
        new User { Id = Guid.NewGuid(), UserName = "User2"}
    }
};