عملیات CRUD، آپلود و دانلود فایل در ASP.NET Core 2.0

در این مقاله نحوه پیاده‌سازی عملیات CRUD یعنی Create (افزودن داده‌ها در پایگاه داده)، Read (دریافت داده از پایگاه داده)، Update (آپدیت داده در پایگاه داده)، Delete (حذف داده از پایگاه داده) و نحوه آپلود و دانلود فایل با استفاده از Entity Framework Core و ASP.NET Core را شرح می‌دهیم. همچنین روش ایجاد پوشه، نحوه ارتباط مسیر به پوشه و جایی که فایل‌ها ذخیره می‌شوند (در فولدر wwwroot) را بیان می‌کنیم.

عملیات CRUD، آپلود و دانلود فایل در ASP.NET Core 2.0

معرفی

ما قصد داریم یک برنامه کوچک و ساده net core 2.0. را اجرا کنیم. ما یک کاربر را اضافه می‌کنیم و با آپلود فایل تصویری آن را ویرایش می‌کنیم. تصویر را در فولدر wwwroot در زیر فولدر “UserFiles” اضافه می‌کنیم. بررسی می‌کنیم آیا این فولدر از قبل ایجاد شده است یا نه، سپس ابتدا آن را ایجاد کرده و پس از آن یک فولدر دیگر به نام id این کاربر اضافه خواهیم کرد، و فولدر داخلی آن را به نام “images” اضافه می‌کنیم، جایی که فایل‌های تصویری ما آپلود می‌شوند. ابتدا بررسی می‌کنیم ببینیم آیا تمام فولدرهای بالا در حال حاضر وجود دارند یا نه.

ما آن‌ها را ابتدا ایجاد کرده و سپس فایل را آپلود می‌کنیم. اگر یک کاربر آن را حذف کند، فولدر اصلی، زیرفولدرها و همچنین فایل‌ها حذف خواهند شد.

برای دنبال کردن این مراحل در ویژوال استودیو 2017 این مراحل را انجام می‌دهیم:

File --> New --> Project (1

2) انتخاب ASP.Net Core Web Application

3) تنظیم نام و موقعیت

4) انتخاب قالب Web Application (Model – View – Controller) در صفحه بعدی و انتخاب No Authentication و کلیک روی OK

5) حالا باید چند پکیج مورد نیاز NuGet را اضافه کنیم:

Tools --> NuGet Package Manager --> Package Manager Console.1

2. اجرای Install-Package Microsoft.EntityFrameworkCore.SqlServer

3. برای ابزارهای Entity Framework Core تا پاپگاه داده‌ای را از مدل EF Core خود ایجاد کنید

4. اجرای Install-Package Microsoft.EntityFrameworkCore.Tools
5. و برای ابزارهای اسکفلدینگ ASP.NET Core برای ایجاد کنترلرها و ویوها

6. اجرای Install-Package Microsoft.VisualStudio.Web.CodeGeneration.Design

کلاس “User.cs” را به صورت دستورات زیر اضافه کنید:



    public class User  
       {  
           public int UserId { get; set; }  
           public string Name { get; set; }  
           public string Email { get; set; }  
           public string Company { get; set; }  
           public string Introduction { get; set; }  
      
       }   

کلاس “DataAccess.cs” را همانند دستورات زیر اضافه کنید:

public class DataAccess : DbContext  
    {  
        public DataAccess(DbContextOptions<DataAccess> options)  
            : base(options)  
        { }  
  
        public DbSet<User> User { get; set; }  
    }  

برای اینکه کنترلرهای MVC ما از DataAccess استفاده کنند، ما آن را به عنوان سرویس ثبت می‌کنیم.

کد زیر را به فایل Startup.cs اضافه کنید:

public void ConfigureServices(IServiceCollection services)  
      {  
          services.AddMvc();  
  
          // Custom code for Data Access  
          var connection = @"Data Source=ATIQ;Initial Catalog=UserDB;Integrated Security=False;  Persist Security Info=False;User ID=sa;Password=*****";  
          services.AddDbContext<DataAccess>(options => options.UseSqlServer(connection));  
      }  

دو using را به فایل Startup.cs اضافه کنید:

using UserDemo.Models;    
using Microsoft.EntityFrameworkCore;  

در Tools --> NuGet Package Manager --> Package Manager Console، دو دستور را اضافه کنید:

Add-Migration InitialCreate

Update-Database

این دستور پایگاه داده‌ای را با استفاده از Entity Framework Core ایجاد می‌کند.

روی Controllers راست کلیک کرده، Add Controller را زده و “MVC Controller with Views using Entity Framework” را انتخاب کرده و نامی برای کنترلر بگذارید.

این عمل کنترلری را با تمام ویوهای CRUD در فولدر views برای آن کنترلر، که ما آن را "Users" نامیدیم، ایجاد می‌کند.

ما تغییرات کوچکی را درون این ویوها به عنوان فایل‌های منبع مربوطه ایجاد خواهیم کرد. کدهایی را درون Views/Users/Edit.cshtml اضافه کنید.

<form asp-action="UploadImage" method="post" enctype="multipart/form-data">  
           <div class="form-group">  
               <input type="hidden" asp-for="UserId" />  
               <label class="control-label">User Image</label><br />  
               <img src="@ViewBag.ImgPath" alt="@Model.Name" height="100" width="100" /><br />  
               @if (!string.IsNullOrEmpty(ViewBag.FileName))  
               {  
                   <a href="~/Users/Download?img=@ViewBag.FileName&userId=@Model.UserId">Download</a><br />  
               }  
               <input type="file" name="user_image" id="user_image" />  
  
           </div>  
           <div class="form-group">  
               <input type="submit" value="Upload" class="btn btn-default" />  
           </div>  
       </form> 

و در فایل UsersController.cs کدهای سفارشی زیر را اضافه کنید:

public async Task<IActionResult> Edit(int? id)  
       {  
           if (id == null)  
           {  
               return NotFound();  
           }  
  
           var user = await _context.User.SingleOrDefaultAsync(m => m.UserId == id);  
           if (user == null)  
           {  
               return NotFound();  
           }  
  
           string webRoot = _env.WebRootPath;  
           string img_p = "";  
           string fileName = "";  
           if (System.IO.Directory.Exists(webRoot + "/UserFiles/" + user.UserId.ToString() + "/Image/"))  
           {  
               string[] strfiles = Directory.GetFiles(webRoot + "/UserFiles/" + user.UserId.ToString() + "/Image/", "*.*");  
  
               if (strfiles.Length > 0)  
               {  
  
                   for (int i = 0; i < strfiles.Length; i++)  
                   {  
                       fileName = Path.GetFileName(strfiles[i]);  
  
                       string _CurrentFile = strfiles[i].ToString();  
                       if (System.IO.File.Exists(_CurrentFile))  
                       {  
                           string tempFileURL = "/UserFiles/" + user.UserId.ToString() + "/Image/" + Path.GetFileName(_CurrentFile);  
                           img_p = tempFileURL;  
                       }  
  
                   }  
  
               }  
           }  
  
           if (!string.IsNullOrEmpty(img_p))  
           {  
               ViewBag.ImgPath = Convert.ToString(img_p);  
               ViewBag.FileName = Convert.ToString(fileName);  
           }  
           else  
               ViewBag.ImgPath = "/Images/default.jpg";  
  
           return View(user);  
       }  
[HttpPost]  
        [ValidateAntiForgeryToken]  
        public async Task<IActionResult> Edit(int id, [Bind("UserId,Name,Email,Password,Introduction")] User user)  
        {  
            if (id != user.UserId)  
            {  
                return NotFound();  
            }  
  
            if (ModelState.IsValid)  
            {  
                try  
                {  
                    _context.Update(user);  
                    await _context.SaveChangesAsync();  
                }  
                catch (DbUpdateConcurrencyException)  
                {  
                    if (!UserExists(user.UserId))  
                    {  
                        return NotFound();  
                    }  
                    else  
                    {  
                        throw;  
                    }  
                }  
                return RedirectToAction(nameof(Index));  
            }  
            return View(user);  
        }  

و کدی را برای آپلود فایل اضافه کنید:

[HttpPost]  
       public async Task<IActionResult> UploadImage(IFormCollection form)  
       {  
           if (form.Files == null || form.Files[0].Length == 0)  
               return RedirectToAction("Edit", new { id = Convert.ToString(form["UserId"]) });  
  
           var webRoot = _env.WebRootPath;  
           string userId = Convert.ToString(form["UserId"]);  
  
           if (!System.IO.Directory.Exists(webRoot + "/UserFiles/"))  
           {  
               System.IO.Directory.CreateDirectory(webRoot + "/UserFiles/");  
           }  
           if (!System.IO.Directory.Exists(webRoot + "/UserFiles/" + userId + "/Image/"))  
           {  
               System.IO.Directory.CreateDirectory(webRoot + "/UserFiles/" + userId + "/Image/");  
           }  
  
           //Delete existing files first and then add new file  
           DeleteFiles(userId);  
  
           var path = Path.Combine(  
                       Directory.GetCurrentDirectory(), "wwwroot" + "/UserFiles/" + userId + "/Image/",  
                       form.Files[0].FileName);  
  
           using (var stream = new FileStream(path, FileMode.Create))  
           {  
               await form.Files[0].CopyToAsync(stream);  
           }  
  
           return RedirectToAction("Edit", new { id = Convert.ToString(form["UserId"]) });  
       }  

و همچنین کد مربوط به دانلود را:

public async Task<IActionResult> Download(string img, string userId)  
        {  
            string filename = img;  
            if (filename == null)  
                return Content("filename not present");  
  
            var path = Path.Combine(  
                           Directory.GetCurrentDirectory(),  
                           "wwwroot" + "/UserFiles/" + userId + "/Image/", filename);  
  
            var memory = new MemoryStream();  
            using (var stream = new FileStream(path, FileMode.Open))  
            {  
                await stream.CopyToAsync(memory);  
            }  
            memory.Position = 0;  
            return File(memory, GetContentType(path), Path.GetFileName(path));  
        }  
  
        private string GetContentType(string path)  
        {  
            var types = GetMimeTypes();  
            var ext = Path.GetExtension(path).ToLowerInvariant();  
            return types[ext];  
        }  
  
        private Dictionary<string, string> GetMimeTypes()  
        {  
            return new Dictionary<string, string>  
            {  
                {".png", "image/png"},  
                {".jpg", "image/jpeg"},  
                {".jpeg", "image/jpeg"},  
                {".gif", "image/gif"}  
            };  
        }  

در اینجا مباحث جدیدی را در رابطه با مپ کردن تصویر با مسیرها و پوشه‌های root مطرح می‌کنیم.

تمام فایل‌های استاتیک (.css, .js and images) به صورت پیش‌فرض در فولدر wwwroot ذخیره شده‌اند.

ما از "Request.Files" استفاده می‌کنیم، حالا ما از "Request.Form.Files" برای گرفتن فایل‌ها از فرم در کنترلر استفاده می‌کنیم.

)”"/Server.MapPath("~/UserImages" همچنین به "var webRoot = _env.WebRootPath;" تغییر پیدا می‌کند، جایی که ما _env را اضافه کردیم مانند:

private readonly DataAccess _context;  
       private readonly IHostingEnvironment _env;  
         
       public UsersController(DataAccess context, IHostingEnvironment env)  
       {  
           _context = context;  
           _env = env;  
       }  

تغییر دیگری که باید به آن توجه شود این است که کلمه کلیدی "HttpFileCollectionBase" در CORE استفاده نشده است، در عوض ما از "IFormFileCollection" برای گرفتن پارامترهای مجموعه فایل‌ها استفاده می‌کنیم.

همچنین کلمه کلیدی "HttpPostedFileBase" به "IFormFile" برای گرفتن یک فایل واحد تغییر می‌کند.

هنگامی که کاربر تمام فولدرها و زیرفولدرها را حذف می‌کند، فایل تصویر نیز همانند کد زیر حذف می‌شود:

[HttpPost, ActionName("Delete")]  
       [ValidateAntiForgeryToken]  
       public async Task<IActionResult> DeleteConfirmed(int id)  
       {  
           var user = await _context.User.SingleOrDefaultAsync(m => m.UserId == id);  
           _context.User.Remove(user);  
           await _context.SaveChangesAsync();  
  
           //Delete User Files as well  
           var dirPath = Path.Combine(  
                          Directory.GetCurrentDirectory(),  
                          "wwwroot" + "/UserFiles/" + Convert.ToString(id) + "/");  
           Directory.Delete(dirPath,true);  
           return RedirectToAction(nameof(Index));  
       }  

ممکن است توضیحات کامل نباشند ولی می‌توانید کد را با کمی تلاش به خوبی درک کنید.

حرف آخر

این یک برنامه حرفه‌ای نیست بلکه فقط یک برنامه مقدماتی و آموزشی برای Asp.Net Core 2.0 است. تمام کدهای مورد نیاز مربوط به فایل‌ها در این مقاله موجود هستند،فقط آن‌ها را در روت پروژه خود کپی پیس کنید.لطفا connection string مربوط به Sql Server خودتان را در فایل Sratrup.cs تغییر دهید. همچنین namespaces را با توجه به نام پروژه خود تغییر دهید.