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
CodePudding user response:
The CopyToAsync
method returns a Task
which must be await
ed 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");
}