-1

I want to upload images for gallery and Main page in my website , so I upload image to file system and save info abvout images in db , I use one to many relationship in database and also I use View Model. All data updates in database without problem , I checked it, but I can't display Images in View , maybe I have to write something else in my method Edit?? Please explain me. So Here is my code: View Models

public class FurnitureVM
{
    public FurnitureVM()
    {
        this.MainImage = new ImageVM();
        this.SecondaryImages = new List<ImageVM>();
    }

    public int? ID { get; set; }
    [Display(Name = "Name")]
    [Required(ErrorMessage = "Enter name")]
    public string Name { get; set; }

    [DataType(DataType.MultilineText)]
    [Display(Name = "...")]
    [Required(ErrorMessage = "...")]
    public string Description { get; set; }
    [Display(Name = "Price ()")]
    [Required]
    [Range(0.01, double.MaxValue, ErrorMessage = "...")]
    public decimal Price { get; set; }

    [Display(Name = "...")]
    [Required(ErrorMessage = "...")]
    public string Manufacturer { get; set; }
    [Display(Name = "Size")]
    [Required(ErrorMessage = "...")]
    public string Size { get; set; }

    [Display(Name = "....")]
    [Required]
    public int CategoryId { get; set; }
    public virtual Category Category { get; set; }

    public IEnumerable<SelectListItem> CategoryList { get; set; }
    public HttpPostedFileBase MainFile { get; set; }
    public IEnumerable<HttpPostedFileBase> SecondaryFiles { get; set; }
    public ImageVM MainImage { get; set; }
    public List<ImageVM> SecondaryImages { get; set; }
}
public class ImageVM
{
    public int? ID { get; set; }
    public string Path { get; set; }
    public string DisplayName { get; set; }           
}

My method in controller:

public ActionResult Edit(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    var furniture = db.Furnitures.Find(id);
    if (furniture == null)
    {
        return HttpNotFound();
    }

    FurnitureImages main = furniture.Images.Where(x => x.IsMainImage).FirstOrDefault();

        FurnitureVM model = new FurnitureVM();
        model.Name = furniture.Name;
        model.Description = furniture.Description;
        model.Price = furniture.Price;
        model.Size = furniture.Size;
        model.CategoryId = furniture.CategoryId;
         model.Manufacturer = furniture.Manufacturer;
        model.MainImage.Id = main.Id;
        model.MainImage.DisplayName = main.DisplayName;
        model.MainImage.Path = main.Path;
        model.MainImage.IsMainImage = main.IsMainImage;

    //ViewBag.CategoryId = new SelectList(db.Categories, "CategoryId", "Name", furniture.CategoryId);
    return View(model);
}

[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 = Path.Combine(Server.MapPath("~/Upload/"), fileName);
        model.MainFile.SaveAs(path);
        model.MainImage = new ImageVM() { Path = path, DisplayName = displayName };
    }

    foreach (HttpPostedFileBase file in model.SecondaryFiles)
    {
        FurnitureImages images = new FurnitureImages
        {
            //This is for secondary images for gallery  
        };
    }

    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.Id = model.ID;
        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);
    }

    // ViewBag.CategoryId = new SelectList(db.Categories, "CategoryId", "Name", furniture.CategoryId);
    db.Entry(furniture).State = EntityState.Modified;
    db.SaveChanges();
     return RedirectToAction("Index");
}

And part of my view

@model FurnitureStore.ModelView.FurnitureVM
...
@if (Model.MainImage != null)
{
    @Html.HiddenFor(m => m.MainImage.ID)
    @Html.HiddenFor(m => m.MainImage.Path)
    @Html.HiddenFor(m => m.MainImage.DisplayName)
    <img src="@Model.MainImage.Path" alt="@Model.MainImage.DisplayName" />
}

@Html.TextBoxFor(m => m.SecondaryFiles, new { type = "file", multiple = "multiple" })
@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="@Model.SecondaryImages[i].Path" alt="@Model.MainImage.DisplayName" />
}
M-Misha-M
  • 33
  • 9
  • can you show how the path looks like in the database that is stored, is it relative path? – Ehsan Sajjad Feb 14 '17 at 06:32
  • @Ehsan Sajjad D:\visualstudio2015\FurnitureStore\FurnitureStore\Upload\4b44e4ce-59fc-4ba5-8f1d-719e1e8b1006..jpg how my path looks like – M-Misha-M Feb 14 '17 at 07:37
  • Note the `Path.GetExtension(displayName);` returns the `.jpg` (includes the dot) so it should be just `string fileName = string.Format("{0}{1}", Guid.NewGuid(), extension);` –  Feb 14 '17 at 09:51
  • @StephenMuecke okay I fix what you said , and image still doesn't displays http://imgh.us/1_3143.png Console in browser is clear , maybe I miss some parameters in my method in code above? – M-Misha-M Feb 14 '17 at 11:49
  • You have not shown any code in the GET method where you populate the `MainImage` or `SecondayImages` properties of `FurnitureVM` (so they are `null` and there is nothing to display (and not related, but add a property `IEnumerable CategoryList` and populate that and get rid of your `ViewBag.CategoryId = ...` code) –  Feb 14 '17 at 11:56
  • @StephenMuecke I tried @Url.Content(Model.MainImage.Path) but now I get exception "Value cannot be null or empty. Parameter name: contentPath" . I know this error . it means that Path is null , can I fix it?? – M-Misha-M Feb 14 '17 at 11:56
  • Read my last comment! And remove `public virtual Category Category { get; set; }` from your view model) –  Feb 14 '17 at 11:57
  • @StephenMuecke okay , i removed it , I can't populate MainImage , because if i write something like this MainImage = furniture.MainImage this will be wrong , because MainImage does not exist in furniture context . Furniture context is my codeFirst , what i have to do in this case? – M-Misha-M Feb 14 '17 at 12:00
  • Also the code suggested by Ehsan Sajjad is good practice (although not directly related to your problem) –  Feb 14 '17 at 12:01
  • Your `Furniture` class contains a property `Images` (your adding those in the POST method), so you just need to read the values from that and set the properties of `MainImage` –  Feb 14 '17 at 12:02
  • @StephenMuecke yes sure I know it , but Images is public virtual ICollection Images { get; set; } , u said did it one to many , so i have to use foreach?? – M-Misha-M Feb 14 '17 at 12:04
  • Then if you have used the `bool` property to indicate which is the maian image, the use `FurnitureImages main = furniture.Images.Where(x => x.IsMainImage).FirstOrDefault();` and then populate the `MainImage` properties. –  Feb 14 '17 at 12:07
  • @M-Misha-M You might try to use the method on [How to display images in MVC](http://stackoverflow.com/questions/30651531/how-to-display-images-in-mvc/30653266#30653266). – Murat Yıldız Feb 14 '17 at 13:32
  • @StephenMuecke Image is now display , but i have another problem when i want to change new image it uploads to database good but it doesn't switch to new in the View , I used Modified but it doesn't work , i update my code above (in answer) – M-Misha-M Feb 14 '17 at 17:48
  • @StephenMuecke very strange , first time if upload new image it replace old and will display , but second time it doesn't want to display new , when upload – M-Misha-M Feb 14 '17 at 18:02
  • You have not shown the relevant code, but I guessing that you do have the `bool IsMainImage` property and that may be you did not set the value of the previous selection to `false`. We cannot guess what your code is, and if you have another issue, then ask another question with the relevant code. –  Feb 14 '17 at 23:16
  • @StephenMuecke i fixed it , now when i change another photo , old photo has value false , okay , it's work , next i want to know about foreach (HttpPostedFileBase file in model.SecondaryFiles) { this is from my previous topic , where you answered – M-Misha-M Feb 14 '17 at 23:30
  • Its not that hard - you know how to do it for one image, so its similar for the multiple images - just inside a loop. But as I have previously explained - this site is not a forum or chat site. If you have a problem, ask a new question explaining what your wanting to achieve, and the **minimal** code necessary to reproduce it (we do not need to see every property of `Furniture`), and explain what the problem is (what do you expect to happen and what actually happens, and if there are errors, which line of code throws the error). –  Feb 14 '17 at 23:46
  • @StephenMuecke tell me please how to pass SecondaryImages in model if it is List<> model.SecondaryImages.??? = .... ?? – M-Misha-M Feb 15 '17 at 13:15
  • You have accepted an answer that has nothing to do with your problem (so is confusing to others) and you have ignored by previous comment (ask a new question!) –  Feb 16 '17 at 00:02
  • @Stephen Muecke i accepted answer because with helping Ehsan Sajjad my main image displays good and path correct writes to db , my new answer now about gallery images http://stackoverflow.com/questions/42262582/display-multiple-images-from-database-using-view-model – M-Misha-M Feb 16 '17 at 00:27
  • The suggestion about storing the path is good advice, but your problem was because you never set the value of `MainImage` in the GET method first place :) –  Feb 16 '17 at 00:30
  • yes sure , my bad :) now tried to understand where i'm wrong in SecondaryFiles – M-Misha-M Feb 16 '17 at 00:34

2 Answers2

0

You should not be storing absolute path in the database, but instead store the relative path for which you would need to update the following line of code:

string path = "~/Upload/"+ fileName;
model.MainFile.SaveAs(Server.MapPath(path));

now in your view you would be able to display it this way:

<img src="@Url.Content(Model.MainImage.Path)" alt="@Model.MainImage.DisplayName" />

If you cannot modify the path saving logic and want to store the absolute path for any reason, then you can look at the following post:

https://stackoverflow.com/a/12804451/1875256

Community
  • 1
  • 1
Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
  • hello , thanks I accept it as asnwer , but can u help me please , now I can't display Secondary Images , that's how I pass to model and my view http://pastebin.com/DpBsRB0a – M-Misha-M Feb 15 '17 at 17:49
0

Controller side Looks Fine You need to change View Code

and then the rest of things shall work Like

<img src="@Url.Content(Model.MainImage.Path)" alt="@Model.MainImage.DisplayName" />

OR

<img src="@Url.Content(Model.SecondaryImages[i].Path)" alt="@Model.MainImage.DisplayName" />
  • okay i tried your code , now I have an exception , value cannot be null , name: contentPath . This error in 1 line above from your code , here @Html.HiddenFor(m => m.MainImage.DisplayName) – M-Misha-M Feb 14 '17 at 11:53