Search code examples
c#asp.netasp.net-mvcasp.net-coreiformfile

how to pass multiple of iformfile in c# in post action To Create Product


I Want the User to Enter Product Color With Images multiple time

so I have ProductDto Contain A List Of colorDto That Contain A list Of IFormFile Images

ProductDto

public class ProductDto
    {
        public int id { get; set; }

        [Required(ErrorMessage = "Please Enter The Title")]
        [MaxLength(500, ErrorMessage = "Must be less than 500 Chars")]
        public string Name { get; set; }

        [Required, Display(Name = "Product Description")]
        [DataType(DataType.MultilineText)]
        public string Description { get; set; }



        [Required, Display(Name = "Product Price")]
        public int Price { get; set; }

        [Required(ErrorMessage = "Must Enter Product Amount")]
        [ Display(Name = "Stock")]
        public int inStock { get; set; }

        [Display(Name = "New Price")]
        public  int  NewPrece { get; set; }
        [Required(ErrorMessage = "Must Enter Product Color")]

        [Display(Name = "color")]
        public ColorDto color { get; set; }
       
        [Display(Name = "size")]
        public string size { get; set; }
        [Required(ErrorMessage = "Must Enter Product Brand")]
        [Display(Name = "Brand")]
        public int BrandId { get; set; }

        [Required(ErrorMessage = "Must Enter Product Category")]
        [Display(Name = "Category")]
        public int CategoryId { get; set; }
        public int rate { get; set; }
        public List<ColorDto> colors { get; set;}

    }

ColorDto

public class ColorDto
    {
        public int id { get; set; }
        public int Productid {get;set;}
                public string Name { get; set; }  
                public List<IFormFile> Images { get; set; }
        
    }

My ProductController

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AdminDashboard.ProductConfigration;
using BTechModel;
using Microsoft.AspNetCore.Mvc;
using NToastNotify;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization;
using System.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Routing;
using static System.Collections.Specialized.BitVector32;
using System.IO;
using Microsoft.AspNetCore;
using System.Xml.Linq;
using Microsoft.AspNetCore.Hosting;
using NToastNotify;
using AdminDashboard.Models;
using AdminDashboard.IRepository;
using Newtonsoft.Json;
// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace AdminDashboard.Controllers
{
    public class ProductController : Controller
    {
        ApplicationDbContext context;
        private readonly IproductCreation iproductCreation;
        private readonly IToastNotification toastNotification;
        private readonly IColortRepository colortRepository;
        public ProductController(ApplicationDbContext dbContext, IproductCreation iproduct, IWebHostEnvironment webhost, IToastNotification _toastNotification, IColortRepository _colortRepository)
        {
            context = dbContext;
            iproductCreation = iproduct;
            toastNotification = _toastNotification;
            colortRepository = _colortRepository;

        }
        // GET: /<controller>/
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult AddNewProduct()
        {
            ViewBag.Brand = context.Brands.Select(i => new SelectListItem(i.Name,           i.BrandId.ToString())).AsNoTracking();
            ViewBag.Category = context.Category.Select(i => new SelectListItem(i.Name, i.CategoryId.ToString())).AsNoTracking();
            return View("ProductForm");
        }
        [HttpPost]

        public IActionResult AddNewProduct(ProductDto product)
        {
           
            TempData["ProductFromAdd"] = JsonConvert.SerializeObject(product);

            return RedirectToAction("AddProductImages");
        }

        [HttpGet]
        public IActionResult AddProductImages(ProductDto productdto)
        {
            if (TempData["ProductFromAdd"] != null)
            {

                 productdto = JsonConvert.DeserializeObject<ProductDto>((string)TempData["ProductFromAdd"]);
            }
            if (productdto.colors == null)
            {
                productdto.colors = new List<ColorDto>();
            }

            return View(productdto);
        }
        [HttpPost]
        public IActionResult Addimages( ProductDto _productdto)
        {
           
            var _color = _productdto.color;

      
            if (_productdto.colors == null)
            {
                _productdto.colors = new List<ColorDto>
                {
                    _color
                };
            }
            else
            {
                _productdto.colors.Add(_color);
            }


            return View("AddProductImages", _productdto);
        }

        
    }
}

Product Form



<form  method="post" asp-controller="Product" asp-action="AddNewProduct" enctype="multipart/form-data">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>

    <div>
        <div class="form-group">
            <label asp-for="Name"></label>
            <input asp-for="Name" name="Name" class="form-control" />
            <span asp-validation-for="Name" class="validation"></span>
        </div>
    </div>


    <div class="form-group">

        <label asp-for="Description"></label>
        <input asp-for="Description" class="form-control" />
        <span asp-validation-for="Description" class="validation"></span>
    </div>


    <div class="form-group">

        <label asp-for="BrandId"></label>
        <select asp-for="BrandId" class="form-control js-example-basic-single" asp-items="ViewBag.Brand">
        </select>
        <span asp-validation-for="BrandId" class="validation"></span>
    </div>

    <div class="form-group">

        <label asp-for="CategoryId"></label>
        <select asp-for="CategoryId" asp-items="ViewBag.Category" class="form-control js-example-basic-single " id="id_label_single" data-live-search="true" data-live-search-style="startsWith">
        </select>
        <span asp-validation-for="CategoryId" class="validation"></span>

    </div>

    <div class="form-group">
        <label asp-for="size"></label>
        <input asp-for="size" class="form-control" />
        <span asp-validation-for="size" class="validation"></span>
    </div>


    <div class="form-group">
        <label asp-for="inStock"></label>
        <input asp-for="inStock" class="form-control" />
        <span asp-validation-for="inStock" class="validation"></span>
    </div>

    <div class="form-group">
        <label asp-for="Price"></label>
        <input asp-for="Price" class="form-control" />
        <span asp-validation-for="Price" class="validation"></span>
    </div>

    <div class="form-group">

        <label asp-for="NewPrece"></label>
        <input asp-for="NewPrece" class="form-control" />

    </div>


  

    <input type="submit" value="Add" class="btn btn-primary" />
</form>

Here Color Form

<form method="post" asp-controller="Product" asp-action="Addimages" enctype="multipart/form-data">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>


    <div class="form-group">

        <label asp-for="color.Images"></label>
        <input asp-for="color.Images" multiple class="form-zcontrol form-control" />
        <span asp-validation-for="color.Images" class="validation"></span>
    </div>

    <div class="form-group">
        <div>
            <label asp-for="color.Name"> Choose The Product Color</label>
            <input asp-for="color.Name" name="color.Name" class="form-control" type="color">

            <span asp-validation-for="color.Name" class="validation"></span>
        </div>
    </div>
    <input asp-for="Name" name="Name" value="@Model.Name" class="form-control" hidden />
    <input asp-for="CategoryId" name="Name" value="@Model.CategoryId" class="form-control" hidden />

    <input asp-for="BrandId" name="BrandId" value="@Model.BrandId" class="form-control" hidden />

    <input asp-for="size" name="size" value="@Model.size" class="form-control" hidden />

    <input asp-for="inStock" name="inStock" value="@Model.inStock" class="form-control" hidden />

    <input asp-for="Price" name="Price" value="@Model.Price" class="form-control" hidden />
    <input asp-for="NewPrece" name="NewPrece" value="@Model.NewPrece" class="form-control" hidden />
    <input asp-for="Description" name="Description" value="@Model.Description" class="form-control" hidden />
    @if (Model.colors.Count > 0 || Model.colors != null)
        {
            for (int i = 0; i < Model.colors.Count; i++)
            {
            <div class="form-group mt-20">
            
                @if (@Model.colors[i].Images.Count > 0)
                 {
                    for (int j = 0; j < @Model.colors[i].Images.Count; j++)
                    {
                        <input class=" form-control"  asp-for="@Model.colors[i].Images[j]." name="Images" type="hidden"  />
                    }
                  }

                <input class="form-control" asp-for="colors[i].Name" type="hidden" />
            </div>
        }
    }

    <input type="submit" value="Add" class="btn btn-primary" />
    <input type="submit" value="CreateProduct" class="btn btn-primary" asp-controller="Product" asp-action="CreateProduct" />

</form>

the Problem the Colors. Images return a null list

but return the name


Solution

  • the Problem the Colors. Images return a null list but return the name

    Because you set Images name as asp-for="color.Images"

    <input asp-for="color.Images" multiple class="form-zcontrol form-control" />

    so you will pass the images list to color.Images not colors.Images.

    Update

    From persist IFormFile Upload and bind IFormFile back to View we can see:

    It's impossible to re-select the file after returning the ViewModel from server to client.

    Since, you are using <input type="file" class="form-control" /> element, we can't set value for this element, due to security reasons.

    So in your

    <input class=" form-control"  asp-for="@Model.colors[i].Images[j]." name="Images" type="hidden"  />
    

    If we remove the type="hidden" we cannot see the Images we selected before, so we cannot pass the input images from view to controller. That's the reason the color doesn't have images except the last color have the list of his images. If you change the code to

     <input class=" form-control" type="file" multiple asp-for="colors[i].Images" />
    

    result:

    enter image description here

    we will need to select again, but we can get the list of his images.If you don't want this way, we can store the list of images.