Support us .Net Basics C# SQL ASP.NET Aarvi MVC Slides C# Programs Subscribe Download

Upload multiple files in asp.net core mvc

Suggested Videos
Part 51 - Entity framework core seed data | Text | Slides
Part 52 - Keeping domain models and database schema in sync in asp.net core | Text | Slides
Part 53 - File upload in asp.net core mvc | Text | Slides

In this video we will discuss how to upload multiple files in asp.net core. This is continuation to Part 53. Please watch Part 53 from ASP.NET Core tutorial before proceeding.


We will use the following Create Employee Form to understand uploading multiple files in ASP.NET Core. When we click on the Photo filed on the form, we should be able to select multiple files that we want to upload.


upload multiple files in asp.net core mvc

When this Create Employee Form is submitted, we want to store Employee data i.e Name, Email, Department and PhotoPath in Employees database table. Here is the Employees database table. This table is created using Migrations in ASP.NET Core.

upload multiple images in asp.net core

All the selected photos should be uploaded to wwwroot/images folder on the web server.

Employee Model Class

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public Dept? Department { get; set; }
    public string PhotoPath { get; set; }
}

EmployeeCreateViewModel Class

public class EmployeeCreateViewModel
{
    public string Name { get; set; }
    public string Email { get; set; }
    public Dept? Department { get; set; }
    public List<IFormFile> Photos { get; set; }
}
  • IFormFile is in Microsoft.AspNetCore.Http namespace.
  • The file uploaded to the server can be accessed through Model Binding using the IFormFile interface.
  • The Photos property receives the uploaded files through Model Binding 
  • To support multiple files upload we have set the data type of Photos property to List<IFormFile>
  • The interface IFormFile has the following properties and methods
public interface IFormFile
{
    string ContentType { get; }
    string ContentDisposition { get; }
    IHeaderDictionary Headers { get; }
    long Length { get; }
    string Name { get; }
    string FileName { get; }
    Stream OpenReadStream();
    void CopyTo(Stream target);
    Task CopyToAsync(Stream target, CancellationToken cancellationToken = null);
}

Create View Code

@model EmployeeCreateViewModel

@{
    ViewBag.Title = "Create Employee";
}

@*To support file upload set the form element enctype="multipart/form-data" *@

<form enctype="multipart/form-data" asp-controller="home" asp-action="create"
      method="post" class="mt-3">
    <div class="form-group row">
        <label asp-for="Name" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="Name" class="form-control" placeholder="Name">
            <span asp-validation-for="Name" class="text-danger"></span>
        </div>
    </div>
    <div class="form-group row">
        <label asp-for="Email" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <input asp-for="Email" class="form-control" placeholder="Email">
            <span asp-validation-for="Email" class="text-danger"></span>
        </div>
    </div>

    <div class="form-group row">
        <label asp-for="Department" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <select asp-for="Department" class="custom-select mr-sm-2"
                    asp-items="Html.GetEnumSelectList<Dept>()">
                <option value="">Please Select</option>
            </select>
            <span asp-validation-for="Department" class="text-danger"></span>
        </div>
    </div>

    @*  asp-for tag helper is set to "Photo" property. "Photo" property type is IFormFile
        so at runtime asp.net core generates file upload control (input type=file). To
        support multiple files upload include multiple attribute on the input element

    *@

    <div class="form-group row">
        <label asp-for="Photos" class="col-sm-2 col-form-label"></label>
        <div class="col-sm-10">
            <div class="custom-file">
                <input asp-for="Photos" multiple class="form-control custom-file-input">
                <label class="custom-file-label">Choose File...</label>
            </div>
        </div>
    </div>

    <div asp-validation-summary="All" class="text-danger"></div>

    <div class="form-group row">
        <div class="col-sm-10">
            <button type="submit" class="btn btn-primary">Create</button>
        </div>
    </div>

    @*This script is required to display the selected file in the file upload element
        If a sinle file is selected, the name of the file is displayed. If multiple
        files are selected, then the count of files is displayed.*@

    @section Scripts {
        <script>
            $(document).ready(function () {
                $('.custom-file-input').on("change", function () {
                    var fileLabel = $(this).next('.custom-file-label');
                    var files = $(this)[0].files;
                    if (files.length > 1) {
                        fileLabel.html(files.length + ' files selected');
                    }
                    else if (files.length == 1) {
                        fileLabel.html(files[0].name);
                    }
                });
            });
        </script>
    }
</form>

Create Action Method

using EmployeeManagement.Models;
using EmployeeManagement.ViewModels;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace EmployeeManagement.Controllers
{
    public class HomeController : Controller
    {
        private IEmployeeRepository _employeeRepository;
        private readonly IHostingEnvironment hostingEnvironment;

        public HomeController(IEmployeeRepository employeeRepository, IHostingEnvironment hostingEnvironment)
        {
            _employeeRepository = employeeRepository;
            this.hostingEnvironment = hostingEnvironment;
        }

        [HttpGet]
        public ViewResult Create()
        {
            return View();
        }

        [HttpPost]
        public IActionResult Create(EmployeeCreateViewModel model)
        {
            if (ModelState.IsValid)
            {
                string uniqueFileName = null;

                // If the Photos property on the incoming model object is not null and if count > 0,
                // then the user has selected at least one file to upload

                if (model.Photos != null && model.Photos.Count > 0)
                {
                    // Loop thru each selected file
                    foreach (IFormFile photo in model.Photos)
                    {
                        // The file must be uploaded to the images folder in wwwroot
                        // To get the path of the wwwroot folder we are using the injected
                        // IHostingEnvironment service provided by ASP.NET Core
                        string uploadsFolder = Path.Combine(hostingEnvironment.WebRootPath, "images");
                        // To make sure the file name is unique we are appending a new
                        // GUID value and and an underscore to the file name
                        uniqueFileName = Guid.NewGuid().ToString() + "_" + photo.FileName;
                        string filePath = Path.Combine(uploadsFolder, uniqueFileName);
                        // Use CopyTo() method provided by IFormFile interface to
                        // copy the file to wwwroot/images folder
                        photo.CopyTo(new FileStream(filePath, FileMode.Create));
                    }
                }

                Employee newEmployee = new Employee
                {
                    Name = model.Name,
                    Email = model.Email,
                    Department = model.Department,
                    PhotoPath = uniqueFileName
                };

                _employeeRepository.Add(newEmployee);
                return RedirectToAction("details", new { id = newEmployee.Id });
            }

            return View();
        }
    }
}

asp.net core tutorial for beginners

3 comments:

  1. Hi, I would love to see the project source since I don't get the list of selected files.

    ReplyDelete
  2. // This line is not safe. If you try to delete an image after you add it //then an exception will be thrown.
    photo.CopyTo(new FileStream(filePath, FileMode.Create));

    //Use this instead
    using(var stream = new FileStream(filePath, FileMode.Create))
    {
    photo.CopyTo(stream);
    }

    ReplyDelete
    Replies
    1. Also, another error displayed, if you try to display an image without clear your buffer for this stream.
      So add this line after photo.copyTo(stream):

      using(var stream = new FileStream(filePath, FileMode.Create))
      {
      photo.CopyTo(stream);

      //this line
      stream.Flush();
      }

      Delete

It would be great if you can help share these free resources