Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot access a closed file when uploading to memory stream

I am trying to create an controller that will allow me to save images into my database. So far I have this bit of code:

/// <summary>
/// Handles an upload
/// </summary>
/// <returns></returns>
[HttpPost]
[Route("")]
public async Task<IHttpActionResult> Upload()
{

    // If the request is not of multipart content, then return a bad request
    if (!Request.Content.IsMimeMultipartContent())
        return BadRequest("Your form must be of type multipartcontent.");

    // Get our provider
    var provider = new MultipartFormDataStreamProvider(ConfigurationManager.AppSettings["UploadFolder"]);

    // Upload our file
    await Request.Content.ReadAsMultipartAsync(provider);

    // Get our file
    var file = provider.Contents.First();
    var bytes = await file.ReadAsByteArrayAsync();

    // Using a MemoryStream
    using (var stream = new MemoryStream(bytes))
    {

        stream.Seek(0, SeekOrigin.Begin);

        // Create the data
        var data = "data:image/gif;base64," + Convert.ToBase64String(stream.ToArray());

        // Return the data
        return Ok(data);
    }
}

But it isn't working. When I get into the using block I get an error message:

"Error while copying content to a stream."
"Cannot access a closed file."

Does anyone know why?

like image 552
r3plica Avatar asked May 15 '15 01:05

r3plica


1 Answers

The reason this is happening is the MultipartFormDataStreamProvider closes and disposes the uploaded files streams after it has written the uploaded data to the file location you provided when you passed this into the constructor: ConfigurationManager.AppSettings["UploadFolder"]

To access the files that have been uploaded you need to consult the file data on disk from the uploaded file location:

So in your example your code needs to use this:

// Read the first file from the file data collection:
var fileupload = provider.FileData.First;

// Get the temp name and path that MultipartFormDataStreamProvider used to save the file as:
var temppath = fileupload.LocalFileName;

// Now read the file's data from the temp location.
var bytes = File.ReadAllBytes(temppath);

Additionally if your using very small files you can instead use:

MultipartMemoryStreamProvider

This stores the file data in memory and should work as expected. Be warned though if you are using large files (25mb+) its wise to stream to disk first otherwise you might get out of memory exceptions as .net tries to hold the whole file in memory.

like image 107
Rtype Avatar answered Nov 08 '22 18:11

Rtype