Search code examples
c#json.net

JsonConvert.DeserializeObject throws an exception when attempting to deserialize byte[] to IEnumerable<byte>


The code below fails in deserialization with the following error.

Error converting value "AQID" to type 'System.Collections.Generic.IEnumerable`1[System.Byte]'

public class ByteArrayTest
{
    public string SomeString { get; set; }
    public IEnumerable<byte> ByteArray { get; set; } 
} 

using Newtonsoft.Json;

[TestClass]
public class UnitTest10
{
    [TestMethod]
    public void TestTheByteArraySerialization()
    {
        var test = new ByteArrayTest { ByteArray = new byte[] { 1, 2, 3 }, SomeString = "testing" };
        var serializedData = JsonConvert.SerializeObject(test);
        //This line belows fails with an error of can't convert to IEnumerable<byte>
        var myByeArrayClass = JsonConvert.DeserializeObject<ByteArrayTest>(serializedData);
        Assert.AreEqual(test.ByteArray, myByeArrayClass.ByteArray);

    }
}

In my particular case I don't own the ByteArrayTest class, this is just a quick example of the issue. I'd like a solution that doesn't involve modifying the ByteArrayTest class. Ideally I'd pass something into one of the DeserializeObject<> overloads to get this to work, but I'm unsure of the best approach to resolve this exception


Solution

  • You can't expect JsonConvert to magically create an implementation for an interface.

    You could use List<byte> or byte[] instead of IEnumerable<byte> if your architecture permits OR you can add a field to interface the Json serializer and hide your actual IEnumerable from it.

    private IEnumerable<byte> myBytes = null;
    
    [JsonProperty("BytesArray")]
    public string JsonBytes
    {
        get 
        {
            // this may need tweaking, null checks etc
            return String.Join("", myBytes.Select(b => b.ToString("X2"))); 
        }
        set
        {
            byte[] bytes = Convert.FromBase64String(value);
            myBytes = bytes;
        } 
    }
    
    [JsonIgnore]
    public IEnumerable<byte> BytesArray
    {
        get { return myBytes; }
        set { myBytes = value; }
    }
    

    You could probably provide a converter to achieve the same thing but I'd say it's too much fiddling around without the need to.

    For a list of several implementations on the StringToByteArray see this post, I copied the shortest implementation.