5

I'm trying to convert a list of base64String into a list of IFormFile. When I try MemoryStream stream = new MemoryStream(bytes) I got a stream.ReadTimeout SystemInvalidOperation. So Why it isn't working?

Here is my code:

private async Task<List<IFormFile>> Base64ToImage(List<EquipmentFile> equipmentFiles)
{
    List<IFormFile> formFiles = new List<IFormFile>();
    foreach (var eqp in equipmentFiles)
    {
      byte[] bytes = Convert.FromBase64String(eqp.File);
      MemoryStream stream = new MemoryStream(bytes);
      IFormFile file = new FormFile(stream, 0, bytes.Length, eqp.Name, eqp.Name);
      formFiles.Add(file);
    }
    return formFiles;
}
 

My Stack trace:

System.InvalidOperationException: Timeouts are not supported on this stream.
   at System.IO.Stream.get_ReadTimeout()
   at FieldService.CallCenter.Api.Controllers.EquipmentLibraryController.Base64ToImage(List`1 equipmentFiles) in C:\Users\CMTech-DEV\Documents\cmtech\fieldservice-api\src\CallCenter\FieldService.CallCenter.API\Controllers\EquipmentLibraryController.cs:line 331
   at System.IO.Stream.get_ReadTimeout()
   at FieldService.CallCenter.Api.Controllers.EquipmentLibraryController.Base64ToImage(List`1 equipmentFiles) in C:\Users\CMTech-DEV\Documents\cmtech\fieldservice-api\src\CallCenter\FieldService.CallCenter.API\Controllers\EquipmentLibraryController.cs:line 331
matheusmosca
  • 73
  • 1
  • 7
  • 4
    Provide a proper stack trace – Nkosi Jan 27 '21 at 14:13
  • 4
    I'm not sure if this is it, but you are disposing all of the streams before you return them (wrapped by FormFile) via the `using`. Unless FormFile makes a copy of the stream then this is likely bad and could be related – pinkfloydx33 Jan 27 '21 at 14:15

1 Answers1

11

You are implicitly calling Dispose on the MemoryStreams after you pass them to the FormFile constructor due to the using block. You then return a list of FormFile objects where the inner streams are all disposed.

FormFile does not make a copy of the stream's content, but instead (via ReferencedReadStream) calls methods like Stream.Read which (in the case of MemoryStream at least) will throw an exception if the stream has been closed--which it has due to Dispose.

You've not provided any information such as a stack trace so this is a best guess, but removing the using block should suffice to fix this problem.

private List<IFormFile> Base64ToImage(List<EquipmentFile> equipmentFiles)
{
    List<IFormFile> formFiles = new List<IFormFile>();
    foreach (var eqp in equipmentFiles)
    {
        
        byte[] bytes = Convert.FromBase64String(eqp.File);
        MemoryStream stream = new MemoryStream(bytes);
        
        IFormFile file = new FormFile(stream, 0, bytes.Length, eqp.Name, eqp.Name);
        formFiles.Add(file);
        
    }
    return formFiles;
} 
pinkfloydx33
  • 11,863
  • 3
  • 46
  • 63
  • [`FormFile`](https://github.com/dotnet/aspnetcore/blob/a598360d1963b8f1dce7f3064da9f8ce1c7061df/src/Http/Http/src/FormFile.cs#L15) is a strange class. It doesn't dispose the `_baseStream` itself and doesn't provide any methods for consumers to dispose it, either by implementing `IDisposable` itself or providing a getter to let the consumer dispose the `_baseStream`. I don't think it is mean for general use. – dbc Jan 27 '21 at 14:44
  • 1
    @dbc I think you are right. What's interesting is that in ASP.NET (not Core), `FormFile` was in an [`Internal` namespace](https://github.com/aspnet/HttpAbstractions/blob/master/src/Microsoft.AspNetCore.Http/Internal/FormFile.cs) yet publicly accessible. There was usually a reason for this pattern, typically for "advanced" cases or because other parts of the infrastructure needed access. – pinkfloydx33 Jan 27 '21 at 14:47
  • I removed the `using` block but the problem remains. I also provided a stack trace. Should I add my controller method? – matheusmosca Jan 27 '21 at 16:06