2

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?

dbc
  • 104,963
  • 20
  • 228
  • 340
DoomerDGR8
  • 4,840
  • 6
  • 43
  • 91
  • 1
    Why are you using a `StreamReader` when JsonSerializer can [deserialize directly from a stream](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializer.deserialize?view=net-6.0#system-text-json-jsonserializer-deserialize-1(system-io-stream-system-text-json-jsonserializeroptions))? Just do `JsonSerializer.Deserialize(ms);`. Incidentally there's no reason to use `async` deserialization when deserializing from a `MemoryStream`. – dbc Aug 11 '22 at 19:06
  • 1
    Also, since you already have a JSON string `metaData`, why not just deserialize the string directly via [`JsonSerializer.Deserialize(metaData)`](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializer.deserialize?view=net-6.0#system-text-json-jsonserializer-deserialize-1(system-readonlyspan((system-char))-system-text-json-jsonserializeroptions))? – dbc Aug 11 '22 at 19:13

1 Answers1

1

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.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • my object is not deserialized properly. Here is the original Newtonsoft based code: https://docs.telerik.com/aspnet-core/html-helpers/editors/upload/chunk-upload – DoomerDGR8 Aug 13 '22 at 14:59
  • Hi @dbc, after the call I get an emtpy object (properties are all empty) where as the source object actually has valid json – DoomerDGR8 Aug 13 '22 at 15:01
  • @HassanGulzar - then please [edit](https://stackoverflow.com/posts/73325481/edit) your question to provide a [mcve]. Or better yet ask a second question as the format for questions here is [one question per post](https://meta.stackexchange.com/q/222735). There are many differences between System.Text.Json and Json.NET (see [Compare Newtonsoft.Json to System.Text.Json, and migrate to System.Text.Json](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to)) so I can't guess what the problem is from just a comment. – dbc Aug 13 '22 at 15:01