How to upload files in ASP.NET Core?
Asked Answered
P

7

81

How to upload files or images using ASP.NET MVC 6 with some model data?

For example, I have a form like this:

<form>
    <input type="file">
    <input type="text" placeholder="Image name...">
    <input type="text" placeholder="Image description...">
    <input type="submit" value="Submit">
</form>

I read many Tutorials in how to upload but I don't see anything uploading with some data like the form above.

Also, is there any library for image manipulation for re-sizing and Image Watermarking same as Codeigniter image manipulation class? (https://codeigniter.com/user_guide/libraries/image_lib.html

Pistareen answered 13/2, 2016 at 11:31 Comment(1)
Seems this was published recently -> learn.microsoft.com/en-us/aspnet/core/mvc/models/…Matz
O
147

You can add a new property of type IFormFile to your view model

public class CreatePost
{
   public string ImageCaption { set;get; }
   public string ImageDescription { set;get; }
   public IFormFile MyImage { set; get; }
}

and in your GET action method, we will create an object of this view model and send to the view.

public IActionResult Create()
{
   return View(new CreatePost());
}

Now in your Create view which is strongly typed to our view model, have a form tag which has the enctype attribute set to "multipart/form-data"

@model CreatePost
<form asp-action="Create" enctype="multipart/form-data">   

    <input asp-for="ImageCaption"/>
    <input asp-for="ImageDescription"/>
    <input asp-for="MyImage"/>

    <input type="submit"/>
</form>

And your HttpPost action to handle the form posting

[HttpPost]
public IActionResult Create(CreatePost model)
{
   var img = model.MyImage;
   var imgCaption = model.ImageCaption;

   //Getting file meta data
   var fileName = Path.GetFileName(model.MyImage.FileName);
   var contentType = model.MyImage.ContentType;

   // do something with the above data
   // to do : return something
}

If you want to upload the file to some directory in your app, you should use IHostingEnvironment to get the webroot path. Here is a working sample.

public class HomeController : Controller
{
    private readonly IHostingEnvironment hostingEnvironment;
    public HomeController(IHostingEnvironment environment)
    {
        hostingEnvironment = environment;
    }
    [HttpPost]
    public IActionResult Create(CreatePost model)
    {
        // do other validations on your model as needed
        if (model.MyImage != null)
        {
            var uniqueFileName = GetUniqueFileName(model.MyImage.FileName);
            var uploads = Path.Combine(hostingEnvironment.WebRootPath, "uploads");
            var filePath = Path.Combine(uploads,uniqueFileName);
            model.MyImage.CopyTo(new FileStream(filePath, FileMode.Create)); 

            //to do : Save uniqueFileName  to your db table   
        }
        // to do  : Return something
        return RedirectToAction("Index","Home");
    }
    private string GetUniqueFileName(string fileName)
    {
        fileName = Path.GetFileName(fileName);
        return  Path.GetFileNameWithoutExtension(fileName)
                  + "_" 
                  + Guid.NewGuid().ToString().Substring(0, 4) 
                  + Path.GetExtension(fileName);
    }
}

This will save the file to uploads folder inside wwwwroot directory of your app with a random file name generated using Guids ( to prevent overwriting of files with same name)

Here we are using a very simple GetUniqueName method which will add 4 chars from a guid to the end of the file name to make it somewhat unique. You can update the method to make it more sophisticated as needed.

Should you be storing the full url to the uploaded image in the database ?

No. Do not store the full url to the image in the database. What if tomorrow your business decides to change your company/product name from www.thefacebook.com to www.facebook.com ? Now you have to fix all the urls in the table!

What should you store ?

You should store the unique filename which you generated above(the uniqueFileName varibale we used above) to store the file name. When you want to display the image back, you can use this value (the filename) and build the url to the image.

For example, you can do this in your view.

@{
    var imgFileName = "cats_46df.png";
}
<img src="~/uploads/@imgFileName"  alt="my img"/>

I just hardcoded an image name to imgFileName variable and used that. But you may read the stored file name from your database and set to your view model property and use that. Something like

<img src="~/uploads/@Model.FileName"  alt="my img"/>

Storing the image to table

If you want to save the file as bytearray/varbinary to your database, you may convert the IFormFile object to byte array like this

private byte[] GetByteArrayFromImage(IFormFile file)
{
    using (var target = new MemoryStream())
    {
        file.CopyTo(target);
        return target.ToArray();
    }
}

Now in your http post action method, you can call this method to generate the byte array from IFormFile and use that to save to your table. the below example is trying to save a Post entity object using entity framework.

[HttpPost]
public IActionResult Create(CreatePost model)
{
    //Create an object of your entity class and map property values
    var post=new Post() { ImageCaption = model.ImageCaption };

    if (model.MyImage != null)
    {
       post.Image =  GetByteArrayFromImage(model.MyImage);
    }
    _context.Posts.Add(post);
    _context.SaveChanges();
    return RedirectToAction("Index","Home");
}
Osman answered 13/2, 2016 at 21:21 Comment(10)
Hi Shyju, I tried your example above but didn't work for me. The image gets to the Create method within the CreatePost object as null (the other properties are correctly filled). I will continue looking into this and will let you know if I find anything. In case you have any suggestions, please let me know.Callao
does your form has enctype="multipart/form-data" ?Osman
This solution does not work for me, event if i add enctype="multipart/form-data" to my form. Any idea what could be the problem? The IFormFile always is null.Plash
check whether your property has a set;. Also make sure that the input file name matches with your property name.Osman
using the code above I found it helpful to close the file after using FileMode.Create otherwise a 0kb file was created that was in use by .net until I stopped debugging var newfile = new FileStream(filePath, FileMode.CreateNew); file.CopyTo(newfile); newfile.Close();Italic
IHostingEnvironment has since been deprecated. Use IWebHostEnvironment instead.Hagioscope
Closing the stream is the key here. Otherwise, the data is just in the memory.Ephraimite
@Callao did you find solution for the null? I found that putting the IFromFile as a parameter of the action works, but I want to keep it in the model, any solution?Guide
Good example indeed! Works like a charm.Raynor
One change: Instead of model.MyImage.CopyTo(new FileStream(filePath, FileMode.Create)); I used : using (var stream = new FileStream(filePath, FileMode.Create)) { model.MyImage.CopyTo(stream); } This way works best.Raynor
C
27
 <form class="col-xs-12" method="post" action="/News/AddNews" enctype="multipart/form-data">

     <div class="form-group">
        <input type="file" class="form-control" name="image" />
     </div>

     <div class="form-group">
        <button type="submit" class="btn btn-primary col-xs-12">Add</button>
     </div>
  </form>

My Action Is

        [HttpPost]
        public IActionResult AddNews(IFormFile image)
        {
            Tbl_News tbl_News = new Tbl_News();
            if (image!=null)
            {

                //Set Key Name
                string ImageName= Guid.NewGuid().ToString() + Path.GetExtension(image.FileName);

                //Get url To Save
                string SavePath = Path.Combine(Directory.GetCurrentDirectory(),"wwwroot/img",ImageName);

                using(var stream=new FileStream(SavePath, FileMode.Create))
                {
                    image.CopyTo(stream);
                }
            }
            return View();
        }
Chromosphere answered 29/7, 2019 at 18:22 Comment(0)
A
9

Fileservice.cs:

public class FileService : IFileService
{
    private readonly IWebHostEnvironment env;

    public FileService(IWebHostEnvironment env)
    {
        this.env = env;
    }

    public string Upload(IFormFile file)
    {
        var uploadDirecotroy = "uploads/";
        var uploadPath = Path.Combine(env.WebRootPath, uploadDirecotroy);

        if (!Directory.Exists(uploadPath))
            Directory.CreateDirectory(uploadPath);

        var fileName = Guid.NewGuid() + Path.GetExtension(file.FileName);
        var filePath = Path.Combine(uploadPath, fileName);

        using (var strem = File.Create(filePath))
        {
            file.CopyTo(strem);
        }
        return fileName;
    }
}

IFileService:

namespace studentapps.Services
{
    public interface IFileService
    {
        string Upload(IFormFile file);
    }
}

StudentController:

[HttpGet]
public IActionResult Create()
{
    var student = new StudentCreateVM();
    student.Colleges = dbContext.Colleges.ToList();
    return View(student);
}

[HttpPost]
public IActionResult Create([FromForm] StudentCreateVM vm)
{
    Student student = new Student()
    {
        DisplayImage = vm.DisplayImage.FileName,
        Name = vm.Name,
        Roll_no = vm.Roll_no,
        CollegeId = vm.SelectedCollegeId,
    };


    if (ModelState.IsValid)
    {
        var fileName = fileService.Upload(vm.DisplayImage);
        student.DisplayImage = fileName;
        getpath = fileName;

        dbContext.Add(student);
        dbContext.SaveChanges();
        TempData["message"] = "Successfully Added";
    }
    return RedirectToAction("Index");
}
Accrescent answered 16/3, 2020 at 8:17 Comment(1)
Note: if you want to use IWebHostEnvironment in your Service or Bussiness Layer then you need to install Microsoft.AspNetCore.Http.Features. If you get an exception as the following : Error CS0246 The type or namespace name 'IWebHostEnvironment' could not be found (are you missing a using directive or an assembly reference?) , please include this on your project: <ItemGroup> <FrameworkReference Include="Microsoft.AspNetCore.App" /> </ItemGroup>. Source: github.com/dotnet/Scaffolding/issues/1186Lindeman
B
3

you can try below code

1- model or view model

public class UploadImage 
{
  public string ImageFile { get; set; }
  public string ImageName { get; set; }
  public string ImageDescription { get; set; }
}

2- View page

<form class="form-horizontal" asp-controller="Image" asp-action="UploadImage" method="POST" enctype="multipart/form-data">

<input type="file" asp-for="ImageFile">
<input type="text" asp-for="ImageName">
<input type="text" asp-for="ImageDescription">
</form>

3- Controller

 public class Image
    {

      private IHostingEnvironment _hostingEnv;
      public Image(IHostingEnvironment hostingEnv)
      {
         _hostingEnv = hostingEnv;
      }

      [HttpPost]
      public async Task<IActionResult> UploadImage(UploadImage model, IFormFile ImageFile)
      {
        if (ModelState.IsValid)
         {
        var filename = ContentDispositionHeaderValue.Parse(ImageFile.ContentDisposition).FileName.Trim('"');
        var path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images", ImageFile.FileName);
        using (System.IO.Stream stream = new FileStream(path, FileMode.Create))
         {
            await ImageFile.CopyToAsync(stream);
         }
          model.ImageFile = filename;
         _context.Add(model);
         _context.SaveChanges();
         }        

      return RedirectToAction("Index","Home");   
    }
Brahe answered 16/1, 2017 at 7:18 Comment(1)
@BerBar please added 'index' action. This code not return. only work redirects to another action.Brahe
C
1

Controller Code:-

 public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

    private IHostingEnvironment _environment;
    public HomeController(ILogger<HomeController> logger,IHostingEnvironment environment)
    {
        _logger = logger;
        _environment = environment;
    }

    public IActionResult Index()
    {
        return View();
    }
    [HttpPost]
    public IActionResult uploader()
    {
        var filelist = HttpContext.Request.Form.Files;
        if(filelist.Count>0)
        {
            foreach(var file in filelist)
            {

            var uploads = Path.Combine(_environment.WebRootPath, "files");
            string FileName = file.FileName;
            using (var fileStream = new FileStream(Path.Combine(uploads, FileName), FileMode.Create))
            {
                file.CopyToAsync(fileStream);
            }                    
            }
        }
        return View("Index");
    }
  
}

View Code:-

@using (Html.BeginForm("uploader", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{     
    <input type="file" multiple name="file" />
    <input type="submit" value="Upload" />
}

How to upload files in asp.net core

Cisalpine answered 8/11, 2021 at 14:43 Comment(0)
C
1
public static class FileManager
        {
            public static async Task<string> UploadImage(this IFormFile Image , string env,string folderName)
            {
                string path = env+folderName;
                if(!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
                string fileName=Image.FileName;
                fileName = Guid.NewGuid().ToString()+fileName;
                path = env+folderName+fileName;
                using(FileStream stream = new FileStream(path, FileMode.Create))
                {
                    await Image.CopyToAsync(stream);
                }
                return fileName;
            }
            public static bool CheckImage(this IFormFile Image,int size)
            {
                return Image.ContentType.Contains("image/") && Image.Length/1024/1024 < size;
            }
        }
    }
namespace Jof.Helpers
{
    public static class FileManager
    {
        public static async Task<string> UploadImage(this IFormFile Image , string env,string folderName)
        {
            string path = env+folderName;
            if(!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            string fileName=Image.FileName;
            fileName = Guid.NewGuid().ToString()+fileName;
            path = env+folderName+fileName;
            using(FileStream stream = new FileStream(path, FileMode.Create))
            {
                await Image.CopyToAsync(stream);
            }
            return fileName;
        }
        public static bool CheckImage(this IFormFile Image,int size)
        {
            return Image.ContentType.Contains("image/") && Image.Length/1024/1024 < size;
        }
}
Crumpet answered 21/1 at 1:50 Comment(2)
Thank you for your interest in contributing to the Stack Overflow community. This question already has quite a few answers—including one that has been extensively validated by the community. Are you certain your approach hasn’t been given previously? If so, it would be useful to explain how your approach is different, under what circumstances your approach might be preferred, and/or why you think the previous answers aren’t sufficient. Can you kindly edit your answer to offer an explanation?Satinet
Welcome to Stack Overflow! Thank you for your answer. Please provide more details about your solution. Code snippets, high quality descriptions, or any relevant information would be great. Clear and concise answers are more helpful and easier to understand for everyone. Edit your answer with specifics to raise the quality of your answer. For more information: How To: Write good answers. Happy coding!Kourtneykovac
D
0
        foreach (var formFile in files)
        {
            if (formFile.Length > 0)
            {
                var FilePath = _configuration.GetValue<string>("FilesPath:Cases");
                string FileName = Guid.NewGuid().ToString() + Path.GetExtension(formFile.FileName);
                string SavePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot" + FilePath, FileName);

                using (var stream = System.IO.File.Create(SavePath))
                {
                    formFile.CopyTo(stream);
                }
            }
        }
Drops answered 2/8, 2022 at 6:7 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Ducktail

© 2022 - 2024 — McMap. All rights reserved.