Search code examples
sqlasp.net-core

How to delete image from folder where record is deleted from database


I'm saving data into a database and uploading image to its destination folder and this works perfectly. But I'm unable to delete the image. My code can only delete data from the database, but not the image file from its folder.

I want my code to both delete data from the database and the image file from its folder.

[HttpDelete("{id}")]
public void Delete(int id)
{
    var image = _context.Employee.Where(x => x.EmployeeId.Equals(id)).FirstOrDefault();

    Employee _book = _context.Employee.Where(x => x.EmployeeId.Equals(id)).FirstOrDefault();

    var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/Photos", image.Passport);

    if (System.IO.File.Exists(filePath))
    {
        System.IO.File.Delete(filePath);
    }            

    _context.Employee.Remove(image);
    _context.Employee.Remove(_book);

    _context.SaveChanges();
}

Solution

  • I'm saving data into a database and uploading image to its destination folder and this works perfectly. But I'm unable to delete the image. My code can only delete data from the database, but not the image file from its folder.

    Well, I have investigated with your delete code and it seems that your shared code is correct as producing the expected result and can delete the file/Image from both location. As you can see as following:

    However, you might get the unexpected result due to couple of reasons.

    First, as per your shared code, its very crucial how you are saving the image, does it contains full path in the database or only the image name. So the main thing is the way you have saved your image in database and the wwwroot directory, the same way you have to extarct the path.

    If that doesn't match your databse file might be deleted but as the location path incorrect so the image still may exist in wwwroot directory.

    So, you can refer to below steps...

    Saving Image Location In Database and wwwroot directory:

    In order to simulate your scenario, I have used following model:

    public class Employee
    {
        [Key]
        public int EmployeeId { get; set; }
        public string? Name { get; set; }
        public string? Gender { get; set; }
        public DateTime DOB { get; set; }
        public string? ImageLocation { get; set; }
    } 
    

    Controller:

    public class EmployeeController : Controller
    {
        private readonly ApplicationDbContext _context;
        private readonly IWebHostEnvironment _environment;
    
    
        public EmployeeController(IWebHostEnvironment environment, ApplicationDbContext context)
        {
            _environment = environment;
            _context = context;
        }
    
       
    
        public IActionResult Create()
        {
            return View();
        }
    
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> CreateEmployee(Employee model, IFormFile photo)
        {
    
            if (photo == null || photo.Length == 0)
            {
                return Content("File not selected");
            }
            var path = Path.Combine(_environment.WebRootPath, "Photos", photo.FileName);
    
    
            using (FileStream stream = new FileStream(path, FileMode.Create))
            {
                await photo.CopyToAsync(stream);
                stream.Close();
            }
    
            model!.ImageName = photo.FileName;
    
            if (model == null)
            {
                return Content("Invalid Submission!");
            }
            var emp = new Employee
            {
                Name = model.Name,
                Gender = model.Gender,
                DOB = model.DOB,
                ImageName = model.ImageName,
                ImageLocation = path,
            };
    
            _context.Add(emp);
            await _context.SaveChangesAsync();
    
    
            return RedirectToAction("Index");
    
    
        }
        
    
    }
    

    My wwwroot Directory:

    enter image description here

    So, while I am saving the image location in database I am saving the full path/locaiton by using IWebHostEnvironment

       var path = Path.Combine(_environment.WebRootPath, "Photos", photo.FileName);
    

    So the location got saved in database in following way:

    enter image description here

    Delete Controller Action:

    In case of removing image from both database and the wwwroot diorectory, first of we should fetch the object by its ID, and then, we should check the directory location/path.

    Although, you code is correct but I have slidely modified that as following:

    public async Task<IActionResult> DeleteConfirmed(int Id)
    {
        var employee = await _context.Employees.FindAsync(Id);
        if (employee == null)
        {
            return NotFound();
        }
    
        var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/Photos", employee.ImageLocation!);
    
        if (System.IO.File.Exists(filePath))
        {
            System.IO.File.Delete(filePath);
        }
    
        _context.Employees.Remove(employee);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    

    As you can see, I am fetching the image location accordingly and it has deleted the image from the location as expected.

    enter image description here

    In addition, you can do another alternative way, if you have full path in your database, so that directly remove it within searching by the directory, instead, you can directly could remove from location as well. Let's hava a look at the below action:

    public async Task<IActionResult> DeleteConfirmed(int Id)
     {
         var employee = await _context.Employees.FindAsync(Id);
         if (employee == null)
         {
             return NotFound();
         }
         if (!string.IsNullOrEmpty(employee.ImageLocation) && System.IO.File.Exists(employee.ImageLocation))
         {
             System.IO.File.Delete(employee.ImageLocation);
         }
    
         _context.Employees.Remove(employee);
         await _context.SaveChangesAsync();
         return RedirectToAction(nameof(Index));
     }
    

    Ouput:

    enter image description here

    Note: Make sure, you have UseStaticFiles middleware reference added with your program.cs file. Please refer to this official document beside.