Reputation: 33
I have method Edit that uploads one image for Main Page and multiple images for gallery to the existing record in database. I have one to many relationship table (FurnitureImages
where I store info about image) , also I use View Model
So here my code
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(FurnitureVM model)
{
if (model.MainFile != null && model.MainFile.ContentLength > 0)
{
string displayName = model.MainFile.FileName;
string extension = Path.GetExtension(displayName);
string fileName = string.Format("{0}{1}", Guid.NewGuid(), extension);
string path = "~/Upload/" + fileName;
model.MainFile.SaveAs(Server.MapPath( path));
model.MainImage = new ImageVM() { Path = path, DisplayName = displayName };
}
foreach (HttpPostedFileBase file in model.SecondaryFiles)
{
FurnitureImages images = new FurnitureImages();
if (file != null && file.ContentLength > 0)
{
string displayName = file.FileName;
string extension = Path.GetExtension(displayName);
string fileName = string.Format("{0}{1}", Guid.NewGuid(), extension);
var path = "~/Upload/" + fileName;
file.SaveAs(Server.MapPath(path));
model.SecondaryImages = new List<ImageVM> { new ImageVM { DisplayName = displayName, Path = path } };
}
}
if (!ModelState.IsValid)
{
model.CategoryList = new SelectList(db.Categories, "CategoryId", "Name",model.CategoryId); // repopulate the SelectList
return View(model);
}
Furniture furniture = db.Furnitures.Where(x => x.FurnitureId == model.ID).FirstOrDefault();
FurnitureImages main = furniture.Images.Where(x => x.IsMainImage).FirstOrDefault();
furniture.Name = model.Name;
furniture.Description = model.Description;
furniture.Manufacturer = model.Manufacturer;
furniture.Price = model.Price;
furniture.CategoryId = model.CategoryId;
furniture.Size = model.Size;
main.DisplayName = model.MainImage.DisplayName;
main.Path = model.MainImage.Path;
main.IsMainImage = model.MainImage.IsMainImage;
if (model.MainImage != null && !model.MainImage.Id.HasValue)
{
FurnitureImages image = new FurnitureImages
{
Path = model.MainImage.Path,
DisplayName = model.MainImage.DisplayName,
IsMainImage = true
};
furniture.Images.Add(image);
db.Entry(furniture).State = EntityState.Modified;
}
// Update secondary images
IEnumerable<ImageVM> newImages = model.SecondaryImages.Where(x => x.Id == null);
foreach (ImageVM image in newImages)
{
FurnitureImages images = new FurnitureImages
{
DisplayName = image.DisplayName,
Path = image.Path ,
IsMainImage = false
};
furniture.Images.Add(images);
}
ViewBag.CategoryId = new SelectList(db.Categories, "CategoryId", "Name", furniture.CategoryId);
db.SaveChanges();
return RedirectToAction("Index");
}
Main image uploads good , but when I try to upload multiple images from another input file
@Html.TextBoxFor(m => m.SecondaryFiles, new { type = "file", multiple = "multiple" , name = "SecondaryFiles" })
@Html.ValidationMessageFor(m => m.SecondaryFiles)
@for (int i = 0; i < Model.SecondaryImages.Count; i++)
{
@Html.HiddenFor(m => m.SecondaryImages[i].Id)
@Html.HiddenFor(m => m.SecondaryImages[i].Path)
@Html.HiddenFor(m => m.SecondaryImages[i].DisplayName)
<img src="@Url.Content(Model.SecondaryImages[i].Path)" />
}
It uploads only one image , And as much as I keep trying to upload many images, it always upload only one, so where are errors in my method?
Upvotes: 1
Views: 39
Reputation:
Your issue is that inside the first foreach
loop, you correctly save each file to the server, but in each iteration, your creating an new List<ImageVM>
and overwriting the value of SecondaryImages
so when the loop has completed, it contains only one item (based on the last image).
Change the loop to
foreach (HttpPostedFileBase file in model.SecondaryFiles)
{
// FurnitureImages images = new FurnitureImages(); -- DELETE
if (file != null && file.ContentLength > 0)
{
string displayName = file.FileName;
string extension = Path.GetExtension(displayName);
string fileName = string.Format("{0}{1}", Guid.NewGuid(), extension);
var path = "~/Upload/" + fileName;
file.SaveAs(Server.MapPath(path));
// Add a new ImageVM to the collection
model.SecondaryImages.Add(new ImageVM { DisplayName = displayName, Path = path });
}
}
Note that the above assumes you view model has a parameter-less constructor that initializes SecondaryImages
. If not, then add model.SecondaryImages = new List<ImageVM>
before the loop.
A few other minor issues to address.
SelectList
should be just
model.CategoryList = new SelectList(db.Categories, "CategoryId", "Name");
- the last parameter of the SelectList
constructor is
ignored when binding to a model property so its pointless.ViewBag.CategoryId = new SelectList(...)
line of code.
Your model already contains a property for the SelectList
(as per
note 1) but in any case, your redirecting, so adding anything to
ViewBag
is pointless.db.Entry(furniture).State = EntityState.Modified;
line
of code to immediately before db.SaveChanges();
Upvotes: 1