File Upload and Download Asp.Net Core Web API

Viewed 13492

I have to create a web API for file management which are file upload, download, delete in ASP.NET Core. The requirement is this that the file will be saved to the disk and the path, filename, UniqueId will be saved in the database. The Entity Model that I have created is this:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace FileManagerAPI.Model
{
public class FileDetail
{
    public Guid Id { get; set; }
    public DateTime? DateEntered { get; set; }
    public bool? Deleted { get; set; }
    public string DocumentName { get; set; }
    public string DocId { get; set; }
    public string DocType { get; set; }
    public string DocUrl { get; set; }
}

}

Only selected types of files(pdf, png, jpg, jpeg) can be uploaded. I have read a lot of documents but I couldn't make it work. Also, I have to save the files outside the project root directory. How can I implement this? Also I am using ASP.Net Core 3.1!

3 Answers

Here is what I have done to upload a file in my Controller.

namespace FileManagerAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class FilesController : ControllerBase
{
    private readonly FileDbContext _context;
    private readonly IHostingEnvironment _env;
    public FilesController(FileDbContext context, IHostingEnvironment env)
    {
        _context = context;
        _env = env;
    }

    [HttpPost]
    public IActionResult Upload(IList<IFormFile>files)
    {
        //either you can pass the list of files in the method or you can initialize them inside the method like the commented line below
        //var files = HttpContext.Request.Form.Files;
        FileDetail fileDetail = new FileDetail();
        foreach (var file in files)
        {
            var fileType = Path.GetExtension(file.FileName);
            //var ext = file.;
            if (fileType.ToLower() == ".pdf" || fileType.ToLower() == ".jpg" || fileType.ToLower() == ".png" || fileType.ToLower() == ".jpeg")
            {
                var filePath = _env.ContentRootPath;
                var docName = Path.GetFileName(file.FileName);
                if (file != null && file.Length > 0)
                {
                    fileDetail.Id = Guid.NewGuid();
                    fileDetail.DocumentName = docName;
                    fileDetail.DocType = fileType;
                    fileDetail.DocUrl = Path.Combine(filePath, "Files", fileDetail.Id.ToString() + fileDetail.DocType);
                    using (var stream = new FileStream(fileDetail.DocUrl, FileMode.Create))
                    {
                        file.CopyToAsync(stream);
                    }

                    _context.Add(fileDetail);
                    _context.SaveChangesAsync();
                }
                else
                {
                    return BadRequest();
                }
            }
        }
        return Ok();
    }


    [HttpGet]
    public IActionResult Download(Guid id)
    {
        var fileDetail = _context.FileDetail
            .Where(x => x.Id == id)
            .FirstOrDefault();
        if(fileDetail != null)
        {
            System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
            {
                FileName = fileDetail.DocumentName,
                Inline = false
            };
            Response.Headers.Add("Content-Disposition", cd.ToString());

            //get physical path
            var path = _env.ContentRootPath;
            var fileReadPath = Path.Combine(path, "Files", fileDetail.Id.ToString() + fileDetail.DocType);

            var file = System.IO.File.OpenRead(fileReadPath);
            return File(file, fileDetail.DocType);
        }
        else
        {
            return StatusCode(404);
        }
    }
}

For upload file - you should use interface IFormFile in your command and save Stream from that interface to eg. array of bytes. (Remeber - sending file should be send by HTTP Form Method). Before save you should check what is mime type and wheresome write information about file eg. in database.

For download file - you can use Method File in Controller. First arg of that method is Stream/Array of bytes/Physic path to file, second is mime/type.

To saving file outside Project Root can be sometimes probaly. Lot of external servers not shar that posibility. In my opinion should you save file in eg. Azure Blobs or simply in wwwroot in application.

If you are passing the file back to your controller using HttpPostedFileBase, you can adapt the following code to suit your needs.

string path = Path.Combine(Server.MapPath("~/Path/To/Desired/Folder"), file.FileName);
file.SaveAs(path);

file is a parameter of type HttpPostedFileBase, and is passed back to the controller via a HttpPost Method.

Just make sure that your program has the correct permissions to access the folder you desire.

Related