DEV Community

Jaydeep Patil
Jaydeep Patil

Posted on

Upload single and multiple files using the .NET Core 6 Web API

We are going to discuss single and multiple file uploads with the help of the IFormFile Interface and others which are provided by .NET and step-by-step implementation using .NET Core 6 Web API.

Agenda

Introduction
Step-by-step Implementation

Prerequisites

.NET Core 6 SDK
Visual Studio 2022
SQL Server
Postman

Introduction

  • .NET provides an IFormFile interface that represents transmitted files in an HTTP request.
  • Also, it provides many properties like ContentDisposition, ContentType, FileName, Headers, Name, and Length.
  • IFormFile also provides many methods like copying the request stream content, opening the request stream for reading, and many more.

Step-by-step Implementation

Step 1

Create a new .NET Core Web API

Image description

Step 2

Install following NuGet Packages

Image description

Step 3

Create the following file entities

FileDetails.cs

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace FileUpload.Entities
{
    [Table("FileDetails")]
    public class FileDetails
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int ID { get; set; }
        public string FileName { get; set; }
        public byte[] FileData { get; set; }
        public FileType FileType { get; set; }
    }
}
Enter fullscreen mode Exit fullscreen mode

FileUploadModel

namespace FileUpload.Entities
{
    public class FileUploadModel
    {
        public IFormFile FileDetails { get; set; }
        public FileType FileType { get; set; }
    }
}
Enter fullscreen mode Exit fullscreen mode

FileType

namespace FileUpload.Entities
{
    public enum FileType
    {
        PDF = 1,
        DOCX = 2
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 4

Next, DbContextClass.cs class inside the Data folder

using FileUpload.Entities;
using Microsoft.EntityFrameworkCore;
namespace FileUpload.Data
{
    public class DbContextClass : DbContext
    {
        protected readonly IConfiguration Configuration;
        public DbContextClass(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
        }
        public DbSet<FileDetails> FileDetails { get; set; }
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 5

Create IFileService and FileService files

IFileService

using FileUpload.Entities;
namespace FileUpload.Services
{
    public interface IFileService
    {
        public Task PostFileAsync(IFormFile fileData, FileType fileType);
        public Task PostMultiFileAsync(List<FileUploadModel> fileData);
        public Task DownloadFileById(int fileName);
    }
}
Enter fullscreen mode Exit fullscreen mode

FileService

using FileUpload.Data;
using FileUpload.Entities;
using Microsoft.EntityFrameworkCore;
namespace FileUpload.Services
{
    public class FileService : IFileService
    {
        private readonly DbContextClass dbContextClass;
        public FileService(DbContextClass dbContextClass)
        {
            this.dbContextClass = dbContextClass;
        }
        public async Task PostFileAsync(IFormFile fileData, FileType fileType)
        {
            try
            {
                var fileDetails = new FileDetails()
                {
                    ID = 0,
                    FileName = fileData.FileName,
                    FileType = fileType,
                };
                using (var stream = new MemoryStream())
                {
                    fileData.CopyTo(stream);
                    fileDetails.FileData = stream.ToArray();
                }
                var result = dbContextClass.FileDetails.Add(fileDetails);
                await dbContextClass.SaveChangesAsync();
            }
            catch (Exception)
            {
                throw;
            }
        }
        public async Task PostMultiFileAsync(List<FileUploadModel> fileData)
        {
            try
            {
                foreach(FileUploadModel file in fileData)
                {
                    var fileDetails = new FileDetails()
                    {
                        ID = 0,
                        FileName = file.FileDetails.FileName,
                        FileType = file.FileType,
                    };
                    using (var stream = new MemoryStream())
                    {
                        file.FileDetails.CopyTo(stream);
                        fileDetails.FileData = stream.ToArray();
                    }
                    var result = dbContextClass.FileDetails.Add(fileDetails);
                }
                await dbContextClass.SaveChangesAsync();
            }
            catch (Exception)
            {
                throw;
            }
        }
        public async Task DownloadFileById(int Id)
        {
            try
            {
                var file =  dbContextClass.FileDetails.Where(x => x.ID == Id).FirstOrDefaultAsync();
                var content = new System.IO.MemoryStream(file.Result.FileData);
                var path = Path.Combine(
                   Directory.GetCurrentDirectory(), "FileDownloaded",
                   file.Result.FileName);
                await CopyStream(content, path);
            }
            catch (Exception)
            {
                throw;
            }
        }
        public async Task CopyStream(Stream stream, string downloadPath)
        {
            using (var fileStream = new FileStream(downloadPath, FileMode.Create, FileAccess.Write))
            {
               await stream.CopyToAsync(fileStream);
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 6

Create FilesController.cs inside controller section

using FileUpload.Entities;
using FileUpload.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace FileUpload.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class FilesController : ControllerBase
    {
        private readonly IFileService _uploadService;
        public FilesController(IFileService uploadService)
        {
            _uploadService = uploadService;
        }
        /// <summary>
        /// Single File Upload
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        [HttpPost("PostSingleFile")]
        public async Task<ActionResult> PostSingleFile([FromForm] FileUploadModel fileDetails)
        {
            if(fileDetails == null)
            {
                return BadRequest();
            }
            try
            {
                await _uploadService.PostFileAsync(fileDetails.FileDetails, fileDetails.FileType);
                return Ok();
            }
            catch (Exception)
            {
                throw;
            }
        }
        /// <summary>
        /// Multiple File Upload
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        [HttpPost("PostMultipleFile")]
        public async Task<ActionResult> PostMultipleFile([FromForm] List<FileUploadModel> fileDetails)
        {
            if (fileDetails == null)
            {
                return BadRequest();
            }
            try
            {
                await _uploadService.PostMultiFileAsync(fileDetails);
                return Ok();
            }
            catch (Exception)
            {
                throw;
            }
        }
        /// <summary>
        /// Download File
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        [HttpGet("DownloadFile")]
        public async Task<ActionResult> DownloadFile(int id)
        {
            if (id < 1)
            {
                return BadRequest();
            }
            try
            {
                await _uploadService.DownloadFileById(id);
                return Ok();
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 7

Configure a few services in Program Class and inside the DI Container

using FileUpload.Data;
using FileUpload.Services;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<DbContextClass>();
builder.Services.AddScoped<IFileService, FileService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
app.Run();
Enter fullscreen mode Exit fullscreen mode

Step 8

Create a new Database inside SQL Server and named it as FileUploadDemo

Step 9

Next, create the FileDetails table using the following script

USE [FileUploadDemo]
GO
/****** Object:  Table [dbo].[FileDetails]    Script Date: 10/1/2022 5:51:22 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[FileDetails](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [FileName] [nvarchar](80) NOT NULL,
    [FileData] [varbinary](max) NOT NULL,
    [FileType] [int] NULL,
 CONSTRAINT [PK_FileDetails] PRIMARY KEY CLUSTERED
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
Enter fullscreen mode Exit fullscreen mode

Step 10

Put database connection inside the appsettings.json file

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=DESKTOP-****;;Initial Catalog=FileUploadDemo;User Id=sa;Password=database;"
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 11

Finally, we run the application

Image description

Step 12

Now, we are going to upload a single file using swagger by providing the file and type of file based on enum id

Image description

Step 13

Also, for uploading multiple files we use Postman. Here you can see we use array index to send the file and their type and it will be working fine.

Image description
Step 14

Later on, based on file id we are able to download files on the local system at a specified path location

Image description
Step 15

Here you can see the downloaded file at the specified location

Image description
Also, in the database, we can see whatever files we already uploaded using the above endpoints

Image description

GITHUB URL:

https://github.com/Jaydeep-007/FileUpload/tree/master/FileUpload

Conclusion

In this article, we discussed the single and multiple file upload using IFormFile and step-by-step implementation of that using .NET Core Web API and also read and save the files from the database to the specified location.

Happy Learning!

Top comments (3)

Collapse
 
jaspercreed profile image
Alex

Thanks for the article! Came up with one question - why do we need to catch the exceptions if we just throw the same exception instance further?

Collapse
 
jaydeep007 profile image
Jaydeep Patil

Thanks! Yes correct, that's not necessary. We use as per our requirement.

Collapse
 
shaiful191 profile image
Shaiful Islam

Thanks for the article!