Reputation: 89
I am attempting to add a feature which allows users to upload a photo of their pets. I am new to MVC and am using this tutorial as guidance: https://www.codaffection.com/asp-net-core-article/asp-net-core-mvc-image-upload-and-retrieve/
View:
@model PetPhotoModel;
@{
ViewData["Title"] = "Upload A photo of your pet";
}
<div class="row">
<div class="col-md-4">
<form asp-action="UploadPhoto">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="PetName" class="control-label"></label>
<input asp-for="PetName" class="form-control" />
<span asp-validation-for="PetName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ImageFile" class="control-label"></label>
<input asp-for="ImageFile" accept="image/*" />
<span asp-validation-for="ImageFile" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="UploadPhoto" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Controller (partial):
...
public IActionResult UploadPhoto()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> UploadPhoto([Bind("Id,PetName,Title,Description,ImageFile")] PetPhotoModel petPhotoModel)
{
if (ModelState.IsValid)
{
//Save image to wwwroot/image
string wwwRootPath = _hostEnvironment.WebRootPath;
string fileName = Path.GetFileNameWithoutExtension(petPhotoModel.ImageFile.FileName);
string extension = Path.GetExtension(petPhotoModel.ImageFile.FileName);
petPhotoModel.ImageName = fileName = fileName + DateTime.Now.ToString("yymmssfff") + extension;
string path = Path.Combine(wwwRootPath + "/Image/", fileName);
using (var fileStream = new FileStream(path, FileMode.Create))
{
await petPhotoModel.ImageFile.CopyToAsync(fileStream);
}
//GetLoggedInUser() gets the current user by id from the db context
GetLoggedInUser().Uploads.Add(petPhotoModel);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(petPhotoModel);
}
...
The UserModel
contains a collection of PetPhotoModel
in order to create a 1 to many relationship in the database:
public virtual ICollection<PetPhotoModel> Uploads { get; set; }
PetPhotoModel:
public class PetPhotoModel
{
private DateTime _dateUploaded = DateTime.Now;
public int Id { get; set; }
[Required]
public string PetName { get; set; }
[Required]
public string Title { get; set; }
public string Description { get; set; }
[Column(TypeName = "nvarchar(100)")]
[DisplayName("Image Name")]
public string ImageName { get; set; }
[NotMapped]
[DisplayName("Upload File")]
public IFormFile ImageFile { get; set; }
public DateTime DateUploaded
{
get { return _dateUploaded; }
set { _dateUploaded = value; }
}
...
The issue is after the submit button is pressed that the controller does not get any data about image from the view at all despite the image being uploaded in the view:
[
Upvotes: 1
Views: 357
Reputation: 43959
When the form includes any type file elements you have to use "multipart/form-data" encoding. Since default encoding is "application/x-www-form-urlencoded", change form tag in your view to this:
<form asp-action="UploadPhoto" enctype="multipart/form-data" method="post">
Upvotes: 2