[SOLVED] .NET Core 6 upload file to wwwroot/images fails sometimes and uploads half images

Issue

I am trying to upload files from a website to my wwwroot/images directory but sometimes only half the image get uploaded and it doesnt seem to work with .png files, here is my code:

[HttpPost]
        public IActionResult UploadFile(IFormFile userfile)
        {
            MgvaKrantransportContext DBContext = new MgvaKrantransportContext();

            try
            {
                Image image = new Image() { Filepath = "images/" + userfile.FileName, Filename = userfile.FileName };

                DBContext.Add(image);
                DBContext.SaveChanges();
            }
            catch (Exception ex)
            {
                ViewBag.message = ex.Message;
            }


            try
            {
                string filename = userfile.FileName;
                filename = Path.GetFileName(filename);
                string uploadFilePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot\\images", filename);

                var stream = new FileStream(uploadFilePath, FileMode.Create);
                userfile.CopyToAsync(stream);
                ViewBag.message = "Success";
            }
            catch (Exception ex)
            {
                ViewBag.message = ex.Message;
            }
            return RedirectToAction("Index");
        }

And here is the form in the View:

@using (Html.BeginForm("UploadFile", "Management", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <h2>Upload File</h2>
    <input type="file" name="userfile">
    <br />
    <input type="submit" value="Upload" />
}

Thanks beforehand!
Best regards Max

Solution

The CopyToAsync method returns a Task which must be awaited for the copy to succeed. Your code is currently closing the destination stream before the copy completes.

Either change your code to use the synchronous CopyTo method, or make your action method async and await the task.

You’ll also want to remove any directory information from the FileName before saving the name to the database – you’ve done it when you construct the physical path, but not for the Image entity.

And add await using to the DbContext and FileStream instances to ensure they are always disposed of properly.

There’s no point storing values in the ViewBag if you’re going to return a redirection; those values will always be lost. You could use TempData instead, which would store the messages in the session.

And Directory.GetCurrentDirectory() is not really the best way to get the root path of the application. Instead, inject the IWebHostEnvironment service and use its WebRootPath property to find the physical path of the wwwroot folder.

[HttpPost]
public async Task<IActionResult> UploadFile(IFormFile userfile)
{
    await using MgvaKrantransportContext DBContext = new MgvaKrantransportContext();
    try
    {
        string filename = userfile.FileName;
        filename = Path.GetFileName(filename);
        
        Image image = new() 
        { 
            Filepath = "images/" + filename, 
            Filename = filename 
        };

        await DBContext.AddAsync(image);
        await DBContext.SaveChangesAsync();

        string uploadFilePath = Path.Combine(WebHost.WebRootPath, "images", filename);

        await using var stream = new FileStream(uploadFilePath, FileMode.Create);
        await userfile.CopyToAsync(stream);
    }
    catch (Exception ex)
    {
        // TODO: Log the error somewhere
    }
    
    return RedirectToAction("Index");
}

Answered By – Richard Deeming

Answer Checked By – David Goodson (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *