Azure Storage Serisi #7 – Azure Blob Storage ve Asp.NET Core İle Kullanımı

Merhaba,

Azure Storage Yazı Dizisinin bu yedinci makalesinde Azure Blob Storage’dan bahsedecek ve Asp.NET Core üzerinde nasıl kullanıldığını inceleyeceğiz.

Azure Blob Storage Nedir?

Azure Blob Storage, Microsoft’un bulut için dosya depolama servisidir. PDF, Image, MP3 vs. gibi farklı türdeki tüm dosyalar binary türde blob storage’a kaydedilebilir.

Azure Blob Storage Neden Tercih Etmeliyiz?

Azure Blob Storage’ı aşağıdaki durumlarda tercih edebilirsiniz.

  • Dosyaları doğrudan bulutta tutmak için,
  • Video ve ses streamleri oluşturabilmek için,
  • Verileri yedekleme ve olağanüstü durumlara istinaden geri yükleme, kurtarma yahut arşivlemek için,
  • Yapılan analiz çalışmalarında veri dopalama için…

Tüm bunlara istinaden Blob Storage, birden fazla instance olarak ayağa kaldırılan uygulamalarda dosyaları tek bir yerde depolamak ve böylece scale(ölçeklendirebilmek) edebilmek için kullanılmaktadır. Böylece dosyaların merkezi olmasını sağlamakta ve yönetilebilirlik seviyesi oldukça arttırılmaktadır.

Misal, Docker gibi sanallaştırma ortamlarında dosyaların tutulabilmesi için merkezi bir ortak nokta ayarlanabilmektedir. Bknz : .NET Core & Docker Yazı Dizisi Lakin Docker dışı durumlarda Blob storage hayat kurtaran bir çözüm sunmakta ve dosyaları ortak bir havuzda toplayabilmek için ekstradan kopyalama işlemlerine vs. gerek kalmaksızın daha efektif bir süreç sergilememizi sağlamaktadır.

Azure Blob Storage Kavramları Nelerdir?

Azure Storage Serisi #7 - Azure Blob Storage ve Asp.NET Core İle Kullanımı
Kavramsal açıdan Blob; jpg, png, avi, mp3 vs. gibi herhangi bir uzantılı dosyayı tarif eden bir terimdir. Azure tarafında dosya uzantısının hiçbir önemi yoktur. Azure sadece bynary datayı bilir ve bloblara kaydeder.

Azure Blob Storage; ‘Account’, ‘Container’ ve ‘Blob’ olmak üzere üç yapıdan meydana gelir.

‘Account’; Storage Account, datalar için Azure’da benzersiz bir isim alanı sağlamaktadır. Böylece depolanacak her nesnenin benzersiz hesap adını içeren bir adresi olacaktır.

Örnek bir account endpoint’i şöyle olmaktadır.
https://<account_name>.blob.core.windows.net

‘Container’; Blob’ları sarmalayacak klasörlerdir. Blob kaydetmeden önce container üretilmelidir. Bir account sınırsız sayıda container, bir container ise sınırsız sayıda blob barındırabilmektedir.

‘Blob’; Datanın yerleştirildiği yerdir. Yapısal olarak ‘Block Blobs’, ‘Append Blobs’ ve ‘Page Blobs’ olmak üzere üçe ayrılır.

  • Block Blobs
    Kaydedilecek dosyanın bir bütün olarak değilde blok blok parçalanarak kaydedilmesidir. Okunmak istendiği zaman bu parçalar eş zamanlı okunabilmekte ve böylece hız kazanılmaktadır.Her blok 100 MB‘a kadar data alır ve bir blob’da 50 bin kadar blok olabilir. Bu da tek bir blob’da 5 Terabayt’lık veriye karşılık gelmektedir.

    Eklenen dosya isimleri yahut içerikleri değiştirilmek istendiğinde değişiklik yapmaz, ilgili dosyanın üzerine tekrardan yazar. Değişiklik yapılabilir dosyaları tutmak için ‘Append Blobs’ tercih edilmelidir.

  • Append Blobs
    Üzerine ekleme yapılabilir dosyalar tutulur. Misal, loglama raporlarının kaydedildiği durumlara istinaden sürekli içeriği değişen .txt uzantılı dosyalar gibi…
  • Page Blobs
    Datalar pagelerde tutulmakta ve her bir page 512 byte‘tan meydana gelmektedir. Bu byte’lar da herhangi bir byte aralığında okuma ve yazma işlemi gerçekleştirilebilir. Normal senaryolara göre pekte uygun bir storage değildir.

Asp.NET Core İle Azure Blob Storage Kullanımı

Bir önceki Azure Table Storage ve Asp.NET Core İle Kullanımı başlıklı yazımızda, Table Storage’ı Asp.NET Core ile örneklendirebilmek için bir class library oluşturmuştuk. Benzer mantıkla burada da aynı şekilde bir geliştirmede bulunacağız.

  • Adım 1
    Bir class library uygulaması oluşturunuz ve uygulamaya Azure.Storage.Blobs kütüphanesini yükleyiniz.Azure Storage Serisi #7 - Azure Blob Storage ve Asp.NET Core İle Kullanımı
  • Adım 2
    ‘IBlobStorage’ isminde bir interface oluşturunuz ve içeriğini aşağıdaki gibi tasarlayınız.

        public interface IBlobStorage
        {
            Task UploadAsnyc(Stream fileStream, string name, string containerName);
            Task<Stream> DownloadAsync(string fileName, string containerName);
            Task DeleteAsync(string fileName, string containerName);
            Task SetLogAsync(string text, string fileName);
            Task<List<string>> GetLogAsync(string fileName);
            List<string> GetNames(string containerNames);
        }
    
  • Adım 3
    Ardından ‘IBlobStorage’ interface’ini uygulayan ‘BlobStorage’ isminde bir class oluşturunuz ve içeriğini aşağıdaki gibi inşa ediniz.

        public class BlobStorage : IBlobStorage
        {
            private readonly BlobServiceClient _blobServiceClient;
            BlobContainerClient _blobContainerClient;
            public BlobStorage()
            {
                _blobServiceClient = new BlobServiceClient("DefaultEndpointsProtocol=https;AccountName=gencayyildizstorage;AccountKey=9KxOlzewH/S3zOCRTDGesGO9HR+86GZC2Zsyk7Rk54Bs1BxP4MT7tTeHbNe/WljTCZQt7RfMr5UqVbKnuGTrtA==;EndpointSuffix=core.windows.net");
            }
            public async Task DeleteAsync(string fileName, string containerName)
            {
                _blobContainerClient = _blobServiceClient.GetBlobContainerClient(containerName);
                BlobClient blobClient = _blobContainerClient.GetBlobClient(fileName);
                await blobClient.DeleteAsync();
            }
            public async Task<Stream> DownloadAsync(string fileName, string containerName)
            {
                _blobContainerClient = _blobServiceClient.GetBlobContainerClient(containerName);
                BlobClient blobClient = _blobContainerClient.GetBlobClient(fileName);
                Response<BlobDownloadInfo> response = await blobClient.DownloadAsync();
                //response.Value -> Tüm bilgileri getirecektir.
                return response.Value.Content;
            }
            public async Task<List<string>> GetLogAsync(string fileName)
            {
                List<string> logs = new List<string>();
                _blobContainerClient = _blobServiceClient.GetBlobContainerClient("logs");//Log olacağı için ismi sabit.
                AppendBlobClient appendBlobClient = _blobContainerClient.GetAppendBlobClient(fileName); //Üzerine eklenebilir olacağından doayı AppendBlobClient seçildi.
                await appendBlobClient.CreateIfNotExistsAsync();
                Response<BlobDownloadInfo> response = await appendBlobClient.DownloadAsync();
                using StreamReader sr = new StreamReader(response.Value.Content);
                string line = string.Empty;
                while ((line = sr.ReadLine()) != null)
                    logs.Add(line);
                return logs;
            }
            public List<string> GetNames(string containerNames)
            {
                List<string> blobNames = new List<string>();
                _blobContainerClient = _blobServiceClient.GetBlobContainerClient(containerNames);
                return _blobContainerClient.GetBlobs().Select(b => b.Name).ToList();
            }
            public async Task SetLogAsync(string text, string fileName)
            {
                _blobContainerClient = _blobServiceClient.GetBlobContainerClient("logs");//Log olacağı için ismi sabit.
                await _blobContainerClient.CreateIfNotExistsAsync();
                AppendBlobClient appendBlobClient = _blobContainerClient.GetAppendBlobClient(fileName);
                await appendBlobClient.CreateIfNotExistsAsync();
                using MemoryStream ms = new MemoryStream();
                using StreamWriter sw = new StreamWriter(ms);
                await sw.WriteLineAsync($"{DateTime.Now} | {text}");
                await sw.FlushAsync();
                ms.Position = 0; //Stream 0. akıştan itibaren yazmaya başlayacak.
                await appendBlobClient.AppendBlockAsync(ms);
            }
            public async Task UploadAsnyc(Stream fileStream, string name, string containerName)
            {
                _blobContainerClient = _blobServiceClient.GetBlobContainerClient(containerName);
                //Container yoksa oluşturacak.
                await _blobContainerClient.CreateIfNotExistsAsync();
                //Artık url üzerinden erişime açıldı.
                await _blobContainerClient.SetAccessPolicyAsync(PublicAccessType.BlobContainer);
    
                BlobClient blobClient = _blobContainerClient.GetBlobClient(name);
                await blobClient.UploadAsync(fileStream);
            }
        }
    

    Yukarıdaki kod bloğunda bir izah yapmamız gerekecekse eğer o da ilgili storage’ın çalışabilmesi için 6. satırda connection string girilmesi gerekliliğidir. Geri kalan tüm izahatler kodun içerisinde açıklama satırı olarak yapılmıştır.

  • Adım 4
    Bir Asp.NET Core uygulaması oluşturunuz ve ilk olarak ilgili class library’i projeye referans olarak ekleyiniz ve ardından yukarıda oluşturulan yapılanmaları uygulamaya servis olarak dahil ediniz.

        public class Startup
        {
            .
            .
            .
            public void ConfigureServices(IServiceCollection services)
            {
                .
                .
                .
                services.AddSingleton<IBlobStorage, BlobStorage>();
                .
                .
                .
            }
            .
            .
            .
        }
    
  • Adım 5
    Ardından aşağıdaki gibi bir controller sınıfı oluşturup, geliştiriniz.

        [Route("api/[controller]")]
        [ApiController]
        public class FileController : ControllerBase
        {
            readonly IBlobStorage _blobStorage;
            public FileController(IBlobStorage blobStorage)
            {
                _blobStorage = blobStorage;
            }
            [HttpGet("[action]")]
            public async Task<IActionResult> UploadAsync(string fileName)
            {
                try
                {
                    FileStream fileStream = new FileStream(fileName, FileMode.OpenOrCreate);
                    await _blobStorage.UploadAsnyc(fileStream, Path.GetFileName(fileName), "files");
                    return Ok(true);
                }
                catch
                {
                    return Ok("Beklenmeyen bir hatayla karşılaşıldı.");
                }
            }
            [HttpGet("[action]")]
            public async Task<IActionResult> DownloadAsync(string fileName, string containerName)
            {
                try
                {
                    Stream stream = await _blobStorage.DownloadAsync(fileName, containerName);
                    //return File(stream, "application/octet-stream", fileName);
                    return File(stream, "application/text", fileName);
                }
                catch
                {
                    return Ok("Beklenmeyen bir hatayla karşılaşıldı.");
                }
            }
            [HttpGet("[action]")]
            public async Task<IActionResult> DeleteAsync(string fileName, string containerName)
            {
                try
                {
                    await _blobStorage.DeleteAsync(fileName, containerName);
                    return Ok(true);
                }
                catch
                {
                    return Ok(false);
                }
            }
            [HttpGet("[action]")]
            public IActionResult GetNames(string containerName)
            {
                return Ok(_blobStorage.GetNames(containerName));
            }
            [HttpGet("[action]")]
            public async Task<IActionResult> GetLogAsync(string fileName)
            {
                return Ok(await _blobStorage.GetLogAsync(fileName));
            }
            [HttpGet("[action]")]
            public async Task<IActionResult> SetLogAsync(string text, string fileName)
            {
                try
                {
                    await _blobStorage.SetLogAsync(text, fileName);
                    return Ok(true);
                }
                catch(Exception ex)
                {
                    
                    return Ok("Beklenmeyen bir hatayla karşılaşıldı.");
                }
            }
        }
    

Tüm bu işlemlerden sonra artık ilgili uygulama derlenip çalıştırılmalı ve istek gönderilmelidir.

Test Edelim

Upload Download
Azure Storage Serisi #7 - Azure Blob Storage ve Asp.NET Core İle Kullanımı Azure Storage Serisi #7 - Azure Blob Storage ve Asp.NET Core İle Kullanımı
Getnames Delete
Azure Storage Serisi #7 - Azure Blob Storage ve Asp.NET Core İle Kullanımı Azure Storage Serisi #7 - Azure Blob Storage ve Asp.NET Core İle Kullanımı
Setlog Getlog
Azure Storage Serisi #7 - Azure Blob Storage ve Asp.NET Core İle Kullanımı Azure Storage Serisi #7 - Azure Blob Storage ve Asp.NET Core İle Kullanımı

Blob URL Üzerinden Dosyalara Erişim Nasıl Sağlanır?

Azure Blob Storage’da depolanan dosyalara url üzerinden erişebilmek için account endpoint’ini aşağıdaki gibi kullanabilirsiniz;
https://<account_name>.blob.core.windows.net/<container_name>/<file_name>

Tabi burada container seviyesinde erişime izin verilmesi gerekmektedir. Bunun için ‘Containers’ ekranına gelip ilgili container’ı seçtikten sonra ‘Change access level’ sekmesine tıklayınız.
Azure Storage Serisi #7 - Azure Blob Storage ve Asp.NET Core İle Kullanımı
Ardından ‘Public access level’ alanından ‘Container(anonymous read access for containers and blobs)’ seçeneğini işaretleyerek ‘Ok’ butonuna tıklamanız yeterlidir.
Azure Storage Serisi #7 - Azure Blob Storage ve Asp.NET Core İle Kullanımı

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Not : Örnek projeyi indirebilmek için buraya tıklayınız. (Bir önceki Azure Table Storage başlıklı makalede irdelediğimiz örnek proje üzerinden geliştirme yapılmıştır.)

Bunlar da hoşunuza gidebilir...

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*