Upload, Edit, and Delete Image with Dapper in .NET Core

Introduction

This tutorial teaches ASP.NET Core MVC web development with controllers and views. You will learn to upload, edit, and delete image files with Dapper, repository pattern, and UnitOfWork in .NET Core. To find the complete Code.

Prerequisites

  1. Visual Studio is the latest version with the ASP.NET and web development workload.
  2. .NET SDK latest version (.NET 8.0)
  3. SQL SERVER latest

Creating database table

Launch SQL Server, select Database, and New Database.

CREATE TABLE [dbo].[t_speaker] (
    [f_uid]             UNIQUEIDENTIFIER PRIMARY KEY NOT NULL,
    [f_iid]             INT              IDENTITY (1, 1) NOT NULL,
    [f_fname]           NVARCHAR (150)   NOT NULL,
    [f_lname]           NVARCHAR (150)   NOT NULL,
    [f_gender]          INT              NULL,
    [f_speach_date]     DATETIME         NOT NULL,
    [f_speach_time]     DATETIME         NOT NULL,
    [f_speach_venue]    NVARCHAR (250)   NULL,
    [f_speaker_picture] NVARCHAR (MAX)   NULL,
    [f_create_date]     DATETIME         NULL,
    [f_update_date]     DATETIME         NULL,
    [f_delete_date]     DATETIME         NULL,
);

Creating a New Project in Visual Studio

  1. Launch Visual Studio and select Create a New Project.
    New project

Create a Web App

  1. Start Visual Studio and select Create a new project.
  2. In the Create a new project dialog, select ASP.NET Core Web App (Model-View-Controller) > Next.
    Create a Web App

Configuring Your New Project

  1. In the Configure your new project dialog, enter UploadEditDeleteImageWithDapperNetCore_Demo for the Project name. It's important to name the project UploadEditDeleteImageWithDapperNetCore_Demo. Capitalization needs to match each namespace when code is copied.
  2. Choose a location for your project.
  3. Specify the solution name
  4. Select Next.
    Configure project

Additional information

  1. In the Additional information dialog:
    • Select .NET 8.0 (Long Term Support).
    • Verify that Do not use top-level statements is unchecked.
  2. Select Create.
    Additional information

Option 1. Install the Dapper, Microsoft.Data.SqlClient Library through NuGet Package Manager

  1. Go to Project > Manage NuGet Packages.
  2. On the NuGet Package Manager page, select nuget.org as the Package source.
  3. Under the Browse tab, search for Dapper, then choose Dapper from the list and select Install.
  4. If prompted to verify the installation, click OK.
    Install Dapper

Option 2. Installing the Dapper Library through the Visual Studio Command Line

  1. In Visual Studio, navigate to Tools > NuGet Package Manager > Package Manager Console.
  2. Enter the following command in the Package Manager Console tab.
Install-Package Dapper

Add a data model class

Right-click the Models folder > Add > Class. Name the file SpeakerModel.cs.

Update the Models/SpeakerModel.cs file with the following code:

The SpeakerModel class contains a f_uid field, which is required by the database for the primary key.

SpeakerModel.cs

using System.ComponentModel.DataAnnotations;

namespace UploadEditDeleteImageWithDapperNetCore_Demo.Models
{
    public class SpeakerModel
    {
        public Guid f_uid { get; set; }
        [Display(Name = "ID")]
        public int f_iid { get; set; }

        [Display(Name = "First Name")]
        public string f_fname { get; set; }

        [Display(Name = "Last Name")]
        public string f_lname { get; set; }

        [Display(Name = "Gender")]
        public Gender f_gender { get; set; }

        [Required]
        [DataType(DataType.Date)]
        [Display(Name = "Speach Date")]
        public DateTime f_speach_date { get; set; }

        [Required]
        [DataType(DataType.Time)]
        [Display(Name = "Speach Time")]
        public DateTime f_speach_time { get; set; }

        [Display(Name = "Venue")]
        public string? f_speach_venue { get; set; }

        [Display(Name = "Photo")]
        public string f_speaker_picture { get; set; }

        [Display(Name = "Create Date")]
        public DateTime? f_create_date { get; set; }

        [Display(Name = "Update Date")]
        public DateTime? f_update_date { get; set; }

        [Display(Name = "Delete Date")]
        public DateTime? f_delete_date { get; set; }
    }
}

Gender.cs

namespace UploadEditDeleteImageWithDapperNetCore_Demo.Models
{
    public enum Gender
    {
        Male = 1,
        Female = 2
    }
}

SpeakerViewModel.cs

using System.ComponentModel.DataAnnotations;
using UploadEditDeleteImageWithDapperNetCore_Demo.Models;

namespace UploadEditDeleteImageWithDapperNetCore_Demo.ViewModels
{
    public class SpeakerViewModel:UpdateImageFileModel
    {
        [Display(Name ="ID")]
        public int f_iid { get; set; }

        [Display(Name = "First Name")]
        public string f_fname { get; set; }

        [Display(Name = "Last Name")]
        public string f_lname { get; set; }

        [Display(Name = "Gender")]
        public Gender f_gender { get; set; }

        [Required]
        [DataType(DataType.Date)]
        [Display(Name = "Date")]
        public DateTime f_speach_date { get; set; }

        [Required]
        [DataType(DataType.Time)]
        [Display(Name = "Time")]
        public DateTime f_speach_time { get; set; }

        [Display(Name = "Venue")]
        public string? f_speach_venue { get; set; }

        [Display(Name = "Create Date")]
        public DateTime f_create_date { get; set; }

        [Display(Name = "Update Date")]
        public DateTime f_update_date { get; set; }

        [Display(Name = "Delete Date")]
        public DateTime f_delete_date { get; set; }
    }
}

UploadImageFileViewModel.cs

using System.ComponentModel.DataAnnotations;

namespace UploadEditDeleteImageWithDapperNetCore_Demo.ViewModels
{
    public class UploadImageFileViewModel
    {
        [Display(Name = "Photo")]
        public IFormFile f_speaker_photo { get; set; }
    }
}

UpdateImageFileViewModel.cs

namespace UploadEditDeleteImageWithDapperNetCore_Demo.ViewModels
{
    public class UpdateImageFileModel:UploadImageFileViewModel
    {
        public Guid f_uid { get; set; }
        public string f_existing_photo { get; set; }
    }
}

Adding interfaces

  1. In Solution Explorer, right-click Add New Folder.
  2. Rename the folder to Repositories under these two New Folders Interfaces and Repository.
  3. Right-click on the renamed folder and Add the interface name IGenericRepository.cs

IGenericRepository.cs

namespace UploadEditDeleteImageWithDapperNetCore_Demo.Repositories.Interface
{
    public interface IGenericRepository<T>where T : class
    {
        Task<IEnumerable<T>> Get();
        Task<T> Find(Guid uid);
        Task<T> Add(T model);
        Task<T> Update(T model);
        Task<int> Remove(T model);
    }
}

IUnitOfWork.cs

namespace UploadEditDeleteImageWithDapperNetCore_Demo.Repositories.Interface
{
    public interface IUnitOfWork
    {
        ISpeaker Speakers { get; }
    }
}

ISpeaker.cs

using UploadEditDeleteImageWithDapperNetCore_Demo.Models;

namespace UploadEditDeleteImageWithDapperNetCore_Demo.Repositories.Interface
{
    public interface ISpeaker:IGenericRepository<SpeakerModel>
    {
    }
}

Interface Implementation

UnitOfWork.cs

using UploadEditDeleteImageWithDapperNetCore_Demo.Repositories.Interface;

namespace UploadEditDeleteImageWithDapperNetCore_Demo.Repositories.Repository
{
    public class UnitOfWork : IUnitOfWork
    {
        public ISpeaker Speakers { get; set; }
        public UnitOfWork(ISpeaker Speakers)
        {
            this.Speakers = Speakers;
        }
    }
}

SpeakerRepository.cs

using Dapper;
using Microsoft.Data.SqlClient;
using UploadEditDeleteImageWithDapperNetCore_Demo.Models;
using UploadEditDeleteImageWithDapperNetCore_Demo.Repositories.Interface;

namespace UploadEditDeleteImageWithDapperNetCore_Demo.Repositories.Repository
{
    public class SpeakerRepository : ISpeaker
    {
        private readonly IConfiguration _configuration;
        private readonly SqlConnection _connection;

        public SpeakerRepository(IConfiguration configuration)
        {
            _configuration = configuration;
            _connection = new SqlConnection(_configuration.GetConnectionString("DefaultConnection"));
        }
        public async Task<IEnumerable<SpeakerModel>> Get()
        {
            var sql = $@"SELECT [f_uid]
                               ,[f_iid]
                               ,[f_fname]
                               ,[f_lname]
                               ,[f_gender]
                               ,[f_speach_date]
                               ,[f_speach_time]
                               ,[f_speach_venue]
                               ,[f_speaker_picture]
                               ,[f_create_date]
                               ,[f_update_date]
                               ,[f_delete_date]
                            FROM 
                                [dbo].[t_speaker]
                            WHERE
	                            [f_delete_date] IS NULL";

            return await _connection.QueryAsync<SpeakerModel>(sql);
        }

        public async Task<SpeakerModel> Find(Guid uid)
        {
            var sql = $@"SELECT [f_uid]
                               ,[f_iid]
                               ,[f_fname]
                               ,[f_lname]
                               ,[f_gender]
                               ,[f_speach_date]
                               ,[f_speach_time]
                               ,[f_speach_venue]
                               ,[f_speaker_picture]
                               ,[f_create_date]
                               ,[f_update_date]
                               ,[f_delete_date]
                          FROM 
                               [dbo].[t_speaker]
                          WHERE
                                [f_uid]=@uid AND
                                [f_delete_date] IS NULL";

            return await _connection.QueryFirstOrDefaultAsync<SpeakerModel>(sql, new { uid });
        }

        public async Task<SpeakerModel> Add(SpeakerModel model)
        {
            model.f_uid = Guid.NewGuid();
            model.f_create_date = DateTime.Now;

            var sql = $@"INSERT INTO [dbo].[t_speaker]
                               ([f_uid]
                               ,[f_fname]
                               ,[f_lname]
                               ,[f_gender]
                               ,[f_speach_date]
                               ,[f_speach_time]
                               ,[f_speach_venue]
                               ,[f_speaker_picture]
                               ,[f_create_date])
                         VALUES
                               (@f_uid,
                               @f_fname,
                               @f_lname,
                               @f_gender,
                               @f_speach_date,
                               @f_speach_time,
                               @f_speach_venue,
                               @f_speaker_picture,
                               @f_create_date)";

            await _connection.ExecuteAsync(sql, model);
            return model;
        }

        public async Task<SpeakerModel> Update(SpeakerModel model)
        {
            model.f_update_date = DateTime.Now;
            var sql = $@"UPDATE [dbo].[t_speaker]
                        SET [f_fname] = @f_fname,
                            [f_lname] = @f_lname,
                            [f_gender] = @f_gender,
                            [f_speach_date] = @f_speach_date,
                            [f_speach_time] = @f_speach_time,
                            [f_speach_venue] = @f_speach_venue,
                            [f_speaker_picture] = @f_speaker_picture,
                            [f_update_date] = @f_update_date
                        WHERE 
                            [f_uid]=@f_uid"; ;

            await _connection.ExecuteAsync(sql, model);
            return model;
        }

        public async Task<int> Remove(SpeakerModel model)
        {
            model.f_delete_date = DateTime.Now;
            var sql = $@"
                        UPDATE [t_speaker]
                        SET
                            [f_delete_date] =@f_delete_date
                        WHERE 
                            [f_uid]=@f_uid";

            return await _connection.ExecuteAsync(sql, model);
        }
    }
}

Add a controller

  1. In Solution Explorer, right-click Controllers > Add > Controller.
  2. In the Add New Scaffolded Item dialog box, select MVC Controller - Empty > Add.
  3. In the Add New Item - UploadEditDeleteImageWithDapperNetCore_Demo dialog, enter SpeakersController.cs and select Add.

Replace the contents of Controllers/SpeakersController.cs with the following code.

using Microsoft.AspNetCore.Mvc;
using UploadEditDeleteImageWithDapperNetCore_Demo.Models;
using UploadEditDeleteImageWithDapperNetCore_Demo.Repositories.Interface;
using UploadEditDeleteImageWithDapperNetCore_Demo.ViewModels;

namespace UploadEditDeleteImageWithDapperNetCore_Demo.Controllers
{
    public class SpeakersController : Controller
    {
        private readonly IUnitOfWork unitOfWork;
        private readonly IWebHostEnvironment environment;
        public SpeakersController(IUnitOfWork unitOfWork, IWebHostEnvironment environment)
        {
            this.unitOfWork = unitOfWork;
            this.environment = environment;
        }
        public async Task<IActionResult> Index()
        {
            var speakers = await unitOfWork.Speakers.Get();
            string imageUrl = $"{this.Request.Scheme}://{this.Request.Host}{this.Request.PathBase}" + "/Uploads/" + speakers?.FirstOrDefault().f_speaker_picture;
            ViewBag.SpeakerImage = imageUrl;
            return View(speakers);
        }
        public async Task<IActionResult> Details(Guid id)
        {
            if (id == Guid.Empty)
            {
                return NotFound();
            }
            var speaker = await unitOfWork.Speakers.Find(id);

            var speakers = new SpeakerViewModel()
            {
                f_uid = speaker.f_uid,
                f_fname = speaker.f_fname,
                f_lname = speaker.f_lname,
                f_gender = speaker.f_gender,
                f_speach_date = speaker.f_speach_date,
                f_speach_time = speaker.f_speach_time,
                f_speach_venue = speaker.f_speach_venue,
                f_existing_photo = speaker.f_speaker_picture
            };
            if (speaker == null)
            {
                return NotFound();
            }
            string imageUrl = $"{this.Request.Scheme}://{this.Request.Host}{this.Request.PathBase}" + "/Uploads/" + speakers.f_existing_photo;
            ViewBag.ExistImage = imageUrl;
            return View(speakers);
        }
        public IActionResult Create()
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create(SpeakerViewModel model)
        {
            try
            {
                string uniqueFileName = ProcessUploadedFile(model);
                var speaker = new SpeakerModel()
                {
                    f_fname = model.f_fname,
                    f_lname = model.f_lname,
                    f_gender = model.f_gender,
                    f_speach_date = model.f_speach_date,
                    f_speach_time = model.f_speach_time,
                    f_speach_venue = model.f_speach_venue,
                    f_create_date = DateTime.Now,
                    f_speaker_picture = uniqueFileName
                };

                await unitOfWork.Speakers.Add(speaker);
                return RedirectToAction(nameof(Index));
            }
            catch
            {
                throw;
            }
        }
        public async Task<IActionResult> Edit(Guid id)
        {
            if (id == Guid.Empty)
            {
                return NotFound();
            }

            var speaker = await unitOfWork.Speakers.Find(id);
            var speakerExtended = new SpeakerViewModel()
            {
                f_uid = speaker.f_uid,
                f_iid = speaker.f_iid,
                f_fname = speaker.f_fname,
                f_lname = speaker.f_lname,
                f_gender = speaker.f_gender,
                f_speach_date = speaker.f_speach_date,
                f_speach_time = speaker.f_speach_time,
                f_speach_venue = speaker.f_speach_venue,
                f_existing_photo = speaker.f_speaker_picture
            };

            if (speaker == null)
            {
                return NotFound();
            }
            string imageUrl = $"{this.Request.PathBase}" + "/Uploads/" + speaker.f_speaker_picture;
            ViewBag.ExistImage = imageUrl;
            return View(speakerExtended);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(Guid id, SpeakerViewModel model)
        {
            var speaker = await unitOfWork.Speakers.Find(id);
            speaker.f_fname = model.f_fname;
            speaker.f_lname = model.f_lname;
            speaker.f_gender = model.f_gender;
            speaker.f_speach_date = model.f_speach_date;
            speaker.f_speach_time = model.f_speach_time;
            speaker.f_speach_venue = model.f_speach_venue;
            speaker.f_update_date = DateTime.Now;

            if (model.f_speaker_photo != null)
            {
                var CurrentImage = Path.Combine(environment.WebRootPath, "Uploads", speaker.f_speaker_picture);
                if (System.IO.File.Exists(CurrentImage))
                {
                    System.IO.File.Delete(CurrentImage);
                }

                speaker.f_speaker_picture = ProcessUploadedFile(model);
            }

            await unitOfWork.Speakers.Update(speaker);
            return RedirectToAction(nameof(Index));
        }

        public async Task<IActionResult> Delete(Guid id)
        {
            if (id == Guid.Empty)
            {
                return NotFound();
            }

            var speaker = await unitOfWork.Speakers.Find(id);
            var speakerExtended = new SpeakerViewModel()
            {
                f_uid = speaker.f_uid,
                f_iid = speaker.f_iid,
                f_fname = speaker.f_fname,
                f_lname = speaker.f_lname,
                f_gender = speaker.f_gender,
                f_speach_date = speaker.f_speach_date,
                f_speach_time = speaker.f_speach_time,
                f_speach_venue = speaker.f_speach_venue,
                f_existing_photo = speaker.f_speaker_picture
            };

            if (speaker == null)
            {
                return NotFound();
            }
            string imageUrl = $"{this.Request.PathBase}" + "/Uploads/" + speaker.f_speaker_picture;
            ViewBag.ExistImage = imageUrl;
            return View(speakerExtended);
        }

        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(Guid id)
        {
            var speaker = await unitOfWork.Speakers.Find(id);
            var CurrentImage = Path.Combine(environment.WebRootPath, "Uploads", speaker.f_speaker_picture);
            ViewBag.ExistImage = CurrentImage;
            if (System.IO.File.Exists(CurrentImage))
            {
                System.IO.File.Delete(CurrentImage);
            }
            await unitOfWork.Speakers.Remove(speaker);
            return RedirectToAction(nameof(Index));
        }

        private string ProcessUploadedFile(SpeakerViewModel model)
        {
            string uniqueFileName = null;

            if (model.f_speaker_photo != null)
            {
                string path = Path.Combine(environment.WebRootPath, "Uploads");
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
                string uploadsFolder = Path.Combine(environment.WebRootPath, "Uploads");
                uniqueFileName = Guid.NewGuid().ToString() + "_" + model.f_speaker_photo.FileName;
                string filePath = Path.Combine(uploadsFolder, uniqueFileName);
                using (var fileStream = new FileStream(filePath, FileMode.Create))
                {
                    model.f_speaker_photo.CopyTo(fileStream);
                }
            }

            return uniqueFileName;
        }
    }
}

Add a view

  1. Right-click on the Views folder, then Add > New Folder and name the folder Speakers
  2. Right-click on the Views/Speaker folder, and then Add > New Item.
  3. In the Add New Item dialog, select Show All Templates.
  4. In the Add New Item - UploadEditDeleteImageWithDapperNetCore_Demo dialog:
  5. In the search box in the upper-right, enter the view
  6. Select Razor View - Empty
  7. Keep the Name box value, Index.cshtml.
  8. Select Add
  9. Replace the contents of the Views/Speakers/Index.cshtml, Create.cshtml, Edit.cshtml and Delete.cshtml Razor view file with the following:

Index.cshtml

@model IEnumerable<UploadEditDeleteImageWithDapperNetCore_Demo.Models.SpeakerModel>

@{
    ViewData["Title"] = "Index";
}


<h3 class="text-center text-uppercase">list of speakers</h3>

<p style="float:right;">
    <a asp-action="Create" class="btn btn-primary rounded-0"><i class="fa-solid fa-square-plus"></i> Add New</a>
</p>
<table class="table table-bordered table-striped">
    <thead class="text-center text-uppercase bg-primary text-white">
        <tr>
            <th>@Html.DisplayNameFor(s => s.f_iid)</th>
            <th>@Html.DisplayNameFor(s => s.f_speaker_picture)</th>
            <th>@Html.DisplayNameFor(s => s.f_fname)</th>
            <th>@Html.DisplayNameFor(s => s.f_lname)</th>
            <th>@Html.DisplayNameFor(s => s.f_gender)</th>
            <th>@Html.DisplayNameFor(s => s.f_speach_date)</th>
            <th>@Html.DisplayNameFor(s => s.f_speach_time)</th>
            <th>@Html.DisplayNameFor(s => s.f_speach_venue)</th>
            <th>@Html.DisplayNameFor(s => s.f_create_date)</th>
            <th>@Html.DisplayNameFor(s => s.f_update_date)</th>
            <th>Action(s)</th>
        </tr>
    </thead>
    <tbody>
            @foreach (var item in Model)
            {
            <tr>
                <td>@item.f_iid</td>
                <td>
                    @if (ViewBag.SpeakerImage !=null)
                    {
                        <a href="@Url.Action("Details","Speakers",new { id=item.f_uid })"><img src="@ViewBag.SpeakerImage" alt="speaker-img" height="35" width="35" /></a>
                    }
                </td>
                <td>@item.f_fname</td>
                <td>@item.f_lname</td>
                <td>@item.f_gender</td>
                <td>@item.f_speach_date.ToString("dd-MMM-yyyy")</td>
                <td>@item.f_speach_time.ToString("hh:mm")</td>
                <td>@item.f_speach_venue</td>
                <td>@item.f_create_date?.ToString("dd-MM-yyyy hh:mm:ss:ff")</td>
                <td>@item.f_update_date?.ToString("dd-MM-yyyy hh:mm:ss:ff")</td>
                <td>
                    <a href="@Url.Action("Edit","Speakers",new { id=item.f_uid })" class="btn btn-sm btn-primary"><i class="fa-solid fa-pen-to-square"></i></a>
                    <a href="@Url.Action("Delete","Speakers",new { id=item.f_uid })" class="btn btn-sm btn-danger"><i class="fa-solid fa-trash"></i></a>
                </td>
            </tr>
            }
    </tbody>
</table>

Create.cshtml

@model UploadEditDeleteImageWithDapperNetCore_Demo.ViewModels.SpeakerViewModel

@{
    ViewData["Title"] = "Create";
}

<div class="container">
    <div class="card">
        <div class="card-header">
            <h4>Add New Speaker</h4>
        </div>
        <form asp-action="Create" enctype="multipart/form-data">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="row">
                <div class="col-8">
                    <div class="card-body">
                        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                        <div class="form-group row">
                            <label asp-for="f_fname" class="col-sm-2 col-form-label"></label>
                            <div class="col-sm-10">
                                <input asp-for="f_fname" class="form-control" placeholder="First Name">
                            </div>
                            <span asp-validation-for="f_fname" class="text-danger"></span>
                        </div>
                        <div class="form-group row">
                            <label asp-for="f_lname" class="col-sm-2 col-form-label"></label>
                            <div class="col-sm-10">
                                <input asp-for="f_lname" class="form-control" placeholder="Last Name">
                            </div>
                            <span asp-validation-for="f_fname" class="text-danger"></span>
                        </div>
                        <div class="form-group row">
                            <label asp-for="f_gender" class="col-sm-2 col-form-label"></label>
                            <div class="col-sm-10">
                                <select asp-for="f_gender" class="form-select" asp-items="Html.GetEnumSelectList<Gender>()">
                                    <option selected="selected" value="">Please select</option>
                                </select>
                            </div>
                            <span asp-validation-for="f_gender" class="text-danger"></span>
                        </div>
                        <div class="form-group row">
                            <label asp-for="f_speach_date" class="col-sm-2 col-form-label"></label>
                            <div class="col-sm-10">
                                <input asp-for="f_speach_date" class="form-control" placeholder="Choose Date">
                            </div>
                            <span asp-validation-for="f_speach_date" class="text-danger"></span>
                        </div>
                        <div class="form-group row">
                            <label asp-for="f_speach_time" class="col-sm-2 col-form-label"></label>
                            <div class="col-sm-10">
                                <input asp-for="f_speach_time" class="form-control" placeholder="Choose Time">
                            </div>
                            <span asp-validation-for="f_speach_time" class="text-danger"></span>
                        </div>
                        <div class="form-group row">
                            <label asp-for="f_speach_venue" class="col-sm-2 col-form-label"></label>
                            <div class="col-sm-10">
                                <textarea asp-for="f_speach_venue" class="form-control" placeholder="Speach Venue"></textarea>
                            </div>
                            <span asp-validation-for="f_speach_venue" class="text-danger"></span>
                        </div>
                        <div class="form-group row">
                            <label asp-for="f_speaker_photo" class="col-sm-2 col-form-label"></label>
                            <div class="custom-file col-sm-10">
                                <input asp-for="f_speaker_photo" class="custom-file-input" />
                                <label class="custom-file-label" for="customFile">Choose file</label>
                            </div>
                            <span asp-validation-for="f_speaker_photo" class="text-danger"></span>
                        </div>
                    </div>
                </div>
                <div class="col-4">
                    <div id="image-holder"> </div>
                </div>
            </div>
            <div style="float:right; margin-bottom:10px;padding:10px;">
                <input type="submit" value="Submit" class="btn btn-primary rounded-0" />
                <a asp-action="Index" class="btn btn-primary rounded-0"> Back to List</a>
            </div>
        </form>
    </div>
</div>

@section Scripts {
    <script>
        $(".custom-file-input").on("change", function () {
            var fileName = $(this).val().split("\\").pop();
            $(this).siblings(".custom-file-label").addClass("selected").html(fileName);
        });
        $("#f_speaker_photo").on('change', function () {
            if (typeof (FileReader) != "undefined") {
                var image_holder = $("#image-holder");
                image_holder.empty()
                var reader = new FileReader();
                reader.onload = function (e) {
                    $("<img />", {
                        "src": e.target.result,
                        "class": "img-thumbnail"
                    }).appendTo(image_holder);
                }
                image_holder.show();
                reader.readAsDataURL($(this)[0].files[0]);
            } else {
                alert("This browser does not support FileReader.");
            }
        });
    </script>
    @{
        await Html.RenderPartialAsync("_ValidationScriptsPartial");
    }
}

Edit.cshtml

@model UploadEditDeleteImageWithDapperNetCore_Demo.ViewModels.SpeakerViewModel

@{
    ViewData["Title"] = "Edit";
}

<div class="container">
    <div class="card">
        <div class="card-header">
            <h4>Edit Speaker</h4>
        </div>
        <div class="card-body">
            <form asp-action="Edit" enctype="multipart/form-data">
                <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                <input hidden asp-for="f_uid" />
                <input hidden asp-for="f_iid" />
                <div class="row">
                    <div class="col-8">
                        <div class="form-group row">
                            <label asp-for="f_fname" class="col-sm-2 col-form-label"></label>
                            <div class="col-sm-10">
                                <input asp-for="f_fname" class="form-control" placeholder="First Name">
                            </div>
                            <span asp-validation-for="f_fname" class="text-danger"></span>
                        </div>
                        <div class="form-group row">
                            <label asp-for="f_lname" class="col-sm-2 col-form-label"></label>
                            <div class="col-sm-10">
                                <input asp-for="f_lname" class="form-control" placeholder="Last Name">
                            </div>
                            <span asp-validation-for="f_fname" class="text-danger"></span>
                        </div>
                        <div class="form-group row">
                            <label asp-for="f_gender" class="col-sm-2 col-form-label"></label>
                            <div class="col-sm-10">
                                <select asp-for="f_gender" class="form-select" asp-items="Html.GetEnumSelectList<Gender>()">
                                    <option selected="selected" value="@Model.f_gender">Please select</option>
                                </select>
                            </div>
                            <span asp-validation-for="f_gender" class="text-danger"></span>
                        </div>
                        <div class="form-group row">
                            <label asp-for="f_speach_date" class="col-sm-2 col-form-label"></label>
                            <div class="col-sm-10">
                                <input asp-for="f_speach_date" class="form-control" placeholder="Choose Date">
                            </div>
                            <span asp-validation-for="f_speach_date" class="text-danger"></span>
                        </div>
                        <div class="form-group row">
                            <label asp-for="f_speach_time" class="col-sm-2 col-form-label"></label>
                            <div class="col-sm-10">
                                <input asp-for="f_speach_time" class="form-control" placeholder="Choose Time">
                            </div>
                            <span asp-validation-for="f_speach_time" class="text-danger"></span>
                        </div>
                        <div class="form-group row">
                            <label asp-for="f_speach_venue" class="col-sm-2 col-form-label"></label>
                            <div class="col-sm-10">
                                <textarea asp-for="f_speach_venue" class="form-control" placeholder="Speach Venue"></textarea>
                            </div>
                            <span asp-validation-for="f_speach_venue" class="text-danger"></span>
                        </div>
                        <div class="form-group row">
                            <label asp-for="f_speaker_photo" class="col-sm-2 col-form-label"></label>
                            <div class="custom-file col-sm-10">
                                <input asp-for="f_speaker_photo" class="custom-file-input" />
                                <label class="custom-file-label" for="customFile">Choose file</label>
                            </div>
                            <span asp-validation-for="f_speaker_photo" class="text-danger"></span>
                        </div>
                    </div>
                    <div class="col-4">
                        <div id="image-holder">
                            <img src="~/Uploads/@Model.f_existing_photo" class="img-thumbnail" height="350" width="285" asp-append-version="true" />
                        </div>
                    </div>
                </div>
                <div class="form-group" style="float:right">
                    <input type="submit" value="Save" class="btn btn-md btn-primary rounded-0" />
                    <a href="@Url.Action("Index", "Speakers")" class="btn btn-md btn-primary rounded-0"><i class="fa-solid fa-backward"></i> Back to List</a>
                </div>
            </form>
        </div>
    </div>
</div>

@section Scripts {
    <script>
        $(".custom-file-input").on("change", function () {
            var fileName = $(this).val().split("\\").pop();
            $(this).siblings(".custom-file-label").addClass("selected").html(fileName);
        });
        $("#f_speaker_photo").on('change', function () {
            if (typeof (FileReader) != "undefined") {
                var image_holder = $("#image-holder");
                image_holder.empty()
                var reader = new FileReader();
                reader.onload = function (e) {
                    $("<img />", {
                        "src": e.target.result,
                        "class": "img-thumbnail"
                    }).appendTo(image_holder);
                }
                image_holder.show();
                reader.readAsDataURL($(this)[0].files[0]);
            } else {
                alert("This browser does not support FileReader.");
            }
        });
    </script>
    @{
        await Html.RenderPartialAsync("_ValidationScriptsPartial");
    }
}

Delete.cshtml

@model UploadEditDeleteImageWithDapperNetCore_Demo.ViewModels.SpeakerViewModel

@{
    ViewData["Title"] = "Delete";
}

<div class="container">
    <div class="alert alert-danger" role="alert">
        Are you sure you want to delete this?
    </div>
    <div class="card">
        <div class="card-header">
            <h4>Speaker Details</h4>
        </div>
        <div class="card-body">
            <div class="row">
                <div class="col-8">
                    <dl class="row">
                        <dt class="col-sm-2">
                            @Html.DisplayNameFor(model => model.f_fname)
                        </dt>
                        <dd class="col-sm-10">
                            @Html.DisplayFor(model => model.f_fname)
                        </dd>
                        <dt class="col-sm-2">
                            @Html.DisplayNameFor(model => model.f_lname)
                        </dt>
                        <dd class="col-sm-10">
                            @Html.DisplayFor(model => model.f_lname)
                        </dd>
                        <dt class="col-sm-2">
                            @Html.DisplayNameFor(model => model.f_gender)
                        </dt>
                        <dd class="col-sm-10">
                            @Html.DisplayFor(model => model.f_gender)
                        </dd>
                        <dt class="col-sm-2">
                            @Html.DisplayNameFor(model => model.f_speach_date)
                        </dt>
                        <dd class="col-sm-10">
                            @Html.DisplayFor(model => model.f_speach_date)
                        </dd>
                        <dt class="col-sm-2">
                            @Html.DisplayNameFor(model => model.f_speach_time)
                        </dt>
                        <dd class="col-sm-10">
                            @Html.DisplayFor(model => model.f_speach_time)
                        </dd>
                        <dt class="col-sm-2">
                            @Html.DisplayNameFor(model => model.f_speach_venue)
                        </dt>
                        <dd class="col-sm-10">
                            @Html.DisplayFor(model => model.f_speach_venue)
                        </dd>
                    </dl>
                </div>
                <div class="col-4">
                    <div id="image-holder">
                        <img src="@ViewBag.ExistImage" class="img-thumbnail" height="350" width="285" asp-append-version="true" />
                    </div>
                </div>
            </div>
        </div>
        <div class="card-footer">
            <div style="float:right;">
                <form asp-action="Delete">
                    <button type="submit" class="btn btn-md btn-danger rounded-0"><i class="fa-solid fa-trash"></i> Delete</button>
                    <a href="@Url.Action("Edit", "Speakers", new { id = Model.f_uid })" class="btn btn-md btn-primary rounded-0"><i class="fa-solid fa-pen-to-square"></i> Edit</a>
                    <a href="@Url.Action("Index", "Speakers")" class="btn btn-md btn-primary rounded-0"><i class="fa-solid fa-backward"></i> Back to List</a>
                </form>
            </div>
        </div>
    </div>
</div>

Add repository services to the Program.cs

The object handles the task of connecting to the database and mapping Speaker objects to database records. The database context is registered with the Dependency Injection container in the Program.cs file.

builder.Services.AddTransient<ISpeaker, SpeakerRepository>();
builder.Services.AddTransient<IUnitOfWork, UnitOfWork>();

Add Connection String

The ASP.NET Core Configuration system reads the DefaultConnection key. For local development, it gets the connection string from the appsettings.json file.

{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=farhan1086\\SQLEXPRESS;Initial Catalog=Speaker-db;Integrated Security=True;MultipleActiveResultSets=True;Encrypt=False;TrustServerCertificate=False;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Run the Application

Select Ctrl+F5 to run the app without the debugger. Visual Studio runs the ASP.NET app and opens the default browser.

List

Speaker

Edit speaker information

Speaker details

Conclusion

The above article has taught us. How can we use Dapper with repository and UnitOfWork pattern? Dapper is Micro ORM, whereas Entity Framework is ORM. Dapper is faster than entity framework. I hope you enjoyed the article. Happy Coding.