CoreLib Storage Design Reference

Keyworks: Storage Azure Blob Table File

Introdução

O serviço de storage permite armazenar ficheiros e dados não estruturados em repositórios na cloud como o Azure Blob Storage ou o Azure Table Storage.

Esses serviços de storage são úteis para gerir determinados dados das aplicações, porque são mais económicos em determinados cenários de utilização e porque foram concebidos para esses cenários e para a integração com aplicações Web.

Conceitos

Azure Blob Storage

"Azure Blob storage is a service that stores unstructured data in the cloud as objects/blobs. Blob storage can store any type of text or binary data, such as a document, media file, or application installer. Blob storage is also referred to as object storage."

Azure Table Storage

"Azure Table storage is a service that stores structured NoSQL data in the cloud, providing a key/attribute store with a schemaless design. Because Table storage is schemaless, it's easy to adapt your data as the needs of your application evolve. Access to Table storage data is fast and cost-effective for many types of applications, and is typically lower in cost than traditional SQL for similar volumes of data."

Pressupostos

  • Na cloud o armazenamento de ficheiros em base de dados torna-se uma má prática porque faz crescer as bases de dados em demasia e isso impacta os custos. Por essa razão é preferível armazenar os ficheiros em disco.
  • As plataformas cloud disponibilizam serviços especificamente para este efeito que tornam possível a sua utilização abstraindo o sistema de ficheiros, através de uma API mais adaptada à construção de aplicações Web.
  • Os repositórios de dados não estruturados (NoSql) são particularmente úteis para armazenar estruturas de dados que se espera que mudem de estrutura à medida que a respetiva aplicação evolui, simplificando os cenários de upgrade típicos em bases de dados SQL. É principalmente por essa razão que a sua utilização em aplicações Web tem vindo a aumentar.

Desenho

Storage Service Factory

Os vários serviços de storage disponilizados pela CoreLib podem ser acedidos a partir de uma factory definida pelo tipo Primavera.Core.Storage.StorageServiceFactory (em Primavera.CoreLib.dll).

Atualmente estão disponíveis dois serviços:

  • File Storage: desenhando especificamente para armazenamento de ficheiros.
  • Table Storage: desenhado para armazenamento de dados em tabelas NoSql com uma estrutura chave/atríbuto.

A implementação concreta de cada um destes serviços é definida por configuração. As instâncias de cada serviço são disponibilizadas pela factory como nos exemplos seguintes:

IFileStorageService service = StorageServiceFactory.GetFileStorageService();

FileStorageServiceConfiguration configuration = FileStorageServiceConfiguration
    .Default()
    .WithImplementation<LocalFileStorageService>();

IFileStorageService service = StorageServiceFactory.GetFileStorageService(configuration);
ITableStorageService service = StorageServiceFactory.GetTableStorageService();

TableStorageServiceConfiguration configuration = TableStorageServiceConfiguration
    .FromConfiguration()
    .WithSetting(StorageSettingsBuilder.ServerConnectionTimeout, TimeSpan.FromSeconds(2))
    .WithSetting(StorageSettingsBuilder.UseRootTracing, true);

ITableStorageService service = StorageServiceFactory.GetTableStorageService(configuration)

File Storage

O serviço IFileStorageService (Primavera.Core.Storage.Files.IFileStorageService em Primavera.CoreLib.dll) permite armazenar ficheiros num respositório configurável (em disco ou usando Azure Blob Storage).

Arquitetura

O serviço permite gerir dois tipos de repositórios lógicos:

  • Públicos: que armazenam ficheiros acessíveis publicamente.
  • Privados: que armazenam ficheiros privados a determinado contexto (por exemplo, para determinada subscrição da aplicação).

Cada repositório é conhecido como um container que é identificado por um nome distinto. Também é possível criar o container para uma determinada conta e subscrição, sendo então gerado um nome único a partir desses dois identificadores.

CoreLib Storage

O repositório concreto será então definido por configuração.

Na versão atual da CoreLib estão disponíveis 2 implementações do serviço:

  • Primavera.Core.Storage.Files.LocalFileStorageService - armazena os ficheiros em disco (local).
  • Primavera.Core.Storage.Azure.Files.AzureFileStorageService - armazena os ficheiros na Azure Blob Storage.

API

A API permite aceder a um container público ou privado. Note-se que estes métodos devolvem uma referência para o container que pode não existir ainda fisicamente.

IFileStorageService service = StorageServiceFactory.GetFileStorageService();

IFileContainerReference publicContainer = service.GetPublicContainer("mycontainer");

IFileContainerReference privateContainer = service.GetPublicContainer("account", "subscription");

O interface Primavera.Core.Storage.Files.IFileContainerReference permite depois realizar todas as operações sobre o container ou sobre os ficheiros nesse container:

  • Create() - cria o container (lança um erro se o container já existir).
  • CreateIfNotExists() - cria o container se ainda não existir.
  • Delete() - apaga o container (lança um erro se o container não existir).
  • DeleteIfExists() - apaga o container se existir.
  • Exists() - verifica se o container existe.
  • UploadFile(fileName, stream) - faz o upload de um ficheiro para o container.
  • DownloadFile(fileName) - faz o download do ficheiro indicado.
  • FileExists(fileName) - verifica se o ficheiro existe.
  • RenameFile(originalFileName, destinationFileName) - renomeia um ficheiro.
  • DeleteFile(fileName) - elimina um ficheiro (lança um erro se o ficheiro não existir).
  • DeleteFileIfExists(fileName) - elimina o ficheiro se este existir.
  • GetFileUri(fileName) - devolve o URL para aceder ao ficheiro no container.

Esta API disponibiliza sempre a versão síncrona e a versão assíncrona de cada método (exemplo: Create e CreateAsync).

Configuração

A configuração do serviço pode ser feita no ficheiro de configuração da aplicação usando o tipo Primavera.Core.Storage.Files.FileStorageServiceConfigurationSection e/ou em runtime usando o tipo Primavera.Core.Storage.Files.FileStorageServiceConfiguration que disponibiliza uma API fluente.

Exemplo de configuração no web.config:

<configSections>
    <section name="fileStorageServiceConfiguration" type="Primavera.Core.Storage.Files.FileStorageServiceConfigurationSection, Primavera.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=33086db60a481256" />
</configSections>
<fileStorageServiceConfiguration>
    <elements>
        <add name="default">
            <settings>
                <add key="StorageConnectionString" value="DefaultEndpointsProtocol=https;AccountName=intdevunittesting;AccountKey=mLiNPWgCnVHFW74eFaC4XDiDki5LMPA9deKydHOsOhwx7xkgl0lwEYMcd/k6daJwSdTYpcTszE03lGXJ0ZGDrA==;EndpointSuffix=core.windows.net" />
                <add key="ServerConnectionTimeout" value="00:00:04" />
                <add key="RequireEncryption" value="false" />
                <add key="MaximumExecutionTime" value="00:02:00" />
                <add key="RetryPolicy" value="Linear" />
                <add key="RetryPolicyMaximumAttempts" value="4" />
                <add key="RetryPolicyBackoffTime" value="00:00:03" />
            </settings>
        </add>
    </elements>
</fileStorageServiceConfiguration>

Exemplo de configuração em runtime:

FileStorageServiceConfiguration configuration = FileStorageServiceConfiguration
    .Default()
    .WithImplementation<LocalFileStorageService>();

IFileStorageService service = StorageServiceFactory.GetFileStorageService(configuration);

Implementação de um Provider

Pode-se implementar novos providers para suportar outros repositórios. Para o efeito bastará que a respetiva classe implemente o interface 'Primavera.Core.Storage.Files.IFileStorageService'.

Exemplo:

internal sealed partial class LocalFileStorageService : IFileStorageService

Table Storage

O serviço ITableStorageService (Primavera.Core.Storage.Tables.ITableStorageService em Primavera.CoreLib.dll) permite armazenar dados em tabelas NoSql num respositório configurável (exemplo: usando Azure Table Storage).

Arquitetura

O serviço permite gerir uma tabela na storage.

CoreLib Storage

O repositório concreto das tabelas será então definido por configuração.

Na versão atual da CoreLib estão disponíveis 2 implementações do serviço:

  • Primavera.Core.Storage.Tables.InMemoryTableStorageService - armazena as tabelas em memória (num dicionário).
  • Primavera.Core.Storage.Azure.Tables.AzureTableStorageService - armazena os ficheiros na Azure Table Storage.

API

A API permite aceder a uma tabela. Note-se que estes métodos devolvem uma referência para a tabela que pode não existir ainda fisicamente.

ITableStorageService service = StorageServiceFactory.GetTableStorageService();
ITableReference table = service.GetTable("mytable");

O interface Primavera.Core.Storage.Tables.ITableReferenced permite depois realizar todas as operações sobre a tabela ou sobre os dados nessa tabela:

  • Create() - cria a tabela (lança um erro se a tabela já existir).
  • CreateIfNotExists() - cria tabela se ainda não existir.
  • Delete() - apaga a tabela (lança um erro se a tabela não existir).
  • DeleteIfExists() - apaga a tabela se existir.
  • Exists() - verifica se a tabela existe.
  • InsertRecord(record) - insere o registo especificado (lança um erro se já existir um registo com as mesmas chaves).
  • InsertRecords(records) - insere todos os registos especificados (lança um erro se algum dos registos já existir).
  • InsertOrReplaceRecord() - insere o registo especificado ou substitui-o se já existir.
  • InsertOrReplaceRecords(record) - insere todos os registos especificados ou substitui os que já existirem.
  • DeleteRecord(record) - elimina o registo especificado.
  • ReplaceRecord(record) - substitui o registo especificado.
  • RetrieveRecord(key1, key2)- devolve o registo que tem as chaves especificadas.
  • TryRetrieveRecord(key1, key2, out result) - devolve o registo que tem as chaves especificadas.
  • RetrieveRecords() - devolve todos os registos da tabela.

Esta API disponibiliza sempre a versão síncrona e a versão assíncrona de cada método (exemplo: Create e CreateAsync).

Configuração

A configuração do serviço pode ser feita no ficheiro de configuração da aplicação usando o tipo Primavera.Core.Storage.Tables.TableStorageServiceConfigurationSection e/ou em runtime usando o tipo Primavera.Core.Storage.Tables.TableStorageServiceConfiguration que disponibiliza uma API fluente.

Exemplo de configuração no web.config:

<configSections>
    <section name="tableStorageServiceConfiguration" type="Primavera.Core.Storage.Tables.TableStorageServiceConfigurationSection, Primavera.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=33086db60a481256" />
</configSections>
<tableStorageServiceConfiguration>
    <elements>
        <add name="release" type="Primavera.Core.Storage.Tables.InMemoryTableStorageService, Primavera.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=33086db60a481256" />
        <add name="debug">
            <settings>
                <add key="StorageConnectionString" value="DefaultEndpointsProtocol=https;AccountName=intdevunittesting;AccountKey=mLiNPWgCnVHFW74eFaC4XDiDki5LMPA9deKydHOsOhwx7xkgl0lwEYMcd/k6daJwSdTYpcTszE03lGXJ0ZGDrA==;EndpointSuffix=core.windows.net" />
            </settings>
        </add>
    </elements>
</tableStorageServiceConfiguration>

Exemplo de configuração em runtime:

TableStorageServiceConfiguration configuration = TableStorageServiceConfiguration
    .FromConfiguration()
    .WithSetting(StorageSettingsBuilder.ServerConnectionTimeout, TimeSpan.FromSeconds(2))
    .WithSetting(StorageSettingsBuilder.UseRootTracing, true);

ITableStorageService service = StorageServiceFactory.GetTableStorageService(configuration)

Implementação de um Provider

Pode-se implementar novos providers para suportar outros repositórios. Para o efeito bastará que a respetiva classe implemente o interface 'Primavera.Core.Storage.Tables.ITableStorageService'.

Exemplo:

internal sealed partial class AzureTableStorageService : ITableStorageService

Questões em Aberto

  • A API do serviço de file storage pode ser evoluída no futuro para disponibilizar comportamentos diferentes conforme o tipo de ficheiros armazenados.

FAQ

  • P: A configuração do serviço de file storage é obrigatória?
    • R: Não. Se não existir será utilizado o AzureFileStorageService.
  • P: A configuração do serviço de table storage é obrigatória?
    • R: Também não. Se não existir será utilizado o AzureTableStorageService.