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

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

Dans la structure de données il y a quelques byte[] champs, je veux ces champs comme un Array en JavaScript aussi.

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

24
demandé sur Useless Code 2013-03-05 18:55:03

3 réponses

La façon la plus simple de 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 gestion spéciale de la bibliothèque JSON, ni aucune sérialisation personnalisée ou quelque chose comme ça.

EDIT : cela signifierait avoir à 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 de la quantité de choses que vous devez sérialiser

12
répondu Joe Enos 2013-03-05 15:15:15

JSON.NET sélectionne le BinaryConverter pour lire et écrire un tableau d'octets. Vous pouvez voir dans la source {[8] } qu'elle utilise l'opération WriteValue sur la classe JsonWriter avec le tableau d'octets qui les amène à être écrits en 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 le JsonConverterAttribute au membre:

[JsonConverter(typeof(ByteArrayConverter))]
public byte[] Data { get; set; }
46
répondu Paul Turner 2018-01-30 09:18:13

Ref ma réponse , JSON.net peut personnaliser la sérialisation dans le paramètre pour tous au lieu de l'attribut dans la propriété.

Vous pouvez facilement le changer de base64 en tableau de nombres, il suffit d'écrire une valeur brute CSV entre crochets.

0
répondu IlPADlI 2018-09-11 06:55:01