Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to serialize byte[] as simple JSON Array and not as base64 in JSON.net?

I use JSON.net to serialize some objects between C# and JavaScript. The JSON data is transfered via WebSocket between the .NET and browser application.

In the data structure there are some byte[] fields, I want these fields as an Array in JavaScript also.

How can I serialize a C# byte[] to a simple JSON Array like [ 0 , 1 , 254, 255 ] instead of a base64 string?

like image 963
Marcus Avatar asked Mar 05 '13 14:03

Marcus


People also ask

Can we pass byte array in JSON?

json now lets you put a byte[] object directly into a json and it remains readable. you can even send the resulting object over a websocket and it will be readable on the other side.

Is an array JSON serializable?

NumPy array is not JSON serializable.

What is serialized and deserialized in JSON?

JSON is a format that encodes objects in a string. Serialization means to convert an object into that string, and deserialization is its inverse operation (convert string -> object).

Can JSON serialize a list?

To serialize a collection - a generic list, array, dictionary, or your own custom collection - simply call the serializer with the object you want to get JSON for. Json.NET will serialize the collection and all of the values it contains.


Video Answer


2 Answers

JSON.NET is selecting the BinaryConverter to read and write an array of bytes. You can see in the source that it uses the WriteValue operation on the JsonWriter class with the array of bytes which causes them to be written to as Base-64.

To modify this, you can write your own converter which reads and writes an array in the format you expect:

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[]);     } } 

You would use this by applying the JsonConverterAttribute to the member:

[JsonConverter(typeof(ByteArrayConverter))] public byte[] Data { get; set; } 
like image 152
Paul Turner Avatar answered Oct 02 '22 08:10

Paul Turner


Simplest way I can think of is to convert the byte array into an integer array, like:

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

This wouldn't require any special handling of the JSON library, or any custom serialization or anything like that.

EDIT: This would mean having to customize your data object to handle the different type. Maybe:

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

So maybe it's not the simplest - depending on how much stuff you have to serialize

like image 44
Joe Enos Avatar answered Oct 02 '22 08:10

Joe Enos