ASP.NET Core supports uploading one or more files using buffered model binding for smaller files and unbuffered streaming for larger files.
File Model
Create a new class, Models/FileModel.cs
. This will be the base class.
1 2 3 4 5 6 7 8 9 10
| public abstract class FileModel { public int Id { get; set; } public string Name { get; set; } public string FileType { get; set; } public string Extension { get; set; } public string Description { get; set; } public string UploadedBy { get; set; } public DateTime? CreatedOn { get; set; } }
|
Now, let’s create a model for the file on the file system. Name it Models/FileOnFileSystem.cs
and inherit the FileModel
class.
1 2 3 4
| public class FileOnFileSystemModel : FileModel { public string FilePath { get; set; } }
|
Similarly add another class for the file on database, Models/FileOnDatabaseModel.cs
1 2 3 4
| public class FileOnDatabaseModel : FileModel { public byte[] Data { get; set; } }
|
Setting up Entity Framework Core
Install the below packages
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Install-Package Microsoft.EntityFrameworkCore -Version 3.1.9 dotnet add package Microsoft.EntityFrameworkCore --version 3.1.9 <PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.9" />
Install-Package Microsoft.EntityFrameworkCore.Design -Version 3.1.9 dotnet add package Microsoft.EntityFrameworkCore.Design --version 3.1.9 <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.9"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
Install-Package Microsoft.EntityFrameworkCore.Tools -Version 3.1.9 dotnet add package Microsoft.EntityFrameworkCore.Tools --version 3.1.9 <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.9"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 3.1.9 dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 3.1.9 <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.9" />
|
Next, add a connection string to your appsetting.json
file.
1 2 3
| "ConnectionStrings": { "DefaultConnection": "Server=.;Database=FileDb;Trusted_Connection=True;" }
|
Create ApplicationDbContext
1 2 3 4 5 6 7 8 9 10
| using Microsoft.EntityFrameworkCore;
public class ApplicationDbContext : DbContext { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } public DbSet<FileOnDatabaseModel> FilesOnDatabase { get; set; } public DbSet<FileOnFileSystemModel> FilesOnFileSystem { get; set; } }
|
Let’s now configure the services. Modify the Startup.cs/ConfigureServices
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| using Microsoft.EntityFrameworkCore;
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer( Configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)) ); } }
|
Finally, let’s do the required migrations and update our database. Just run the following commands on the Package Manager Console
or other terminals.
1 2 3 4 5 6 7
| Add-Migration initial Update-Database
// dotnet tool install --global dotnet-ef // dotnet tool update --global dotnet-ef dotnet ef migrations add initial dotnet ef database update
|
You will get a done message on console. Open up SQL Server Object Explorer to check if the database and tables have been created.
Setting up the View and ViewModel
Make a new class, a ViewModel class, Models/FileUploadViewModel.cs
as below.
1 2 3 4 5
| public class FileUploadViewModel { public List<FileOnFileSystemModel> FilesOnFileSystem { get; set; } public List<FileOnDatabaseModel> FilesOnDatabase { get; set; } }
|
After that, Let’s start modifying the View Page, Views/File/Index.cshtml
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| @model FileUploadViewModel @{ ViewData["Title"] = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; }
<h4>Start Uploading Files Here</h4> <hr /> @if (ViewBag.Message != null) { <div class="alert alert-success alert-dismissible" style="margin-top:20px"> @ViewBag.Message </div> } <form method="post" enctype="multipart/form-data"> <input type="file" name="files" multiple required /> <input type="text" autocomplete="off" placeholder="Enter File Description" name="description" required /> <button type="submit" class="btn btn-primary" asp-controller="File" asp-action="UploadToFileSystem">Upload to File System</button> <button class="btn btn-success" type="submit" asp-controller="File" asp-action="UploadToDatabase">Upload to Database</button> </form> <hr /> <h4>Files on File System</h4> @if (Model.FilesOnFileSystem.Count == 0) { <caption>No Records Found</caption> } else { <caption>List of Files on File System</caption> <table class="table table-striped"> <thead> <tr> <th>#</th> <th>Name</th> <th>Description</th> <th>File Type</th> <th>Created On</th> <th>Actions</th> </tr> </thead> <tbody> @foreach (var file in Model.FilesOnFileSystem) { <tr> <th>@file.Id</th> <td>@file.Name</td> <td>@file.Description</td> <td>@file.FileType</td> <td>@file.CreatedOn</td> <td> <a type="button" class="btn btn-primary" asp-controller="File" asp-action="DownloadFileFromFileSystem" asp-route-id="@file.Id">Download</a> <a type="button" class="btn btn-danger" asp-controller="File" asp-action="DeleteFileFromFileSystem" asp-route-id="@file.Id">Delete</a> </td> </tr> } </tbody> </table> } <hr /> <h4>Files on Database</h4> @if (Model.FilesOnDatabase.Count == 0) { <caption>No Records Found</caption> } else { <caption>List of Files on Database</caption> <table class="table table-striped"> <thead> <tr> <th>#</th> <th>Name</th> <th>Description</th> <th>File Type</th> <th>Created On</th> <th>Actions</th> </tr> </thead> <tbody> @foreach (var file in Model.FilesOnDatabase) { <tr> <th>@file.Id</th> <td>@file.Name</td> <td>@file.Description</td> <td>@file.FileType</td> <td>@file.CreatedOn</td> <td> <a type="button" class="btn btn-primary" asp-controller="File" asp-action="DownloadFileFromDatabase" asp-route-id="@file.Id">Download</a> <a type="button" class="btn btn-danger" asp-controller="File" asp-action="DeleteFileFromDatabase" asp-route-id="@file.Id">Delete</a> </td> </tr> } </tbody> </table> }
|
Now, Create FileController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
public class FileController : Controller { private readonly ApplicationDbContext context; public FileController(ApplicationDbContext context) { this.context = context; } public async Task<IActionResult> Index() { var fileuploadViewModel = await LoadAllFiles(); ViewBag.Message = TempData["Message"]; return View(fileuploadViewModel); } [HttpPost] public async Task<IActionResult> UploadToFileSystem(List<IFormFile> files, string description) { foreach (var file in files) { var basePath = Path.Combine(Directory.GetCurrentDirectory() + "\\Files\\"); bool basePathExists = System.IO.Directory.Exists(basePath); if (!basePathExists) Directory.CreateDirectory(basePath); var fileName = Path.GetFileNameWithoutExtension(file.FileName); var filePath = Path.Combine(basePath, file.FileName); var extension = Path.GetExtension(file.FileName); if (!System.IO.File.Exists(filePath)) { using (var stream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(stream); } var fileModel = new FileOnFileSystemModel { CreatedOn = DateTime.UtcNow, FileType = file.ContentType, Extension = extension, Name = fileName, Description = description, FilePath = filePath }; await context.FilesOnFileSystem.AddAsync(fileModel); await context.SaveChangesAsync(); } } TempData["Message"] = "File successfully uploaded to File System."; return RedirectToAction("Index"); } [HttpPost] public async Task<IActionResult> UploadToDatabase(List<IFormFile> files, string description) { foreach (var file in files) { var fileName = Path.GetFileNameWithoutExtension(file.FileName); var extension = Path.GetExtension(file.FileName); var fileModel = new FileOnDatabaseModel { CreatedOn = DateTime.UtcNow, FileType = file.ContentType, Extension = extension, Name = fileName, Description = description }; using (var dataStream = new MemoryStream()) { await file.CopyToAsync(dataStream); fileModel.Data = dataStream.ToArray(); } await context.FilesOnDatabase.AddAsync(fileModel); await context.SaveChangesAsync(); } TempData["Message"] = "File successfully uploaded to Database"; return RedirectToAction("Index"); } private async Task<FileUploadViewModel> LoadAllFiles() { var viewModel = new FileUploadViewModel(); viewModel.FilesOnDatabase = await context.FilesOnDatabase.ToListAsync(); viewModel.FilesOnFileSystem = await context.FilesOnFileSystem.ToListAsync(); return viewModel; } public async Task<IActionResult> DownloadFileFromDatabase(int id) { var file = await context.FilesOnDatabase.Where(x => x.Id == id).FirstOrDefaultAsync(); if (file == null) return null; return File(file.Data, file.FileType, file.Name + file.Extension); } public async Task<IActionResult> DownloadFileFromFileSystem(int id) { var file = await context.FilesOnFileSystem.Where(x => x.Id == id).FirstOrDefaultAsync(); if (file == null) return null; var memory = new MemoryStream(); using (var stream = new FileStream(file.FilePath, FileMode.Open)) { await stream.CopyToAsync(memory); } memory.Position = 0; return File(memory, file.FileType, file.Name + file.Extension); } public async Task<IActionResult> DeleteFileFromFileSystem(int id) { var file = await context.FilesOnFileSystem.Where(x => x.Id == id).FirstOrDefaultAsync(); if (file == null) return null; if (System.IO.File.Exists(file.FilePath)) { System.IO.File.Delete(file.FilePath); } context.FilesOnFileSystem.Remove(file); await context.SaveChangesAsync(); TempData["Message"] = $"Removed {file.Name + file.Extension} successfully from File System."; return RedirectToAction("Index"); } public async Task<IActionResult> DeleteFileFromDatabase(int id) { var file = await context.FilesOnDatabase.Where(x => x.Id == id).FirstOrDefaultAsync(); context.FilesOnDatabase.Remove(file); await context.SaveChangesAsync(); TempData["Message"] = $"Removed {file.Name + file.Extension} successfully from Database."; return RedirectToAction("Index"); } }
|
Reference(s)
Most of the information in this article has gathered from various references.