Hej Wam. Trzeba trochę odkurzyć projekt, a z racji, że w chwili pisania tego artykułu wylądowałem na ławce, postanowiłem się podszkolić z wiedzy, która przyda się każdemu. Mi się przydała do mojego projektu.
Nie jest też to droga usługa, przynajmniej na potrzebę usług takich jak galeria na stronie.
W tej części nie tylko opowiem Wam na temat założenia Storage Account, ale także jak obsłużyć “Bloby”.
Przy okazji, to już 2 lata od regularnego pisania w ramach DSP. Dzisiaj nie dałbym radę pisać 2x tygodniowo wpisów jak wtedy.

Azure Storage

Zacznę od tego, że usługa Azure Storage, to zestaw przestrzeni dla plików (Blob i File Storage). Mała baza danych Table Storage, a także kolejki czyli Queue (długo nie wiedziałem jak to wymówić bez łamania języka) Storage.
Warto jeszcze dodać, że usługi te świetnie współgrają z usługami serverless od Azure.

Tworzenie usługi

Do rozpoczęcia pracy z BlobStorage potrzebujemy założyć Azure Storage. Jeśli nie posiadasz subskrypcji Azure, na visualstudio.net po założeniu konta i przejściu do my benefits/moje korzyści można dostać za darmo roczną.Wystarczy do sandboxowania, a nawet prostej strony.
Po zalogowaniu na portal Azure klikamy na Create a Resource a potem Storage Accounts i stwórzcie swoją usługę.

Blob Storage


Następnie po wejściu na usługę przechodzimy do Access Key i kopiujemy Connection strings z Key1, np. do naszego appsettings, zmiennych systemowych czy key vault.

No to zaczynamy kod

Czekaliście na to 🙂
Zróbmy to bardziej elegancko, bo dobre nawyki są docenione przez przyszłych lub obecnych pracodawców i kolegów z teamu.
Zacznijmy od interfejsu do naszego repo.

Interfejs i przygotowanie

public interface IBlobStorage
    {
        Task<BlobItem> Create(BlobItem item);
        Task<Result> Update(BlobItem item);
        Task<Result> Remove(string name, string folder); 
        Task<BlobItem> Get(string name, string folder);
        Task<IEnumerable<BlobItem>> GetList(string folder);
    }


Oraz Data Modelu, na którym oprzemy nasze działania

   public class BlobItem
    {
        public string Container { get; set; }
        public Uri Uri { get; set; }
        public Uri StorageUri { get; set; }
        public Stream Stream { get; set; }
        public string Name { get; set; }
    }

Zanim zaczniemy, należy pobrać z nugeta paczkę Microsoft.WindowsAzure.Storage.Blob

W konstruktorze tworzymy instancję Blob Client i Blob Accounts

private readonly CloudBlobClient BlobClient;
public BlobStorage(IConfiguration configuration)
        {
            var storageAccount = CloudStorageAccount.Parse(configuration[“BlobStorage”]);
            BlobClient = storageAccount.CreateCloudBlobClient();
        }

A następnie obiekt, który tworzy i zarządza naszą kolekcją, czyli kontener:

     private CloudBlobContainer GetContainer(string folder)
        {
            var container = BlobClient.GetContainerReference(folder);
            container.CreateIfNotExistsAsync().Wait();
            return container;
        }

Nazwa folderu, czy kontera określa naszą ścieżkę oraz pozwoli zrobić porządek w plikach oraz zarządzaniu uprawnieniami do nich. Ważne, by ustawić np. w panelu dostępność:

  • Private : tylko z poziomu kodu mamy dostęp.
  • Container: Użytkownik może widzieć wszystkie pliki w kolekcji
  • Blob: Użytkownik może widzieć plik, gdy wejdzie na bezpośredni link do niego
    Przy okazji kreator do tworzenia BlobItem
private static BlobItem GenerateBlob(CloudBlockBlob blob)
        {
            return new BlobItem
            {
                Container = blob.Container.Name,
                StorageUri = blob.StorageUri.PrimaryUri,
                Uri = blob.Uri,
                Name = blob.Name
            };
        }

Tworzenie CRUD

To teraz przejdźmy do stworzenia standardowych CRUD Metod dla naszego serwisu:

Create

public async Task<BlobItem> Create(BlobItem item)
        {
            var container = GetContainer(item.Container);
            var blob = container.GetBlockBlobReference(item.Name);
            await blob.UploadFromStreamAsync(item.Stream);
            item.Uri = blob.Uri.AbsoluteUri;            
            return item;
        }

Get

  public async Task<IEnumerable<BlobItem>> GetList(string folder)
        {
            var container = GetContainer(folder);
            var blob = await container.ListBlobsSegmentedAsync(null);
            return blob.Results.Select(p =>new BlobItem
            {
                StorageUri = p.StorageUri.PrimaryUri,
                Uri = p.Uri,
                Container = p.Container.Name
            });
        }
        public async Task<BlobItem> Get(string name, string folder)
        {
            var container = GetContainer(folder);
            var blob = container.GetBlockBlobReference(name);          

            return GenerateBlob(blob);
        }

Jeśli potrzeba, z BlockBlobReference możemy też pobrać Streama z danymi, które potem możemy zapisać do pliku czy pamięci. Na potrzeby swojej strony, potrzebowałem tylko url do pliku.

Update

 public async Task<Result> Update(BlobItem item)
        {          
            try
            {
                var container = GetContainer(item.Container);
                var blob = container.GetBlockBlobReference(item.Name);
                await blob.UploadFromStreamAsync(item.Stream);
                return Result.Success;
            }
            catch (Exception)
            {
                return Result.Failed;
            }
        }

Podobnie jak create, tylko uploadujemy plik do istniejącego juz bloba.

Delete

A teraz czyścimy

public async Task<Result> Remove(string name, string folder)
        {
            try
            {
                var container = GetContainer(folder);
                var blob = container.GetBlockBlobReference(name);
                await blob.DeleteAsync();
                return Result.Success;
            }
            catch (Exception)
            {
                return Result.Failed;
            }
        }    

Czyli szukamy naszego bloba i prosty delete 🙂

Podsumowanie

To by było tyle na ten wpis. Nauczyliście się tworzyć serwis w azure oraz obsługiwać go.
Zapraszam do regularnego czytania oraz opinii.

P.s Kod dostępny na GitHub – aluspl/AzureSamples: Azure samples, for upskill and blog i na GitHub – aluspl/LifeLike: CMS System based on net core and microservices