CRUD Operations And Upload /Download Files In ASP.NET Core 2.0

Description

This blog post describes how to implement CRUD operations i.e Create (Insert data into Database), Read (Get data form Database), Update (Update data in Database), Delete (Delete data in Database) and how to upload and download file using Entity Framework Core and ASP.NET Core. It also describes how to create directory, how to map path to directory and where file (in wwwroot folder) saves. 
 
Introduction

We are going to implement a small and simple asp.net core 2.0 web application, we add a user and edit by uploading his image file. We add his image in wwwroot folder in sub folder “UserFiles”. We check if this folder is already created if not then we create it first and after that we will add another folder named as this user id is, and add its subfolder named “images” where we will upload our image files. We will first check if all the above folders already exist if not
we will create them first and then upload file. If a user deletes it, then its folder, sub folders and files will also be deleted.
 
Body

For this we follow these steps in visual studio 2017,
  1. File --> New --> Project 
  2. Select ASP.Net Core Web Application
  3. Set name and location
  4. In next screen select Web Application (Model – View – Controller) Template and select No Authentication and Click OK.
  5. Now add some necessary NuGet packages,
    1. Tools --> NuGet Package Manager --> Package Manager Console
    2. Run Install-Package Microsoft.EntityFrameworkCore.SqlServer
    3. For Entity Framework Core Tools to create a database from your EF Core model
    4. Run Install-Package Microsoft.EntityFrameworkCore.Tools
    5. And for ASP.NET Core Scaffolding tools to create controllers and views.
    6. Run Install-Package Microsoft.VisualStudio.Web.CodeGeneration.Design
Add class “User.cs” as shown below:
  1. public class User  
  2.    {  
  3.        public int UserId { get; set; }  
  4.        public string Name { get; set; }  
  5.        public string Email { get; set; }  
  6.        public string Company { get; set; }  
  7.        public string Introduction { get; set; }  
  8.   
  9.    }   
Add class “DataAccess.cs” as shown below,
  1. public class DataAccess : DbContext  
  2.     {  
  3.         public DataAccess(DbContextOptions<DataAccess> options)  
  4.             : base(options)  
  5.         { }  
  6.   
  7.         public DbSet<User> User { get; set; }  
  8.     } 

In order for our MVC controllers to make use of DataAccess we will register it as a service.

Add fallowing code to Startup.cs file

  1. public void ConfigureServices(IServiceCollection services)  
  2.       {  
  3.           services.AddMvc();  
  4.   
  5.           // Custom code for Data Access  
  6.           var connection = @"Data Source=ATIQ;Initial Catalog=UserDB;Integrated Security=False;  Persist Security Info=False;User ID=sa;Password=*****";  
  7.           services.AddDbContext<DataAccess>(options => options.UseSqlServer(connection));  
  8.       } 
 Add two using statements in Startup.cs file
  1. using UserDemo.Models;    
  2. using Microsoft.EntityFrameworkCore; 
 In Tools --> NuGet Package Manager --> Package Manager Console, run two commands;

Add-Migration InitialCreate

Update-Database

This will create our Database using Entity Framework Core.

Right click on Controllers, Add Controller and Select “MVC Controller with Views using Entity Framework” and name the controller.

This will add controller with its all CRUD views in views folder as controller name in our case "Users".

We will make little changes into these views as in attached source files. Add some code into Views/Users/Edit.cshtml
  1. <form asp-action="UploadImage" method="post" enctype="multipart/form-data">  
  2.            <div class="form-group">  
  3.                <input type="hidden" asp-for="UserId" />  
  4.                <label class="control-label">User Image</label><br />  
  5.                <img src="@ViewBag.ImgPath" alt="@Model.Name" height="100" width="100" /><br />  
  6.                @if (!string.IsNullOrEmpty(ViewBag.FileName))  
  7.                {  
  8.                    <a href="~/Users/Download?img=@ViewBag.FileName&userId=@Model.UserId">Download</a><br />  
  9.                }  
  10.                <input type="file" name="user_image" id="user_image" />  
  11.   
  12.            </div>  
  13.            <div class="form-group">  
  14.                <input type="submit" value="Upload" class="btn btn-default" />  
  15.            </div>  
  16.        </form> 
 And in UsersController.cs file add custom code;

  1. public async Task<IActionResult> Edit(int? id)  
  2.        {  
  3.            if (id == null)  
  4.            {  
  5.                return NotFound();  
  6.            }  
  7.   
  8.            var user = await _context.User.SingleOrDefaultAsync(m => m.UserId == id);  
  9.            if (user == null)  
  10.            {  
  11.                return NotFound();  
  12.            }  
  13.   
  14.            string webRoot = _env.WebRootPath;  
  15.            string img_p = "";  
  16.            string fileName = "";  
  17.            if (System.IO.Directory.Exists(webRoot + "/UserFiles/" + user.UserId.ToString() + "/Image/"))  
  18.            {  
  19.                string[] strfiles = Directory.GetFiles(webRoot + "/UserFiles/" + user.UserId.ToString() + "/Image/""*.*");  
  20.   
  21.                if (strfiles.Length > 0)  
  22.                {  
  23.   
  24.                    for (int i = 0; i < strfiles.Length; i++)  
  25.                    {  
  26.                        fileName = Path.GetFileName(strfiles[i]);  
  27.   
  28.                        string _CurrentFile = strfiles[i].ToString();  
  29.                        if (System.IO.File.Exists(_CurrentFile))  
  30.                        {  
  31.                            string tempFileURL = "/UserFiles/" + user.UserId.ToString() + "/Image/" + Path.GetFileName(_CurrentFile);  
  32.                            img_p = tempFileURL;  
  33.                        }  
  34.   
  35.                    }  
  36.   
  37.                }  
  38.            }  
  39.   
  40.            if (!string.IsNullOrEmpty(img_p))  
  41.            {  
  42.                ViewBag.ImgPath = Convert.ToString(img_p);  
  43.                ViewBag.FileName = Convert.ToString(fileName);  
  44.            }  
  45.            else  
  46.                ViewBag.ImgPath = "/Images/default.jpg";  
  47.   
  48.            return View(user);  
  49.        } 

  1. [HttpPost]  
  2.         [ValidateAntiForgeryToken]  
  3.         public async Task<IActionResult> Edit(int id, [Bind("UserId,Name,Email,Password,Introduction")] User user)  
  4.         {  
  5.             if (id != user.UserId)  
  6.             {  
  7.                 return NotFound();  
  8.             }  
  9.   
  10.             if (ModelState.IsValid)  
  11.             {  
  12.                 try  
  13.                 {  
  14.                     _context.Update(user);  
  15.                     await _context.SaveChangesAsync();  
  16.                 }  
  17.                 catch (DbUpdateConcurrencyException)  
  18.                 {  
  19.                     if (!UserExists(user.UserId))  
  20.                     {  
  21.                         return NotFound();  
  22.                     }  
  23.                     else  
  24.                     {  
  25.                         throw;  
  26.                     }  
  27.                 }  
  28.                 return RedirectToAction(nameof(Index));  
  29.             }  
  30.             return View(user);  
  31.         } 
 Add code for Uploaded file;
  1. [HttpPost]  
  2.        public async Task<IActionResult> UploadImage(IFormCollection form)  
  3.        {  
  4.            if (form.Files == null || form.Files[0].Length == 0)  
  5.                return RedirectToAction("Edit"new { id = Convert.ToString(form["UserId"]) });  
  6.   
  7.            var webRoot = _env.WebRootPath;  
  8.            string userId = Convert.ToString(form["UserId"]);  
  9.   
  10.            if (!System.IO.Directory.Exists(webRoot + "/UserFiles/"))  
  11.            {  
  12.                System.IO.Directory.CreateDirectory(webRoot + "/UserFiles/");  
  13.            }  
  14.            if (!System.IO.Directory.Exists(webRoot + "/UserFiles/" + userId + "/Image/"))  
  15.            {  
  16.                System.IO.Directory.CreateDirectory(webRoot + "/UserFiles/" + userId + "/Image/");  
  17.            }  
  18.   
  19.            //Delete existing files first and then add new file  
  20.            DeleteFiles(userId);  
  21.   
  22.            var path = Path.Combine(  
  23.                        Directory.GetCurrentDirectory(), "wwwroot" + "/UserFiles/" + userId + "/Image/",  
  24.                        form.Files[0].FileName);  
  25.   
  26.            using (var stream = new FileStream(path, FileMode.Create))  
  27.            {  
  28.                await form.Files[0].CopyToAsync(stream);  
  29.            }  
  30.   
  31.            return RedirectToAction("Edit"new { id = Convert.ToString(form["UserId"]) });  
  32.        } 
And also for Downloading code;
  1. public async Task<IActionResult> Download(string img, string userId)  
  2.         {  
  3.             string filename = img;  
  4.             if (filename == null)  
  5.                 return Content("filename not present");  
  6.   
  7.             var path = Path.Combine(  
  8.                            Directory.GetCurrentDirectory(),  
  9.                            "wwwroot" + "/UserFiles/" + userId + "/Image/", filename);  
  10.   
  11.             var memory = new MemoryStream();  
  12.             using (var stream = new FileStream(path, FileMode.Open))  
  13.             {  
  14.                 await stream.CopyToAsync(memory);  
  15.             }  
  16.             memory.Position = 0;  
  17.             return File(memory, GetContentType(path), Path.GetFileName(path));  
  18.         }  
  19.   
  20.         private string GetContentType(string path)  
  21.         {  
  22.             var types = GetMimeTypes();  
  23.             var ext = Path.GetExtension(path).ToLowerInvariant();  
  24.             return types[ext];  
  25.         }  
  26.   
  27.         private Dictionary<string, string> GetMimeTypes()  
  28.         {  
  29.             return new Dictionary<string, string>  
  30.             {  
  31.                 {".png""image/png"},  
  32.                 {".jpg""image/jpeg"},  
  33.                 {".jpeg""image/jpeg"},  
  34.                 {".gif""image/gif"}  
  35.             };  
  36.         } 
Here lets discuss new things with image map paths and root directories.

All static files (.css, .js and images) are stored in wwwroot folder by default.

We use "Request.Files" befour Asp.Net Core, now we are using "Request.Form.Files" for getting files from form in Controller. "Server.MapPath("~/UserImages/")" aslo be changed to "var webRoot = _env.WebRootPath;" where
we add _env as;
  1. private readonly DataAccess _context;  
  2.        private readonly IHostingEnvironment _env;  
  3.          
  4.        public UsersController(DataAccess context, IHostingEnvironment env)  
  5.        {  
  6.            _context = context;  
  7.            _env = env;  
  8.        } 
Another change you will notic is "HttpFileCollectionBase" keyword is not using in CORE, instead we are using "IFormFileCollection" for file collection receiving parameter.

"HttpPostedFileBase" keyword also be changed as "IFormFile" used for single file object.
 
When user deletes all folders and sub folders, image file is also deleted as in code below;
  1. [HttpPost, ActionName("Delete")]  
  2.        [ValidateAntiForgeryToken]  
  3.        public async Task<IActionResult> DeleteConfirmed(int id)  
  4.        {  
  5.            var user = await _context.User.SingleOrDefaultAsync(m => m.UserId == id);  
  6.            _context.User.Remove(user);  
  7.            await _context.SaveChangesAsync();  
  8.   
  9.            //Delete User Files as well  
  10.            var dirPath = Path.Combine(  
  11.                           Directory.GetCurrentDirectory(),  
  12.                           "wwwroot" + "/UserFiles/" + Convert.ToString(id) + "/");  
  13.            Directory.Delete(dirPath,true);  
  14.            return RedirectToAction(nameof(Index));  
  15.        } 
That's it, may be not the full explanation but you can understand the code with little effort.
 
Last Words

This is not the professional application but just learning and introductory application of Asp.Net Core 2.0. All necessary code related files are attached with this blog post, just copy and paste into your project at root. Please change connection string as for your sql server in Startup.cs file. Also modify namespaces as your project name.