Posted in

ASP.NET Core ile Dosya Yükleme, Görsel Yeniden Boyutlandırma ve Dosya Doğrulama

Modern web uygulamalarında dosya yükleme, kullanıcıların görseller, belgeler veya tablolar gibi farklı dosya türlerini yüklemelerine olanak tanır. Bu blog yazısında, ASP.NET Core MVC uygulamasında dosya yükleme işlemi gerçekleştireceğiz. Ayrıca, görselleri yeniden boyutlandırma, dosya türü doğrulama ve dosya adlarının güvenli bir şekilde işlenmesi gibi konuları ele alacağız.

Gereksinimler

Kodumuza başlamadan önce, görsel işleme görevlerini kolayca gerçekleştirebilmek için SixLabors.ImageSharp paketini yüklememiz gerekecek. Bu kütüphane, ASP.NET Core ile entegre bir şekilde görselleri işlemek için mükemmel bir seçenektir.

Aşağıdaki komutu çalıştırarak ImageSharp paketini yükleyebilirsiniz:

dotnet add package SixLabors.ImageSharp --version 3.1.5

Bu komut, SixLabors.ImageSharp kütüphanesinin 3.1.5 sürümünü yükleyecektir. Bu sürüm, görselleri yeniden boyutlandırma ve işlemeye yönelik ihtiyaçlarımızı karşılayacaktır.

Kod İncelemesi

1. Dosya Yükleme için Controller Oluşturma

Aşağıdaki kodda, HomeController isminde bir controller oluşturduk. Bu controller, dosya yüklemeyi işler ve yüklenen dosyaların güvenliğini sağlamak için çeşitli doğrulamalar yapar. Controller, iki ana metot içeriyor:

  • Index(): Kullanıcılara dosya yükleyebilecekleri bir HTML formu sunar.
  • UploadFile(): Dosya yükleme işlemini yönetir, dosya türünü ve boyutunu doğrular ve dosyayı sunucuya kaydeder.
using Microsoft.AspNetCore.Mvc;

namespace FileUpload.Controllers
{
    public class HomeController : Controller
    {
        // GET: /Home/Index
        [HttpGet]
        [Route("/")]
        public IActionResult Index()
        {
            // HTML formunu döndür
            return Content(@"
                <html>
                <head><meta charset=""utf-8""></head>
                <body>
                    <h2>Dosya Yükleyin</h2>
                    <form action=""/Home/UploadFile"" method=""post"" enctype=""multipart/form-data"">
                        <label for=""file"">Dosya Seçin:</label>
                        <input type=""file"" name=""file"" required />
                        <button type=""submit"">Yükle</button>
                    </form>
                </body>
                </html>", "text/html");
        }

        [HttpPost]
        public async Task<IActionResult> UploadFile(IFormFile file)
        {
            var isUploaded = await FileUploadHelper.UploadFileAsync(file, file.FileName, Path.Combine("wwwroot/uploads"));

            if (Convert.ToBoolean(isUploaded["status"]))
            {
                return Ok(isUploaded);
            }
            else
            {
                return BadRequest("Dosya yükleme başarısız oldu. Lütfen dosya türünü ve boyutunu kontrol edip tekrar deneyin.");
            }
        }
    }
}

2. Dosya Yükleme ve İşleme Yardımcı Sınıfı

Dosya yükleme ve işleme işlemlerini yöneten bir yardımcı sınıf (FileUploadHelper) oluşturduk. Bu sınıf, dosya adlarını güvenli hale getirir, dosya türlerini doğrular ve görsellerin boyutunu yeniden düzenler.

İşte FileUploadHelper sınıfının kodu:

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using System.Text.RegularExpressions;

public class FileUploadHelper
{
    public static async Task<Dictionary<string, object>> UploadFileAsync(IFormFile file, string fileName, string uploadPath, bool deleteIfExists = false)
    {
        var result = new Dictionary<string, object>
        {
            { "status", false },
            { "fileName", "" }
        };

        if (file == null || file.Length == 0)
        {
            return result; // Dosya boşsa veya yüklenmediyse false döner
        }

        // Türkçe karakterleri güvenli hale getirmek için dosya adını temizleyin
        fileName = MakeFileNameSafe(fileName);

        // Geçerli dosya türlerini kontrol et (Updated file types)
        var allowedTypes = new[] {
            "image/jpeg", "image/jpg", "image/png", "application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", // Word formats
            "application/vnd.ms-excel", "application/vnd.openxmlformats.officedocument.spreadsheetml.sheet", // Excel formats
            "image/svg+xml", "application/vnd.oasis.opendocument.text", "application/vnd.oasis.opendocument.spreadsheet", // ODT, ODS, SVG
            "image/webp"
        };

        if (!allowedTypes.Contains(file.ContentType))
        {
            return result; // Desteklenmeyen dosya türü
        }

        // Dosya boyutunu kontrol et (5 MB sınırı)
        const long maxFileSize = 5 * 1024 * 1024;
        if (file.Length > maxFileSize)
        {
            return result; // Dosya çok büyükse
        }

        try
        {
            var filePath = Path.Combine(uploadPath, fileName);

            // Check if the file already exists
            if (File.Exists(filePath))
            {
                if (deleteIfExists)
                {
                    // If deleteIfExists is true, delete the existing file
                    File.Delete(filePath);
                }
                else
                {
                    // If file exists and deleteIfExists is false, generate a unique name
                    fileName = GenerateUniqueFileName(uploadPath, fileName);
                    filePath = Path.Combine(uploadPath, fileName);
                }
            }

            // If the file is an image, handle it separately
            if (file.ContentType.StartsWith("image"))
            {
                using var image = await Image.LoadAsync(file.OpenReadStream());

                // Resize the image to a maximum of 800x800 pixels
                int maxWidth = 800;
                int maxHeight = 800;
                image.Mutate(x => x.Resize(new ResizeOptions
                {
                    Mode = ResizeMode.Max,
                    Size = new Size(maxWidth, maxHeight)
                }));

                // Save the resized image to the specified file path
                await image.SaveAsync(filePath);
            }
            else
            {
                // If the file is not an image, save it directly to the file system
                using var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 4096, FileOptions.Asynchronous);
                await file.CopyToAsync(stream);
            }

            // If upload is successful, update the result dictionary
            result["status"] = true;
            result["fileName"] = fileName; // Set the uploaded file name
        }
        catch (Exception)
        {
            return result; // Hata varsa status false döner
        }

        return result;
    }

    private static string MakeFileNameSafe(string fileName)
    {
        // Güvenlik amacıyla geçersiz karakterleri temizlerken Türkçe karakterleri koruyun
        fileName = Regex.Replace(fileName, @"[<>:""/\\|?*]", "");  // Yasaklı karakterleri kaldır

        // Boşlukları ve diğer özel karakterleri "-" ile değiştirin, Türkçe karakterleri olduğu gibi bırakın
        return Regex.Replace(fileName, @"\s+", "-");
    }

    private static string GenerateUniqueFileName(string uploadPath, string fileName)
    {
        var fileExtension = Path.GetExtension(fileName);
        var baseFileName = Path.GetFileNameWithoutExtension(fileName);

        // Create a unique name by appending a timestamp to the original file name
        var uniqueFileName = $"{baseFileName}_{DateTime.UtcNow.Ticks}{fileExtension}";
        var uniqueFilePath = Path.Combine(uploadPath, uniqueFileName);

        // Ensure that the generated unique name doesn't collide with an existing file
        while (File.Exists(uniqueFilePath))
        {
            uniqueFileName = $"{baseFileName}_{DateTime.UtcNow.Ticks}{fileExtension}";
            uniqueFilePath = Path.Combine(uploadPath, uniqueFileName);
        }

        return uniqueFileName;
    }
}

TAM KOD

HomeController.cs

using Microsoft.AspNetCore.Mvc;
namespace FileUpload.Controllers
{
    public class HomeController : Controller
    {
        // GET: /Home/Index
        [HttpGet]
        [Route("/")]
        public IActionResult Index()
        {
            // HTML formunu döndür
            return Content(@"
                <html>
                <head><meta charset=""utf-8""></head>
                <body>
                    <h2>Upload a File</h2>
                    <form action=""/Home/UploadFile"" method=""post"" enctype=""multipart/form-data"">
                        <label for=""file"">Choose file:</label>
                        <input type=""file"" name=""file"" required />
                        <button type=""submit"">Upload</button>
                    </form>
                </body>
                </html>", "text/html");
        }

        [HttpPost]
        public async Task<IActionResult> UploadFile(IFormFile file)
        {
            var isUploaded = await FileUploadHelper.UploadFileAsync(file, file.FileName, Path.Combine("wwwroot/uploads"));

            if (Convert.ToBoolean(isUploaded["status"]))
            {
                return Ok(isUploaded);
            }
            else
            {
                return BadRequest("File upload failed. Please check file type, size, and try again.");
            }
        }
    }
}

Models/FileUploads.cs

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using System.Text.RegularExpressions;

public class FileUploadHelper
{
    public static async Task<Dictionary<string, object>> UploadFileAsync(IFormFile file, string fileName, string uploadPath, bool deleteIfExists = false)
    {
        var result = new Dictionary<string, object>
        {
            { "status", false },
            { "fileName", "" }
        };

        if (file == null || file.Length == 0)
        {
            return result; // Dosya boşsa veya yüklenmediyse false döner
        }

        // Türkçe karakterleri güvenli hale getirmek için dosya adını temizleyin
        fileName = MakeFileNameSafe(fileName);

        // Geçerli dosya türlerini kontrol et (Updated file types)
        var allowedTypes = new[] {
            "image/jpeg", "image/jpg", "image/png", "application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", // Word formats
            "application/vnd.ms-excel", "application/vnd.openxmlformats.officedocument.spreadsheetml.sheet", // Excel formats
            "image/svg+xml", "application/vnd.oasis.opendocument.text", "application/vnd.oasis.opendocument.spreadsheet", // ODT, ODS, SVG
            "image/webp"
        };

        if (!allowedTypes.Contains(file.ContentType))
        {
            return result; // Desteklenmeyen dosya türü
        }

        // Dosya boyutunu kontrol et (5 MB sınırı)
        const long maxFileSize = 5 * 1024 * 1024;
        if (file.Length > maxFileSize)
        {
            return result; // Dosya çok büyükse
        }

        try
        {
            var filePath = Path.Combine(uploadPath, fileName);

            // Check if the file already exists
            if (File.Exists(filePath))
            {
                if (deleteIfExists)
                {
                    // If deleteIfExists is true, delete the existing file
                    File.Delete(filePath);
                }
                else
                {
                    // If file exists and deleteIfExists is false, generate a unique name
                    fileName = GenerateUniqueFileName(uploadPath, fileName);
                    filePath = Path.Combine(uploadPath, fileName);
                }
            }

            // If the file is an image, handle it separately
            if (file.ContentType.StartsWith("image"))
            {
                using var image = await Image.LoadAsync(file.OpenReadStream());

                // Resize the image to a maximum of 800x800 pixels
                int maxWidth = 800;
                int maxHeight = 800;
                image.Mutate(x => x.Resize(new ResizeOptions
                {
                    Mode = ResizeMode.Max,
                    Size = new Size(maxWidth, maxHeight)
                }));

                // Save the resized image to the specified file path
                await image.SaveAsync(filePath);
            }
            else
            {
                // If the file is not an image, save it directly to the file system
                using var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 4096, FileOptions.Asynchronous);
                await file.CopyToAsync(stream);
            }

            // If upload is successful, update the result dictionary
            result["status"] = true;
            result["fileName"] = fileName; // Set the uploaded file name
        }
        catch (Exception)
        {
            return result; // Hata varsa status false döner
        }

        return result;
    }

    private static string MakeFileNameSafe(string fileName)
    {
        // Güvenlik amacıyla geçersiz karakterleri temizlerken Türkçe karakterleri koruyun
        fileName = Regex.Replace(fileName, @"[<>:""/\\|?*]", "");  // Yasaklı karakterleri kaldır

        // Boşlukları ve diğer özel karakterleri "-" ile değiştirin, Türkçe karakterleri olduğu gibi bırakın
        return Regex.Replace(fileName, @"\s+", "-");
    }

    private static string GenerateUniqueFileName(string uploadPath, string fileName)
    {
        var fileExtension = Path.GetExtension(fileName);
        var baseFileName = Path.GetFileNameWithoutExtension(fileName);

        // Create a unique name by appending a timestamp to the original file name
        var uniqueFileName = $"{baseFileName}_{DateTime.UtcNow.Ticks}{fileExtension}";
        var uniqueFilePath = Path.Combine(uploadPath, uniqueFileName);

        // Ensure that the generated unique name doesn't collide with an existing file
        while (File.Exists(uniqueFilePath))
        {
            uniqueFileName = $"{baseFileName}_{DateTime.UtcNow.Ticks}{fileExtension}";
            uniqueFilePath = Path.Combine(uploadPath, uniqueFileName);
        }

        return uniqueFileName;
    }
}

Sonuç

Bu basit uygulama sayesinde, ASP.NET Core MVC ile dosya yükleme işlemi gerçekleştirebilir, yüklenen dosyaları güvenli bir şekilde sunucuda depolayabilir ve görsellerin boyutunu istediğiniz şekilde yeniden boyutlandırabilirsiniz. Ayrıca, dosya türü ve boyutu doğrulaması ile sadece geçerli dosyaların yüklenmesini sağlarsınız.

Bu blogda kullanılan SixLabors.ImageSharp kütüphanesini yüklemek için:

dotnet add package SixLabors.ImageSharp --version 3.1.5

Komutunu kullanarak görsel işleme işlemlerini kolayca gerçekleştirebilirsiniz.

Umarım bu yazı, ASP.NET Core’da dosya yükleme ve güvenli dosya işleme konularında size yardımcı olmuştur!

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir