DoomerDGR8
DoomerDGR8

Reputation: 5042

System.Text.Json.* & deserialization of streams

I have this original code:

public async Task<ActionResult> Chunk_Upload_Save(IEnumerable<IFormFile> files, string metaData)
{
    if (metaData == null)
    {
        return await Save(files);
    }

    MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(metaData));

    JsonSerializer serializer = new JsonSerializer();
    ChunkMetaData chunkData;
    using (StreamReader streamReader = new StreamReader(ms))
    {
        chunkData = (ChunkMetaData)serializer.Deserialize(streamReader, typeof(ChunkMetaData));
    }

    string path = String.Empty;
    // The Name of the Upload component is "files"
    if (files != null)
    {
        foreach (var file in files)
        {
            path = Path.Combine(WebHostEnvironment.WebRootPath, "App_Data", chunkData.FileName);

            //AppendToFile(path, file);
        }
    }

    FileResult fileBlob = new FileResult();
    fileBlob.uploaded = chunkData.TotalChunks - 1<= chunkData.ChunkIndex;
    fileBlob.fileUid = chunkData.UploadUid;

    return Json(fileBlob);
}

I converted it using only System.Text.Json.* to this:

public async Task<ActionResult> Chunk_Upload_Save(IEnumerable<IFormFile> files, string metaData)
{
    if (metaData == null)
    {
        return await Save(files);
    }

    var ms = new MemoryStream(Encoding.UTF8.GetBytes(metaData));

    ChunkMetaDataModel  chunkData;
    using (var streamReader = new StreamReader(ms))
    {
        // Here is the issues
        chunkData = (ChunkMetaDataModel) await JsonSerializer.DeserializeAsync(streamReader, typeof(ChunkMetaDataModel));
    }

    // The Name of the Upload component is "files"
    if (files != null)
    {
        foreach (var file in files)
        {
            Path.Combine(hostEnvironment.WebRootPath, "App_Data", chunkData!.FileName);

            //AppendToFile(path, file);
        }
    }

    var fileBlob = new FileResultModel
    {
        uploaded = chunkData!.TotalChunks - 1 <= chunkData.ChunkIndex,
        fileUid  = chunkData.UploadUid
    };

    return Json(fileBlob);
}

I get the error:

Argument 1: cannot convert from 'System.IO.StreamReader' to 'System.IO.Stream'.

By Argument 1, VS is pointing to the streamReader parameter and it's this line: chunkData = (ChunkMetaData)serializer.Deserialize(streamReader, typeof(ChunkMetaData));

How do I convert this to the System.Text.Json API?

Upvotes: 3

Views: 2158

Answers (2)

joseclavel
joseclavel

Reputation: 11

Maybe a bit late but... I had the same problem with the Telerik Upload Control sample. This is how I made it work:

First add a basic JsonSerializerOptions:

public JsonSerializerOptions options = new JsonSerializerOptions
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        WriteIndented = true
    };

Then to deserialize the metadata string object, I changed the code to the following:

ChunkMetaData chunkData = JsonSerializer.Deserialize<ChunkMetaData>(metaData, options);

And the chunkdata object is correctly filled now.

Hope this helps somebody

Upvotes: 1

dbc
dbc

Reputation: 116991

System.Text.Json is designed to deserialize most efficiently from UTF8 byte sequences rather than UTF16 strings, so there is no overload to deserialize from a StreamReader. Instead deserialize directly from the MemoryStream ms using the following:

chunkData = await JsonSerializer.DeserializeAsync<ChunkMetaDataModel>(ms);

Notes:

  1. There is no reason to use async deserialization when deserializing from a MemoryStream. Instead use synchronous deserialization like so:

    chunkData = JsonSerializer.Deserialize<ChunkMetaDataModel>(ms);
    
  2. And since you already have a string metaData containing the JSON to be deserialized, you can deserialize directly from it using the Deserialize<TValue>(ReadOnlySpan<Char>, JsonSerializerOptions) overload:

    chunkData = JsonSerializer.Deserialize<ChunkMetaDataModel>(metaData);
    

    System.Text.Json will do the UTF16 to UTF8 conversion for you internally using memory pooling.

  3. If you really must deserialize from a StreamReader for some reason (e.g. incremental integration of System.Text.Json with legacy code), see Reading string as a stream without copying for suggestions on how to do this.

Upvotes: 2

Related Questions