Create Photo Gallery In ASP.NET Core

Introduction

 
This article explains how to create a photo gallery in ASP.NET Core 3.1.
 
So, for creating a photo gallery, we first build a database for storing gallery photos. For gallery style, we will use Ekko-lightbox CSS and js of the Admin-LTE template. And with this, we will perform a delete operation with photos.
 
Here, we are using the code-first approach for creating and generating a database. So, we make a "photography" table and the rest of the identity tables are auto-created.
 
Okay, let's see how to create it.
 
Step 1
 
Create a blank database name db_gallery in the SQL server database. Okay, now we generate a database by the code first approach.
 
So for this we first create an ApplicationDbContext.cs class and photography.cs and register this class under the ApplicationDbContext.cs class.
 
Create ApplicationDbContext.cs class like below,
  1. using System.Text;  
  2. using Microsoft.AspNetCore.Identity.EntityFrameworkCore;  
  3. using Microsoft.EntityFrameworkCore;  
  4.   
  5. namespace DemoGallery.Data  
  6. {  
  7.     public class ApplicationDbContext : IdentityDbContext  
  8.     {  
  9.         public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)  
  10.             : base(options)  
  11.         {  
  12.   
  13.         }  
  14.         public virtual DbSet<PhotoGraphy> PhotoGraphy { getset; }  
  15.     }  
  16. }  
Photography.cs class 
  1. public class PhotoGraphy  
  2.    {  
  3.        [Key]  
  4.        public int Id { getset; }  
  5.        [StringLength(100)]  
  6.        public string Title { getset; }  
  7.        [StringLength(100)]  
  8.        public string Name { getset; }  
  9.        [StringLength(255)]  
  10.        public string Path { getset; }  
  11.        public int? NoOfViews { getset; }  
  12.   
  13.    }  
 Make a DB connection string in the appsetting.json file and register this class in a startup.cs class under ConfigureServices() method.
 
appsettings.json
  1. "ConnectionStrings": {  
  2.     "DefaultConnection""Server=MYSERVERNAME;Database=db_gallery;user=USERID;password=PASSWORD;Trusted_Connection=false;"  
  3.   },  
 Register this connection string in Startup.cs class
  1. public void ConfigureServices(IServiceCollection services)  
  2.        {  
  3.            services.AddDbContext<ApplicationDbContext>(options =>  
  4.                options.UseSqlServer(  
  5.                    Configuration.GetConnectionString("DefaultConnection")));  
  6.            services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)  
  7.                .AddEntityFrameworkStores<ApplicationDbContext>();  
  8.            services.AddControllersWithViews();  
  9.            services.AddRazorPages();  
  10.        }  
Now it's time to update our database and auto-generate the DB with a migration approach. So for doing this, first go to the package manager console and enable the migration by the enable-migration command then, play add-migration, and the last one is the update-database.
 
 
Now check the database. Our database is ready to work
 
 
Step 2
 
Okay now, we are going to create a view like below,
 

We create a view that displays a list of photos in a gallery style, and above it, there is an upload button for uploading multiple files to the gallery. Within each file, there is a delete button for deleting every particular picture.
 
Step 3
 
Okay, here I am using the Ekko-lightbox CSS and js of Admin-LTE template. You can get this from the Admin-LTE website here. 
 
Embed the following CSS and JS into your project,
  • ekko-lightbox.css
  • adminlte.min.css
  • bootstrap-4.min.css
  • jquery.min.js
  • bootstrap.bundle.min.js
  • ekko-lightbox.min.js
  • adminlte.js
Step 4
 
Now create a ViewModel that contains the list of photos for uploading and displaying both.
 
Create a PhotographyViewModel.cs viewmodel,
  1. using DemoGallery.Data;  
  2. using System;  
  3. using System.Collections.Generic;  
  4. using System.Linq;  
  5. using System.Threading.Tasks;  
  6.   
  7. namespace DemoGallery.Models  
  8. {  
  9.     public class PhotographyViewModel  
  10.     {  
  11.         public PhotoGraphy photoGraphy { getset; }  
  12.         public List<PhotoGraphy> photoGraphyList { getset; }  
  13.     }  
  14. }  
Property 1, photoGraphy is the type of the database table ‘PhotoGraphy’, for the binding model on view.
 
Property 2, photoGraphyList is the type of the List<PhotoGraphy> which contains the list of photos for displaying the index view.
 
For getting multiple photos from the single ViewModel, In the PhotoGraphy table, we have created an additional property name Filephoto, of List<IFormFile> type, which we will not map with the database. So, let us decorate it with the [NotMappedAttribute] attribute. This property will help us to get a list of photos from the user.
 
Photography.cs class 
  1. public class PhotoGraphy  
  2.    {  
  3.        [Key]  
  4.        public int Id { getset; }  
  5.        [StringLength(100)]  
  6.        public string Title { getset; }  
  7.        [StringLength(100)]  
  8.        public string Name { getset; }  
  9.        [StringLength(255)]  
  10.        public string Path { getset; }  
  11.        public int? NoOfViews { getset; }  
  12.   
  13.        [NotMappedAttribute]  
  14.        [Required(ErrorMessage = "Photo is required.")]  
  15.        public List<IFormFile> filePhoto { getset; }  
  16.    }  
[NotMappedAttribute]
This is a property attribute found in the System.ComponentModel.DataAnnotations.Schema namespace. This attribute depicts any property decorated with this not to be a part of the database table. That means it will not become the database column.
 
Step 5
 
Create a GalleryController.cs which creates an index method for listing all photographs and getting data.
  1.  public class GalleryController : Controller  
  2.     {  
  3.         ApplicationDbContext db;  
  4.         public GalleryController(ApplicationDbContext db)  
  5.         {  
  6.             this.db = db;  
  7.   
  8.         }  
  9.         public IActionResult Index()  
  10.         {  
  11.             PhotographyViewModel viewModel = new PhotographyViewModel();  
  12.             viewModel.photoGraphyList= db.PhotoGraphy.ToList();  
  13.             viewModel.photoGraphy = new PhotoGraphy();  
  14.             return View(viewModel);  
  15.         }  
  16. }  
Step 6
 
Create _Layout.cshtml  and register all the css and js here.
  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4.     <meta charset="utf-8" />  
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0" />  
  6.     <title>@ViewData["Title"] - DemoGallery</title>  
  7.   
  8.     <link href="~/Content/all.min.css" rel="stylesheet" />  
  9.     <link href="~/Content/ekko-lightbox.css" rel="stylesheet" />  
  10.     <link href="~/Content/adminlte.min.css" rel="stylesheet" />  
  11.     <link href="~/Content/bootstrap-4.min.css" rel="stylesheet" />  
  12. </head>  
  13. <body>  
  14.     <header>  
  15.         <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">  
  16.             <div class="container">  
  17.                 <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">DemoGallery</a>  
  18.                 <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"  
  19.                         aria-expanded="false" aria-label="Toggle navigation">  
  20.                     <span class="navbar-toggler-icon"></span>  
  21.                 </button>  
  22.                 <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">  
  23.                     <partial name="_LoginPartial" />  
  24.                     <ul class="navbar-nav flex-grow-1">  
  25.                         <li class="nav-item">  
  26.                             <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>  
  27.                         </li>  
  28.                         <li class="nav-item">  
  29.                             <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>  
  30.                         </li>  
  31.                     </ul>  
  32.                 </div>  
  33.             </div>  
  34.         </nav>  
  35.     </header>  
  36.     <div class="container">  
  37.         <main role="main" class="pb-3">  
  38.             @RenderBody()  
  39.         </main>  
  40.     </div>  
  41.   
  42.     <footer class="border-top footer text-muted">  
  43.         <div class="container">  
  44.             © 2020 - DemoGallery - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>  
  45.         </div>  
  46.     </footer>  
  47.   
  48.     <!----AdminLTE,SweetAlert,Bootstrap MultiSelect ,Switch-->  
  49.     <script src="~/Scripts/jquery.min.js"></script>  
  50.     <script src="~/Scripts/bootstrap.bundle.min.js"></script>  
  51.     <script src="~/Scripts/ekko-lightbox.min.js"></script>  
  52.     <script src="~/Scripts/adminlte.js"></script>  
  53.     @RenderSection("Scripts", required: false)  
  54. </body>  
  55. </html>  
Now create an index.CSS HTML view for displaying all gallery photos. Here, I make an additional link button for uploading files and render a delete link with each teacher.
 
index.cshtml view 
  1. @model PhotographyViewModel  
  2. @{  
  3.     ViewData["Title"] = "Index";  
  4. }  
  5.   
  6. <div class="col-12">  
  7.     <div class="card card-primary">  
  8.         <div class="card-header">  
  9.             <div class="card-title">  
  10.                 Gallery Photo's  
  11.             </div>  
  12.         </div>  
  13.         <div class="card-body">  
  14.   
  15.             <form id="frmPhototGraphy" class="form-horizontal" asp-action="AddPhotos" asp-controller="gallery" method="post" enctype="multipart/form-data">  
  16.                 <div class="col-md-6 col-sm-6">  
  17.   
  18.                     <div class="form-group row">  
  19.                         <label class="col-sm-2 col-form-label">Photo</label>  
  20.   
  21.                         <div class="col-sm-6 custom-file">  
  22.   
  23.                             <input asp-for="@Model.photoGraphy.filePhoto" type="file" class="custom-file-input" multiple="multiple">  
  24.                             <label class="custom-file-label" for="@Model.photoGraphy.filePhoto">Choose file</label>  
  25.                             <span asp-validation-for="@Model.photoGraphy.filePhoto" class="text-danger"></span>  
  26.   
  27.                         </div>  
  28.                         <div class="col-sm-4"> <button type="submit" class="btn btn-danger">Upload All</button></div>  
  29.                     </div>  
  30.   
  31.   
  32.   
  33.                 </div>  
  34.             </form>  
  35.             <br />  
  36.             <div class="row">  
  37.                 @if (Model.photoGraphyList != null)  
  38.                 {  
  39.                     foreach (var item in Model.photoGraphyList)  
  40.                     {  
  41.                         <div class="col-sm-2">  
  42.                             <a href="@Url.Content("~/photography/"+item.Name)" data-toggle="lightbox" data-title="sample 1 - white" data-gallery="gallery">  
  43.                                 <img src="~/photography/@item.Name" asp-append-version="true" class="img-fluid mb-2" alt="white sample">  
  44.                             </a>  
  45.                             <a href="@Url.Action("DeletePhoto","gallery",new { id=item.Id})" style="float:right">Delete</a>  
  46.                         </div>  
  47.                     }  
  48.   
  49.                 }  
  50.   
  51.             </div>  
  52.         </div>  
  53.     </div>  
  54. </div>  
  55.   
  56. @section Scripts{  
  57.   
  58.     <script>  
  59.         
  60.         $(function () {  
  61.             $(document).on('click''[data-toggle="lightbox"]', function (event) {  
  62.                 event.preventDefault();  
  63.                 $(this).ekkoLightbox({  
  64.                     alwaysShowClose: true  
  65.                 });  
  66.             });  
  67.         });  
  68.   
  69.   
  70.     </script>  
  71. }  
Step 7
 
Now let's create a method for adding photos into the database
  1. [HttpPost]  
  2.       public IActionResult AddPhotos(PhotographyViewModel model)  
  3.       {  
  4.           if (!ModelState.IsValid)  
  5.               return View(model);  
  6.           var Files = model.photoGraphy.filePhoto;  
  7.   
  8.           if (Files.Count > 0)  
  9.           {  
  10.               foreach (var item in Files)  
  11.               {  
  12.                   PhotoGraphy photography = new PhotoGraphy();  
  13.                   var guid = Guid.NewGuid().ToString();  
  14.                   var filePath = "wwwroot/photography/" + guid + item.FileName;  
  15.                   var fileName = guid + item.FileName;  
  16.                   using (var stream = System.IO.File.Create(filePath))  
  17.                   {  
  18.                       item.CopyTo(stream);  
  19.                       photography.Name = fileName;  
  20.                       photography.Path = filePath;  
  21.                       photography.Title = item.FileName;  
  22.                       photography.NoOfViews = 1;  
  23.                       db.PhotoGraphy.Add(photography);  
  24.                       db.SaveChanges();  
  25.                   }  
  26.               }  
  27.               return RedirectToAction("Index");  
  28.           }  
  29.   
  30.   
  31.           return RedirectToAction("Index");  
  32.       }  
Step 8
 
Create a delete action method for deleting each photo by id.
  1. public IActionResult DeletePhoto(int id)  
  2.        {  
  3.            var photo = db.PhotoGraphy.Find(id);  
  4.            if (photo != null)  
  5.            {  
  6.                db.PhotoGraphy.Remove(photo);  
  7.                db.SaveChanges();  
  8.            }  
  9.            return RedirectToAction("index");  
  10.   
  11.        }  
Here, the delete action redirects the user to the DeletePhoto action on the gallery controller.
  1. <a href="@Url.Action("DeletePhoto","gallery",new { id=item.Id})" style="float:right">Delete</a>  
Output
 
Here is what the gallery looks like
 
 
 
 

Summary

 
In the above article, we learned to create and delete multiple files in ASP.NET Core 3.1 MVC, and added an Ekko-lightbox CSS and JS for displaying the layout of this gallery.