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.
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.
All the selected photos should be uploaded to wwwroot/images folder on the web server.
Employee Model Class
EmployeeCreateViewModel Class
Create View Code
Create Action Method
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.
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.
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();
}
}
}
Hi, I would love to see the project source since I don't get the list of selected files.
ReplyDelete// This line is not safe. If you try to delete an image after you add it //then an exception will be thrown.
ReplyDeletephoto.CopyTo(new FileStream(filePath, FileMode.Create));
//Use this instead
using(var stream = new FileStream(filePath, FileMode.Create))
{
photo.CopyTo(stream);
}
Also, another error displayed, if you try to display an image without clear your buffer for this stream.
DeleteSo add this line after photo.copyTo(stream):
using(var stream = new FileStream(filePath, FileMode.Create))
{
photo.CopyTo(stream);
//this line
stream.Flush();
}