M-Misha-M
M-Misha-M

Reputation: 33

Incorrect upload multiple images in Edit method

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

Answers (1)

user3559349
user3559349

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.

  1. The code for generating the 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.
  2. Delete the 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.
  3. Move your db.Entry(furniture).State = EntityState.Modified; line of code to immediately before db.SaveChanges();

Upvotes: 1

Related Questions