web-dev-qa-db-fra.com

Comment sérialiser byte [] comme un tableau JSON simple et non comme base64 dans JSON.net?

J'utilise JSON.net pour sérialiser des objets entre C # et JavaScript. Les données JSON sont transférées via WebSocket entre le .NET et l'application de navigateur. 

Dans la structure de données, il y a quelques champs byte[], je veux également que ces champs soient une variable Array en JavaScript.

Comment puis-je sérialiser un byte[] C # sur un tableau JSON simple tel que [ 0 , 1 , 254, 255 ] au lieu d'une chaîne base64?

24
Marcus

Le moyen le plus simple auquel je puisse penser est de convertir le tableau d'octets en un tableau entier, comme:

var intArray = byteArray.Select(b => (int)b).ToArray();

Cela ne nécessiterait aucune manipulation spéciale de la bibliothèque JSON, ni aucune sérialisation personnalisée, ni rien de ce genre.

EDIT: Cela impliquerait de personnaliser votre objet de données pour gérer le type différent. Peut être:

public class CustomFoo : Foo
{
    // SomeBytesHere is a byte[] in the base class
    public new int[] SomeBytesHere { get;set; }
}

Alors peut-être que ce n'est pas le plus simple - en fonction du nombre de choses que vous avez à sérialiser

12
Joe Enos

JSON.NET sélectionne la variable BinaryConverter pour lire et écrire un tableau d'octets. Vous pouvez voir dans le code source qu'il utilise l'opération WriteValue sur la classe JsonWriter avec le tableau d'octets, ce qui entraîne leur écriture dans Base-64.

Pour modifier cela, vous pouvez écrire votre propre convertisseur qui lit et écrit un tableau dans le format que vous attendez:

public class ByteArrayConverter : JsonConverter
{
    public override void WriteJson(
        JsonWriter writer,
        object value,
        JsonSerializer serializer)
    {
        if (value == null)
        {
            writer.WriteNull();
            return;
        }

        byte[] data = (byte[])value;

        // Compose an array.
        writer.WriteStartArray();

        for (var i = 0; i < data.Length; i++)
        {
            writer.WriteValue(data[i]);
        }

        writer.WriteEndArray();
    }

    public override object ReadJson(
        JsonReader reader,
        Type objectType,
        object existingValue,
        JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartArray)
        {
            var byteList = new List<byte>();

            while (reader.Read())
            {
                switch (reader.TokenType)
                {
                    case JsonToken.Integer:
                        byteList.Add(Convert.ToByte(reader.Value));
                        break;
                    case JsonToken.EndArray:
                        return byteList.ToArray();
                    case JsonToken.Comment:
                        // skip
                        break;
                    default:
                        throw new Exception(
                        string.Format(
                            "Unexpected token when reading bytes: {0}",
                            reader.TokenType));
                }
            }

            throw new Exception("Unexpected end when reading bytes.");
        }
        else
        {
            throw new Exception(
                string.Format(
                    "Unexpected token parsing binary. "
                    + "Expected StartArray, got {0}.",
                    reader.TokenType));
        }
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(byte[]);
    }
}

Vous utiliseriez ceci en appliquant la JsonConverterAttribute au membre:

[JsonConverter(typeof(ByteArrayConverter))]
public byte[] Data { get; set; }
50
Paul Turner

Ref ma réponse , JSON.net peut personnaliser la sérialisation en définissant pour tous au lieu d'attributs en propriétés.

Vous pouvez facilement le changer de base64 en tableau numérique, écrivez simplement une valeur brute csv entre crochets.

0
IlPADlI