0

I want to complete the Image Upload functionality in CRUD including Create, Details, Edit, Delete, and Index. I don't know how to add Image Upload along with lines of code in CombineStagesController. I hope everyone can help me. Picture is my Image Upload Model

Below is my code.

CombineStage Model

public class CombineStage
{
    [Key]
    [ForeignKey("StageId")]
    public int StageId { get; set; }
    [Required(ErrorMessage = "Bạn chưa nhập tên công đoạn")]
    public string Name { get; set; }
    [Required(ErrorMessage = "Bạn chưa chọn công đoạn")]
    [ForeignKey("PricelistId")]
    public int PricelistId { get; set; }
    [Required(ErrorMessage = "Bạn chưa chọn ảnh")]
    public string Picture { get; set; }
    [Required(ErrorMessage = "Bạn chưa nhập giá tiền")]
    public int Price { get; set; }
    public string PricelistIdList { get; set; }
    public virtual PriceList PriceList { get; set; }
}

CombineStagesController

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using WebApp.Models;

namespace WebApp.Areas.Admin.Controllers
{
[Area("Admin")]
public class CombineStagesController : Controller
{
    private readonly ManageContext _context;

    public CombineStagesController(ManageContext context)
    {
        _context = context;
    }

    // GET: Admin/CombineStages
    public async Task<IActionResult> Index()
    {
        var manageContext = _context.CombineStage.Include(c => c.PriceList);
        return View(await manageContext.ToListAsync());
    }

    // GET: Admin/CombineStages/Details/5
    public async Task<IActionResult> Details(int? id)
    {
        if (id == null || _context.CombineStage == null)
        {
            return NotFound();
        }

        var combineStage = await _context.CombineStage
            .Include(c => c.PriceList)
            .FirstOrDefaultAsync(m => m.StageId == id);
        int[] PriceIdList = combineStage.PricelistIdList.Split(',').Select(n => Convert.ToInt32(n)).ToArray();
        List<PriceList> priceLists = new List<PriceList>();
        foreach (var PriceId in PriceIdList)
        {
            var PriceDetails = _context.PriceLists.Where(c => c.PricelistId == PriceId).FirstOrDefault();
            priceLists.Add(PriceDetails);
        }
        ViewBag.priceLists = priceLists;
        if (combineStage == null)
        {
            return NotFound();
        }

        return View(combineStage);
    }

    // GET: Admin/CombineStages/Create
    public IActionResult Create()
    {
        var priceLists = _context.PriceLists.ToList();
        List<SelectListItem> mylist = new List<SelectListItem>();
        foreach (var price in priceLists)
        {
            mylist.Add(new SelectListItem { Text = price.Stage, Value = price.PricelistId.ToString() });

        }
        ViewBag.PricelistId = mylist;
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create([Bind("Name,PricelistId,Picture,Price,PriceList")] CombineStage combineStage, int[] PricelistId)
    {
        int price = 0;
        var stage = "";
        PriceList priceList = new PriceList();

        foreach (var id in PricelistId)
        {
            stage = _context.PriceLists.Where(m => m.PricelistId == id).FirstOrDefault().Stage.ToString();
            price += _context.PriceLists.Where(m => m.PricelistId == id).FirstOrDefault().Price;
            priceList = _context.PriceLists.Where(m => m.PricelistId == id).FirstOrDefault();

        }
        combineStage.Price = price;
        combineStage.PriceList = priceList;
        combineStage.PricelistIdList = string.Join(",", PricelistId);
        ModelState.Clear();
        if (TryValidateModel(combineStage))
        {
            _context.Add(combineStage);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(combineStage);
    }

    // GET: Admin/CombineStages/Edit/5
    public async Task<IActionResult> Edit(int? id)
    {
        if (id == null || _context.CombineStage == null)
        {
            return NotFound();
        }

        var combineStage = await _context.CombineStage
            .Include(c => c.PriceList)
            .FirstOrDefaultAsync(m => m.StageId == id);
        int[] PriceIdList = combineStage.PricelistIdList.Split(',').Select(n => Convert.ToInt32(n)).ToArray();
        List<PriceList> priceLists = new List<PriceList>();
        foreach (var PriceId in PriceIdList)
        {
            var PriceDetails = _context.PriceLists.Where(c => c.PricelistId == PriceId).FirstOrDefault();
            priceLists.Add(PriceDetails);
        }
        ViewBag.priceLists = priceLists;

        if (combineStage == null)
        {
            return NotFound();
        }
        ViewData["PricelistId"] = new SelectList(_context.PriceLists, "PricelistId", "Stage", combineStage.PricelistId);
        return View(combineStage);
    }

    // POST: Admin/CombineStages/Edit/5
    // To protect from overposting attacks, enable the specific properties you want to bind to.
    // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(int id, [Bind("StageId,Name,PricelistId,Picture,Price")] CombineStage combineStage)
    {
        if (id != combineStage.StageId)
        {
            return NotFound();
        }

        if (ModelState.IsValid)
        {
            try
            {
                _context.Update(combineStage);
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!CombineStageExists(combineStage.StageId))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }
            return RedirectToAction(nameof(Index));
        }
        ViewData["PricelistId"] = new SelectList(_context.PriceLists, "PricelistId", "Stage", combineStage.PricelistId);
        return View(combineStage);
    }

    // GET: Admin/CombineStages/Delete/5
    public async Task<IActionResult> Delete(int? id)
    {
        if (id == null || _context.CombineStage == null)
        {
            return NotFound();
        }

        var combineStage = await _context.CombineStage
            .Include(c => c.PriceList)
            .FirstOrDefaultAsync(m => m.StageId == id);
        if (combineStage == null)
        {
            return NotFound();
        }

        return View(combineStage);
    }

    // POST: Admin/CombineStages/Delete/5
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeleteConfirmed(int id)
    {
        if (_context.CombineStage == null)
        {
            return Problem("Entity set 'ManageContext.CombineStage'  is null.");
        }
        var combineStage = await _context.CombineStage.FindAsync(id);
        if (combineStage != null)
        {
            _context.CombineStage.Remove(combineStage);
        }
        
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }

    private bool CombineStageExists(int id)
    {
      return _context.CombineStage.Any(e => e.StageId == id);
    }
}
}

Create.cshtml

@model WebApp.Models.CombineStage

@{
ViewData["Title"] = "Create";
Layout = "~/Areas/Admin/Views/Shared/_AdminLayout.cshtml";
}

<h1>Create</h1>

<h4>CombineStage</h4>
<hr />
<div class="row">
<div class="col-md-4">
    <form asp-action="Create">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="Name" class="control-label"></label>
            <input asp-for="Name" class="form-control" />
            <span asp-validation-for="Name" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="PricelistId" class="control-label"></label>
            <select asp-for="PricelistId" class="form-control" asp-items="ViewBag.PricelistId" multiple id="Subjects_dropdown">
            </select>
        </div>
        <div class="form-group">
            <label asp-for="Picture" class="control-label"></label>
            <input asp-for="Picture" class="form-control" />
            <span asp-validation-for="Picture" class="text-danger"></span>
        </div>
        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary" />
        </div>
    </form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>

</div>

@section Scripts {

@{
    await Html.RenderPartialAsync("_ValidationScriptsPartial");
}


<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-multiselect/0.9.13/js/bootstrap-multiselect.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-multiselect/0.9.13/css/bootstrap-multiselect.css">
<script>

    $(document).ready(function () {

        $('#Subjects_dropdown').multiselect();
    });
</script>
}

Update my expectations

I want to use multiple select and image upload here.

enter image description here

enter image description here

enter image description here

Update2

I want to display it on Details Page like this

enter image description here

Edit Update3

enter image description here

  • Does this answer your question? [uploading image asp.net Core](https://stackoverflow.com/questions/47125439/uploading-image-asp-net-core) – Ebbelink Sep 28 '22 at 06:34
  • @Ebbelink It's correct but only partially correct that I want. I want the lines of code to handle the CRUD function in my code. In there I also handle some functions but I don't know how to add Image Upload. It's completely different from how I coded my previous Image Upload. Before that, I used ViewModel for Image Upload. Not like this – Lâm Trương Sep 28 '22 at 06:48

1 Answers1

1

Change the type of Picture in Model from String to byte[]:

public byte[] Picture { get; set; }

Change the Create method and View:

Controller:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Name,PricelistId,Picture,Price,PriceList")] CombineStage combineStage, int[] PricelistId, IFormFile ImageFile)
{
    using (var ms = new MemoryStream())
    {
        ImageFile.CopyTo(ms);
        combineStage.Picture = ms.ToArray();
    }
    //...
    //Your other code
}

Create.cshtml (Change the Picture part to file upload):

@model _2022092602.Models.CombineStage

@{
ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>CombineStage</h4>
<hr />
<div class="row">
<div class="col-md-4">
     <form asp-action="Create" enctype="multipart/form-data">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="Name" class="control-label"></label>
            <input asp-for="Name" class="form-control" />
            <span asp-validation-for="Name" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="PricelistId" class="control-label"></label>
            <select asp-for="PricelistId" class ="form-control" asp-items="@ViewBag.PricelistId" multiple>
                
            </select>
        </div>
        <div class="form-group">
            <input type="file" name="ImageFile" class="form-control" />
        </div>
        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary" />
        </div>
    </form>
</div>

In this way, when you upload an image when you create it, your image will be saved in the database in the form of base64String, which is convenient for you to use on other pages.

If you want to display this image on the Index page, use this way:

<td>
      <img style="width:30px;" class="img-responsive full-width" src="data:image/jpg;base64,@Convert.ToBase64String(item.Picture)" />
</td>

Hope this can help you.

Edit:

Data Type in Database:

enter image description here

Update:

Controller:

public class CombineStagesController : Controller
    {
        private readonly ManageContext _context;

        public CombineStagesController(ManageContext context)
        {
            _context = context;
        }
        // GET: Admin/CombineStages/Details/5
        public async Task<IActionResult> Details(int? id)
        {
            if (id == null || _context.CombineStage == null)
            {
                return NotFound();
            }

            var combineStage = await _context.CombineStage
                .Include(c => c.PriceList)
                .FirstOrDefaultAsync(m => m.StageId == id);
            int[] PriceIdList = combineStage.PricelistIdList.Split(',').Select(n => Convert.ToInt32(n)).ToArray();
            List<PriceList> priceLists = new List<PriceList>();
            foreach(var PriceId in PriceIdList)
            {
                var PriceDetails = _context.PriceLists.Where(c => c.PricelistId == PriceId).FirstOrDefault();
                priceLists.Add(PriceDetails);
            }
            ViewBag.priceLists = priceLists;
            if (combineStage == null)
            {
                return NotFound();
            }

            return View(combineStage);
        }
        // GET: Admin/CombineStages/Edit/5
        public async Task<IActionResult> Edit(int? id)
        {
            var priceLists = _context.PriceLists.ToList();
            List<SelectListItem> mylist = new List<SelectListItem>();
            foreach (var price in priceLists)
            {
                mylist.Add(new SelectListItem { Text = price.Stage, Value = price.PricelistId.ToString() });

            }
            ViewBag.PricelistId = mylist;

            var combineStage = await _context.CombineStage
                .Include(c => c.PriceList)
                .FirstOrDefaultAsync(m => m.StageId == id);
            int[] PriceIdList = combineStage.PricelistIdList.Split(',').Select(n => Convert.ToInt32(n)).ToArray();

            List<PriceList> priceList = new List<PriceList>();
            foreach (var PriceId in PriceIdList)
            {
                var PriceDetails = _context.PriceLists.Where(c => c.PricelistId == PriceId).FirstOrDefault();
                priceLists.Add(PriceDetails);
            }
            ViewBag.priceLists = priceList;



            if (id == null || _context.CombineStage == null)
            {
                return NotFound();
            }

            
            if (combineStage == null)
            {
                return NotFound();
            }
            
            return View(combineStage);
        }

        // POST: Admin/CombineStages/Edit/5
        // To protect from overposting attacks, enable the specific properties you want to bind to.
        // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, [Bind("StageId,Name,PricelistId,Picture,Price")] CombineStage combineStage, int[] PricelistId, IFormFile ImageFile)
        {
            using (var ms = new MemoryStream())
            {
                ImageFile.CopyTo(ms);
                combineStage.Picture = ms.ToArray();
            }
            int price = 0;
            var stage = "";
            PriceList priceList = new PriceList();

            foreach (var PriceId in PricelistId)
            {
                stage = _context.PriceLists.Where(m => m.PricelistId == PriceId).FirstOrDefault().Stage.ToString();
                price += _context.PriceLists.Where(m => m.PricelistId == PriceId).FirstOrDefault().Price;
                priceList = _context.PriceLists.Where(m => m.PricelistId == PriceId).FirstOrDefault();

            }
            combineStage.Price = price;
            combineStage.PriceList = priceList;
            combineStage.PricelistIdList = string.Join(",", PricelistId);
            ModelState.Clear();
            if (TryValidateModel(combineStage))
            {
                _context.Update(combineStage);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(combineStage);
        }
        // GET: Admin/CombineStages/Delete/5
        public async Task<IActionResult> Delete(int? id)
        {
            if (id == null || _context.CombineStage == null)
            {
                return NotFound();
            }

            var combineStage = await _context.CombineStage
                .Include(c => c.PriceList)
                .FirstOrDefaultAsync(m => m.StageId == id);
            if (combineStage == null)
            {
                return NotFound();
            }

            return View(combineStage);
        }

        // POST: Admin/CombineStages/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(int id)
        {
            if (_context.CombineStage == null)
            {
                return Problem("Entity set 'ManageContext.CombineStage'  is null.");
            }
            var combineStage = await _context.CombineStage.Where(c => c.StageId == id).FirstOrDefaultAsync();
            if (combineStage != null)
            {
                _context.CombineStage.Remove(combineStage);
            }

            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
    }

Details.cshtml:

@model _2022092602.Models.CombineStage

<div>@Model.Name</div>
<div><img style="width:30px;" class="img-responsive full-width" src="data:image/jpg;base64,@Convert.ToBase64String(Model.Picture)" /></div>
<div>@Model.Price</div>

<div>
    @foreach (var price in ViewBag.priceLists)
    {
        <div>
            <span>@price.PricelistId</span>
            <span>@price.Price</span>
            <span>@price.Stage</span>
        </div>

    }
</div>

Delete.cshtml:

@model _2022092602.Models.CombineStage

<h1>Delete</h1>

<h3>Are you sure to delete this?</h3>

<div>
    <dl class="row">
        <dt class="con-sm-2">
            @Html.DisplayNameFor(model => model.Name)
        </dt>
        <dt class="col-sm-10">
            @Html.DisplayFor(model => model.Name)
        </dt>
        <dt class="con-sm-2">
            @Html.DisplayNameFor(model => model.Picture)
        </dt>
        <dt class="col-sm-10">
            <img style="width:30px;" class="img-responsive full-width" src="data:image/jpg;base64,@Convert.ToBase64String(Model.Picture)" />
        </dt>
        <dt class="con-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dt class="col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dt>
    </dl>

    <form asp-action="Delete">
        <input type="hidden" asp-for="StageId" />
        <input type="submit" value="Delete" class="btn btn-danger" /> |
        <a asp-action="Index">Back to List</a>
    </form>
</div>

Edit.cshtml:

@model _2022092602.Models.CombineStage

<h1>Edit</h1>

<div class="row">
    <div class="col-md-4">
        <form asp-action="Edit" enctype="multipart/form-data">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="StageId" />
            <div class="form-group">
                <label asp-for="Name" class="control-label"></label>
                <input asp-for="Name" class="form-control" />
            </div>
            <div class="form-group">
                <label asp-for="PricelistId" class="control-label"></label>
                <select asp-for="PricelistId" class ="form-control" asp-items="@ViewBag.PricelistId" multiple>
                </select>
            </div>
            <div class="form-group">
                <label asp-for="Picture" class="control-label"></label>
                <span><img id="Picture" style="width:100px;" class="img-responsive full-width" src="data:image/jpg;base64,@Convert.ToBase64String(Model.Picture)" /></span>
                <input type="file"  name="ImageFile" class="form-control" onchange="readURL(this);" />
            </div>
            <div class="form-control">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script>
    function readURL(input) {
      if (input.files && input.files[0]) {
        var reader = new FileReader();

        reader.onload = function (e) {
          $('#Picture').attr('src', e.target.result).width(100);
        };

        reader.readAsDataURL(input.files[0]);
      }
    }

</script>
Chen
  • 4,499
  • 1
  • 2
  • 9
  • Your code is very useful but I have some problems with my project. – Lâm Trương Sep 28 '22 at 09:39
  • First, I get the error InvalidCastException: Unable to cast object of type 'System.String' to type 'System.Byte[]'. Second, I want to create a website based on the code I created. My images will be saved directly in the database. As for your image, I don't know how to save it. If I create a website, will the data go wrong somewhere? Third, give me some code to use Delete, Details, and Edit for your Image Upload. Thanks – Lâm Trương Sep 28 '22 at 09:50
  • Where do you get this error? Please describe the effect you want like in the previous post, so that I can test the code. @Lâm Trương – Chen Sep 29 '22 at 01:07
  • First, I need to fix the bug, and then I will show you my expectations for the project. – Lâm Trương Sep 29 '22 at 02:02
  • You did not update the datatype of the Picture field in the database. It should be `varbinary(MAX)`. I would update the data type in the database table. @Lâm Trương – Chen Sep 29 '22 at 02:55
  • I can not update database with varbinary(MAX). My error is Implicit conversion from data type nvarchar(max) to varbinary(max) is not allowed. Use the CONVERT function to run this query. How can I convert it? – Lâm Trương Sep 29 '22 at 03:00
  • So do I need to delete this table and create a new one with Picture data type varbinary(MAX) and scaffold force it into visual studio? – Lâm Trương Sep 29 '22 at 03:07
  • 1
    This may be because there are records in your database table, you only need to delete the data saved in the database to update it without rebuilding a table. – Chen Sep 29 '22 at 03:11
  • @ Oh, I'm done with it. Thank you. So now, I will show you my expectations. – Lâm Trương Sep 29 '22 at 03:32
  • 1
    I update my answer, you can refer to it. @Lâm Trương – Chen Sep 29 '22 at 07:35
  • Your answer is so good but on the Detail Page, I want to display more Machine. So, let me show you what I want in Update2. – Lâm Trương Sep 29 '22 at 08:18
  • In my example, Details is loaded through `ViewBag.priceLists`, and `Machine` is also in it, you can display it like any other data. – Chen Sep 29 '22 at 08:44
  • Oh sorry, my bad. I was a little confused. Thank you so much. So this question is done here. See you in my next question. LOL ~~ – Lâm Trương Sep 29 '22 at 08:53
  • Allow me to ask you the last question in this function. Let's see my edit Update3. – Lâm Trương Sep 29 '22 at 09:56
  • You can use [EnumHelper](https://stackoverflow.com/a/65975541/18789859) to achieve. Or use JavaScript in the page to convert OneK to 1K. – Chen Sep 30 '22 at 01:10
  • Excuse me, I will use EnumHelper in my code to convert OneK to 1K in Pricelist Model. But it does not work. It can only work from the Pricelist model. And the dynamic price is not. As for Javascript, I've never done it so I don't know how it works. So can you help me convert OneK to 1K? Thank you so much – Lâm Trương Oct 01 '22 at 17:51
  • this is my new question: https://stackoverflow.com/questions/73924494/how-to-get-value-from-two-foreign-keys-for-multiple-select. I hope you can help me solve this trouble. Thank you! – Lâm Trương Oct 02 '22 at 09:15