5

I want to convert my model to json, and it has a byte[] array that gets converted to a base64 string while converting to json. I'm not wanting to converting the byte[] array to string format.

Here is what I have tried

       MyModel myObject = new MyModel
        {
            Id = 1,                
            Data = new byte[] { 0x01, 0x02, 0x03 }
        };
        string json = JsonSerializer.Serialize(myObject, options);

It returns the output as Json string output

I want output as {"Id":[1],"Data":[1,2,3]}.

Edit: I have code for above in powershell script which do the same

$CertificateJsonString = ConvertTo-Json $CertificateVaultObject -Compress
$CertificateSecureString = ConvertTo-SecureString -String $CertificateJsonString -AsPlainText –Force
9
  • 2
    So you get "AQID" and you expect 1,2,3. How shall that be possible? Are you sure you're looking at the output of the code you posted? Did you run an old build? Why should ID be an array ([1]) when it's only an int? Commented May 16, 2023 at 14:05
  • 1
    If you don't want your byte[] to be converted to a base64 string when serializing, then what string representation should it become? Commented May 16, 2023 at 14:06
  • 1
    @ThomasWeller I have certificate byte data that I want to store somewhere in byte[] format only. It has more than 2k byte like {"CertBytes":[48,130,13,240,2,1,3,48,130,13,........ 10,144]}. I have powershell command which does the work. Commented May 16, 2023 at 14:10
  • 3
    Also, why do you think Id = 1 should result in "Id":[1] not "Id":1? That seems to be a completely different requirement. Commented May 16, 2023 at 14:17
  • 3
    Encoding binary content as BASE64 is part of the standard. Using your own custom serialization format will make it harder to work with any other application - including your own, as you'll have to repeat the customization all over the place Commented May 16, 2023 at 14:35

1 Answer 1

10

System.Text.Json (and Json.NET) only serializes byte arrays as Base64, so if you declare your Data as some other collection or enumerable of bytes (but not object) it will be serialized as a JSON array, e.g:

public class MyModel
{
    public int Id { get; set; }
    public IEnumerable<byte>? Data { get; set; }
}

When serialized via:

MyModel myObject = new MyModel
{
    Id = 1,                
    Data = new byte[] { 0x01, 0x02, 0x03 }
};
string json = JsonSerializer.Serialize(myObject, options);

Results in:

{"Id":1,"Data":[1,2,3]}

Demo fiddle #1 here.

Or, if you can't change your model, you could introduce a JsonConverter<byte> that round-trips byte [] values as an array:

public class ByteArrayConverter : JsonConverter<byte []>
{
    public override void Write(Utf8JsonWriter writer, byte [] value, JsonSerializerOptions options) =>
        JsonSerializer.Serialize(writer, value.AsEnumerable());
    
    public override byte []? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
        reader.TokenType switch
        {
            JsonTokenType.String => reader.GetBytesFromBase64(),
            JsonTokenType.StartArray => JsonSerializer.Deserialize<List<byte>>(ref reader)!.ToArray(),
            JsonTokenType.Null => null,
            _ => throw new JsonException(),
        };
}

And serialize like so:

MyModel myObject = new MyModel
{
    Id = 1,                
    Data = new byte[] { 0x01, 0x02, 0x03 }
};
var options = new JsonSerializerOptions { Converters = { new ByteArrayConverter() } };
string json = JsonSerializer.Serialize(myObject, options);

And get the same result.

Demo fiddle #2 here.

Notes:

Sign up to request clarification or add additional context in comments.

5 Comments

If that payload is certificate data, anything other than BASE64 would be a problem
@PanagiotisKanavos - it seems like an odd requirement for sure, but it does come up from time to time. The equivalent question Json.NET How to serialize byte[] as simple JSON Array and not as base64 in JSON.net? has 31 votes so I think it's a legitimate question for System.Text.Json as well.
@PanagiotisKanavos why?
@MikeNakis for starters, it's against the standard which means other applications will have trouble dealing with that non-standard field. The reason the standard recommends BASE64 is that otherwise the data type is lost. Since JSON has no explicit numeric types, that list of numbers can be translated as anything, including floats. There's no way to mistranslate BASE64, assuming you know what's stored in that field. An array of numbers takes far more space too.
@PanagiotisKanavos - I added a note mentioning your comment, linking to the standard, and suggesting using Base64 as-is.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.