3

I wanted to add an image as part of the model class and display it on the index view. I'm having problems either classifying the image as a byte[] or iFormFile.

This is what I'm trying to achieve

  1. Create a page to insert a list of employees

  2. In the index page, able to list the employees and see their images as well.

Here's the model.

Employee.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;

namespace MvcMovie.Models
{
  public class Employee
  {
    public int ID { get; set; }
    [Required]
    public string FirstName { get; set; }
    [Required]
    public string LastName { get; set; }
    [Required]
    public string Nationality { get; set; }
    [Required]
    public string NRIC { get; set; }
    [Required]
    public string StaffID { get; set; }
    [Required]
    public int AccessRights { get; set; }
    [Required]
    public DateTime DOB { get; set; }

    [Required(ErrorMessage = "Please Upload a Valid Image File. Only jpg format allowed")]
    [DataType(DataType.Upload)]
    [Display(Name = "Upload Product Image")]
    [FileExtensions(Extensions = "jpg")]
    public IFormFile Image { get; set; }

    public string ImageName { get; set; }
  }
}

This is the section of code of the controller that generates the error.

EmployeeController.cs

[HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(Employee employee, IFormFile    Image) 
    {
        if (ModelState.IsValid)
        {

            if (Image != null && Image.Length > 0)
            {

                var file = Image;
                var uploads = Path.Combine(_environment.WebRootPath, "uploads\\img\\employees");

                if (file.Length > 0)
                {
                    var fileName = ContentDispositionHeaderValue.Parse
                        (file.ContentDisposition).FileName.Trim('"');

                    System.Console.WriteLine(fileName);
                    using (var fileStream = new FileStream(Path.Combine(uploads, file.FileName), FileMode.Create))
                    {
                        await file.CopyToAsync(fileStream);
                        employee.ImageName = Path.Combine(uploads, file.FileName);
                    }

                    var imageUrl = Path.Combine(uploads + file.FileName);

                }
            }

            _context.Add(employee);
            await _context.SaveChangesAsync();
            return RedirectToAction("Index");

        }
        else
        {
            var errors = ModelState.Values.SelectMany(v => v.Errors);
        }
        return View(employee);
    }

Create.cshtml

<form asp-action="Create" enctype="multipart/form-data" asp-antiforgery="true"  method="post">
 <div>
      ...

      <div class="form-group">
          <label asp-for="Image" class="control-label col-md-2"></label>
          <div class="col-md-10">
               <input asp-for="Image" class="form-control" />
               <span  class="text-danger"></span>
          </div>
      </div>
      <div class="form-group">
          <div class="col-md-offset-2 col-md-10">
          <input type="submit" value="Create" class="btn btn-default" />
      </div>
  </div>
</form>

I managed to upload the image into the correct folder. However, i have problem with the statement "_context.Add(employee)". It says that I couldn't add an iformfile. I've no issue with the other fields.

I tried changing Employee.Image to a byte array. However, I'm confused how to structure my view to pass this information to the create function.

5
  • I'd suggest u to not upload ur file to Database. But instead upload its path only. Commented Nov 6, 2016 at 8:37
  • I intend to create web app to allow users to upload file into the server. Do you mean I should create my model class to include only the string. And handle it differently in controller, view and cshtml separately? Commented Nov 6, 2016 at 14:58
  • Hi ar27111994, I've updated the model accordingly. However, I faced some problem updating the database. See here. It seems what I've done is correct, but unable to update the database. I'm new to ASP.net and C# for that matter and is confused at how migrations works. Commented Nov 6, 2016 at 16:30
  • Please watch ASP.NET Core Tutorials on Microsoft Virtual Academy website and avoid posting unrelated and/or duplicate questions on this forum. Apparently you need to learn a lot about Web Development in ASP.NET in general. Thanks. Commented Nov 6, 2016 at 18:44
  • Yes. I'm new to ASP.net, C# and Web development. Regarding the database issue, its a migration issue. And removing all the migrations, creating a new migration and changed the SQL statements according does the trick. Thanks Commented Nov 6, 2016 at 21:52

1 Answer 1

5

Like what ar27111994 suggested, I store the image name and extension instead. The image is saved somewhere in wwwroot.

Here's the change

Employee.cs

public class Employee
{
    [Key]
    public int ID { get; set; }
    [Required]
    public string FirstName { get; set; }
    [Required]
    public string LastName { get; set; }
    [Required]
    public string Nationality { get; set; }
    [Required]
    public string NRIC { get; set; }
    [Required]
    public string StaffIdentity { get; set; }
    [Required]
    public int AccessRights { get; set; }
    [Required]
    public DateTime DOB { get; set; }

    public string ImageName { get; set; }
}

create.cshtml

<div class="form-group">
     <label class="col-md-2 control-label">Employee Image</label>
     <div class="col-md-10">
          <input  class="form-control"  type="file" name="pic" accept="image/*"/>             
     </div>
</div>
<div class="form-group">
     <div class="col-md-offset-2 col-md-10">
          <input type="submit" value="Create" class="btn btn-default" />
     </div>
</div>

EmployeeController.cs

[HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create([Bind("ID,AccessRights,DOB,FirstName,LastName,NRIC,Nationality,StaffIdentity")]Employee employee) 
    {
        if (ModelState.IsValid)
        {
            var files = HttpContext.Request.Form.Files;
            foreach (var Image in files)
            {
                if (Image != null && Image.Length > 0)
                {

                    var file = Image;
                    var uploads = Path.Combine(_environment.WebRootPath, "uploads\\img\\employees");

                    if (file.Length > 0)
                    {
                        var fileName = ContentDispositionHeaderValue.Parse
                            (file.ContentDisposition).FileName.Trim('"');

                        System.Console.WriteLine(fileName);
                        using (var fileStream = new FileStream(Path.Combine(uploads, file.FileName), FileMode.Create))
                        {
                            await file.CopyToAsync(fileStream);
                            employee.ImageName = file.FileName;
                        }


                    }
                }
            }

            _context.Add(employee);
            await _context.SaveChangesAsync();
            return RedirectToAction("Index");

        }
        else
        {
            var errors = ModelState.Values.SelectMany(v => v.Errors);
        }
        return View(employee);
    }
Sign up to request clarification or add additional context in comments.

1 Comment

Why does var files = HttpContext.Request.Form.Files; only bring back the last file when name=files[]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.