Armazenamento de Blobs do Azure exemplos de código com bibliotecas de cliente .NET versão 11.x

Este artigo mostra exemplos de código que utilizam a versão 11.x da biblioteca de cliente Armazenamento de Blobs do Azure para .NET.

A 31 de março de 2023, retirámos o suporte para bibliotecas do SDK do Azure que não estão em conformidade com as diretrizes atuais do SDK do Azure. As novas bibliotecas do SDK do Azure são atualizadas regularmente para impulsionar experiências consistentes e reforçar a sua postura de segurança. Recomenda-se que faça a transição para as novas bibliotecas do SDK do Azure para tirar partido das novas capacidades e das atualizações de segurança críticas.

Embora as bibliotecas mais antigas ainda possam ser utilizadas para além de 31 de março de 2023, deixarão de receber suporte oficial e atualizações da Microsoft. Para obter mais informações, veja o anúncio de descontinuação do suporte.

Criar um instantâneo

Artigo relacionado: Criar e gerir um instantâneo de blobs no .NET

Para criar um instantâneo de um blob de blocos com a versão 11.x da biblioteca de cliente do Armazenamento do Azure para .NET, utilize um dos seguintes métodos:

O seguinte exemplo de código mostra como criar um instantâneo com a versão 11.x. Este exemplo especifica metadados adicionais para o instantâneo quando é criado.

private static async Task CreateBlockBlobSnapshot(CloudBlobContainer container)
{
    // Create a new block blob in the container.
    CloudBlockBlob baseBlob = container.GetBlockBlobReference("sample-base-blob.txt");

    // Add blob metadata.
    baseBlob.Metadata.Add("ApproxBlobCreatedDate", DateTime.UtcNow.ToString());

    try
    {
        // Upload the blob to create it, with its metadata.
        await baseBlob.UploadTextAsync(string.Format("Base blob: {0}", baseBlob.Uri.ToString()));

        // Sleep 5 seconds.
        System.Threading.Thread.Sleep(5000);

        // Create a snapshot of the base blob.
        // You can specify metadata at the time that the snapshot is created.
        // If no metadata is specified, then the blob's metadata is copied to the snapshot.
        Dictionary<string, string> metadata = new Dictionary<string, string>();
        metadata.Add("ApproxSnapshotCreatedDate", DateTime.UtcNow.ToString());
        await baseBlob.CreateSnapshotAsync(metadata, null, null, null);
        Console.WriteLine(snapshot.SnapshotQualifiedStorageUri.PrimaryUri);
    }
    catch (StorageException e)
    {
        Console.WriteLine(e.Message);
        Console.ReadLine();
        throw;
    }
}

Eliminar instantâneos

Artigo relacionado: Criar e gerir um instantâneo de blobs no .NET

Para eliminar um blob e os respetivos instantâneos com a versão 11.x da biblioteca de cliente do Armazenamento do Azure para .NET, utilize um dos seguintes métodos de eliminação de blobs e inclua a enum deleteSnapshotsOption :

O seguinte exemplo de código mostra como eliminar um blob e os respetivos instantâneos no .NET, onde blockBlob é um objeto do tipo [CloudBlockBlob][dotnet_CloudBlockBlob]:

await blockBlob.DeleteIfExistsAsync(DeleteSnapshotsOption.IncludeSnapshots, null, null, null);

Criar uma política de acesso armazenado

Artigo relacionado: Criar uma política de acesso armazenado com .NET

Para criar uma política de acesso armazenado num contentor com a versão 11.x da biblioteca de cliente .NET para o Armazenamento do Azure, chame um dos seguintes métodos:

O exemplo seguinte cria uma política de acesso armazenado que está em vigor durante um dia e que concede permissões de leitura, escrita e lista:

private static async Task CreateStoredAccessPolicyAsync(CloudBlobContainer container, string policyName)
{
    // Create a new stored access policy and define its constraints.
    // The access policy provides create, write, read, list, and delete permissions.
    SharedAccessBlobPolicy sharedPolicy = new SharedAccessBlobPolicy()
    {
        // When the start time for the SAS is omitted, the start time is assumed to be the time when Azure Storage receives the request.
        SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
        Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.List |
            SharedAccessBlobPermissions.Write
    };

    // Get the container's existing permissions.
    BlobContainerPermissions permissions = await container.GetPermissionsAsync();

    // Add the new policy to the container's permissions, and set the container's permissions.
    permissions.SharedAccessPolicies.Add(policyName, sharedPolicy);
    await container.SetPermissionsAsync(permissions);
}

Criar uma SAS de serviço para um contentor de blobs

Artigo relacionado: Criar uma SAS de serviço para um contentor ou blob com .NET

Para criar uma SAS de serviço para um contentor, chame o método CloudBlobContainer.GetSharedAccessSignature .

private static string GetContainerSasUri(CloudBlobContainer container,
                                         string storedPolicyName = null)
{
    string sasContainerToken;

    // If no stored policy is specified, create a new access policy and define its constraints.
    if (storedPolicyName == null)
    {
        // Note that the SharedAccessBlobPolicy class is used both to define
        // the parameters of an ad hoc SAS, and to construct a shared access policy
        // that is saved to the container's shared access policies.
        SharedAccessBlobPolicy adHocPolicy = new SharedAccessBlobPolicy()
        {
            // When the start time for the SAS is omitted, the start time is assumed
            // to be the time when the storage service receives the request. Omitting
            // the start time for a SAS that is effective immediately helps to avoid clock skew.
            SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
            Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.List
        };

        // Generate the shared access signature on the container,
        // setting the constraints directly on the signature.
        sasContainerToken = container.GetSharedAccessSignature(adHocPolicy, null);

        Console.WriteLine("SAS for blob container (ad hoc): {0}", sasContainerToken);
        Console.WriteLine();
    }
    else
    {
        // Generate the shared access signature on the container. In this case,
        // all of the constraints for the shared access signature are specified
        // on the stored access policy, which is provided by name. It is also possible
        // to specify some constraints on an ad hoc SAS and others on the stored access policy.
        sasContainerToken = container.GetSharedAccessSignature(null, storedPolicyName);

        Console.WriteLine("SAS for container (stored access policy): {0}", sasContainerToken);
        Console.WriteLine();
    }

    // Return the URI string for the container, including the SAS token.
    return container.Uri + sasContainerToken;
}

Criar uma SAS de serviço para um blob

Artigo relacionado: Criar uma SAS de serviço para um contentor ou blob com .NET

Para criar uma SAS de serviço para um blob, chame o método CloudBlob.GetSharedAccessSignature .

private static string GetBlobSasUri(CloudBlobContainer container,
                                    string blobName,
                                    string policyName = null)
{
    string sasBlobToken;

    // Get a reference to a blob within the container.
    // Note that the blob may not exist yet, but a SAS can still be created for it.
    CloudBlockBlob blob = container.GetBlockBlobReference(blobName);

    if (policyName == null)
    {
        // Create a new access policy and define its constraints.
        // Note that the SharedAccessBlobPolicy class is used both to define the parameters
        // of an ad hoc SAS, and to construct a shared access policy that is saved to
        // the container's shared access policies.
        SharedAccessBlobPolicy adHocSAS = new SharedAccessBlobPolicy()
        {
            // When the start time for the SAS is omitted, the start time is assumed to be
            // the time when the storage service receives the request. Omitting the start time
            // for a SAS that is effective immediately helps to avoid clock skew.
            SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
            Permissions = SharedAccessBlobPermissions.Read |
                          SharedAccessBlobPermissions.Write |
                          SharedAccessBlobPermissions.Create
        };

        // Generate the shared access signature on the blob,
        // setting the constraints directly on the signature.
        sasBlobToken = blob.GetSharedAccessSignature(adHocSAS);

        Console.WriteLine("SAS for blob (ad hoc): {0}", sasBlobToken);
        Console.WriteLine();
    }
    else
    {
        // Generate the shared access signature on the blob. In this case, all of the constraints
        // for the SAS are specified on the container's stored access policy.
        sasBlobToken = blob.GetSharedAccessSignature(null, policyName);

        Console.WriteLine("SAS for blob (stored access policy): {0}", sasBlobToken);
        Console.WriteLine();
    }

    // Return the URI string for the container, including the SAS token.
    return blob.Uri + sasBlobToken;
}

Criar uma SAS de conta

Artigo relacionado: Criar uma SAS de conta com .NET

Para criar uma SAS de conta para um contentor, chame o método CloudStorageAccount.GetSharedAccessSignature .

O exemplo de código seguinte cria uma SAS de conta válida para os serviços Blob e Ficheiro e dá permissões de leitura, escrita e lista de permissões de cliente para aceder a APIs ao nível do serviço. A SAS da conta restringe o protocolo a HTTPS, pelo que o pedido tem de ser feito com HTTPS. Lembre-se de substituir valores de marcador de posição em parênteses angulares pelos seus próprios valores:

static string GetAccountSASToken()
{
    // To create the account SAS, you need to use Shared Key credentials. Modify for your account.
    const string ConnectionString = "DefaultEndpointsProtocol=https;AccountName=<storage-account>;AccountKey=<account-key>";
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConnectionString);

    // Create a new access policy for the account.
    SharedAccessAccountPolicy policy = new SharedAccessAccountPolicy()
        {
            Permissions = SharedAccessAccountPermissions.Read | 
                          SharedAccessAccountPermissions.Write | 
                          SharedAccessAccountPermissions.List,
            Services = SharedAccessAccountServices.Blob | SharedAccessAccountServices.File,
            ResourceTypes = SharedAccessAccountResourceTypes.Service,
            SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
            Protocols = SharedAccessProtocol.HttpsOnly
        };

    // Return the SAS token.
    return storageAccount.GetSharedAccessSignature(policy);
}

Utilizar uma SAS de conta de um cliente

Artigo relacionado: Criar uma SAS de conta com .NET

Neste fragmento, substitua o <storage-account> marcador de posição pelo nome da sua conta de armazenamento.

static void UseAccountSAS(string sasToken)
{
    // Create new storage credentials using the SAS token.
    StorageCredentials accountSAS = new StorageCredentials(sasToken);
    // Use these credentials and the account name to create a Blob service client.
    CloudStorageAccount accountWithSAS = new CloudStorageAccount(accountSAS, "<storage-account>", endpointSuffix: null, useHttps: true);
    CloudBlobClient blobClientWithSAS = accountWithSAS.CreateCloudBlobClient();

    // Now set the service properties for the Blob client created with the SAS.
    blobClientWithSAS.SetServiceProperties(new ServiceProperties()
    {
        HourMetrics = new MetricsProperties()
        {
            MetricsLevel = MetricsLevel.ServiceAndApi,
            RetentionDays = 7,
            Version = "1.0"
        },
        MinuteMetrics = new MetricsProperties()
        {
            MetricsLevel = MetricsLevel.ServiceAndApi,
            RetentionDays = 7,
            Version = "1.0"
        },
        Logging = new LoggingProperties()
        {
            LoggingOperations = LoggingOperations.All,
            RetentionDays = 14,
            Version = "1.0"
        }
    });

    // The permissions granted by the account SAS also permit you to retrieve service properties.
    ServiceProperties serviceProperties = blobClientWithSAS.GetServiceProperties();
    Console.WriteLine(serviceProperties.HourMetrics.MetricsLevel);
    Console.WriteLine(serviceProperties.HourMetrics.RetentionDays);
    Console.WriteLine(serviceProperties.HourMetrics.Version);
}

Simultaneidade otimista para blobs

Artigo relacionado: Gerir a Simultaneidade no Armazenamento de Blobs

public void DemonstrateOptimisticConcurrencyBlob(string containerName, string blobName)
{
    Console.WriteLine("Demonstrate optimistic concurrency");

    // Parse connection string and create container.
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConnectionString);
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    CloudBlobContainer container = blobClient.GetContainerReference(containerName);
    container.CreateIfNotExists();

    // Create test blob. The default strategy is last writer wins, so
    // write operation will overwrite existing blob if present.
    CloudBlockBlob blockBlob = container.GetBlockBlobReference(blobName);
    blockBlob.UploadText("Hello World!");

    // Retrieve the ETag from the newly created blob.
    string originalETag = blockBlob.Properties.ETag;
    Console.WriteLine("Blob added. Original ETag = {0}", originalETag);

    /// This code simulates an update by another client.
    string helloText = "Blob updated by another client.";
    // No ETag was provided, so original blob is overwritten and ETag updated.
    blockBlob.UploadText(helloText);
    Console.WriteLine("Blob updated. Updated ETag = {0}", blockBlob.Properties.ETag);

    // Now try to update the blob using the original ETag value.
    try
    {
        Console.WriteLine(@"Attempt to update blob using original ETag
                            to generate if-match access condition");
        blockBlob.UploadText(helloText, accessCondition: AccessCondition.GenerateIfMatchCondition(originalETag));
    }
    catch (StorageException ex)
    {
        if (ex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.PreconditionFailed)
        {
            Console.WriteLine(@"Precondition failure as expected.
                                Blob's ETag does not match.");
        }
        else
        {
            throw;
        }
    }
    Console.WriteLine();
}

Simultaneidade pessimista para blobs

Artigo relacionado: Gerir a Simultaneidade no Armazenamento de Blobs

public void DemonstratePessimisticConcurrencyBlob(string containerName, string blobName)
{
    Console.WriteLine("Demonstrate pessimistic concurrency");

    // Parse connection string and create container.
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConnectionString);
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    CloudBlobContainer container = blobClient.GetContainerReference(containerName);
    container.CreateIfNotExists();

    CloudBlockBlob blockBlob = container.GetBlockBlobReference(blobName);
    blockBlob.UploadText("Hello World!");
    Console.WriteLine("Blob added.");

    // Acquire lease for 15 seconds.
    string lease = blockBlob.AcquireLease(TimeSpan.FromSeconds(15), null);
    Console.WriteLine("Blob lease acquired. Lease = {0}", lease);

    // Update blob using lease. This operation should succeed.
    const string helloText = "Blob updated";
    var accessCondition = AccessCondition.GenerateLeaseCondition(lease);
    blockBlob.UploadText(helloText, accessCondition: accessCondition);
    Console.WriteLine("Blob updated using an exclusive lease");

    // Simulate another client attempting to update to blob without providing lease.
    try
    {
        // Operation will fail as no valid lease was provided.
        Console.WriteLine("Now try to update blob without valid lease.");
        blockBlob.UploadText("Update operation will fail without lease.");
    }
    catch (StorageException ex)
    {
        if (ex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.PreconditionFailed)
        {
            Console.WriteLine(@"Precondition failure error as expected.
                                Blob lease not provided.");
        }
        else
        {
            throw;
        }
    }

    // Release lease proactively.
    blockBlob.ReleaseLease(accessCondition);
    Console.WriteLine();
}

Criar uma aplicação de elevada disponibilidade com o Armazenamento de Blobs

Artigo relacionado: Tutorial: Criar uma aplicação de elevada disponibilidade com o Armazenamento de blobs.

Transferir o exemplo

Transfira o projeto de exemplo, extraia (deszipe) o ficheiro storage-dotnet-circuit-breaker-pattern-ha-apps-using-ra-grs.zip e, em seguida, navegue para a pasta v11 para localizar os ficheiros do projeto.

Também pode utilizar o git para transferir uma cópia da aplicação para o seu ambiente de desenvolvimento. O projeto de exemplo na pasta v11 contém uma aplicação de consola.

git clone https://github.com/Azure-Samples/storage-dotnet-circuit-breaker-pattern-ha-apps-using-ra-grs.git

Configurar o exemplo

Na aplicação, tem de indicar a cadeia de ligação da sua conta de armazenamento. Pode armazenar esta cadeia de ligação numa variável de ambiente no computador local que executa a aplicação. Siga um dos exemplos abaixo, consoante o Sistema Operativo para criar a variável de ambiente.

No portal do Azure, navegue para a sua conta de armazenamento. Selecione Chaves de acesso, em Definições, na conta de armazenamento. Copie a cadeia de ligação da chave primária ou secundária. Execute um dos seguintes comandos com base no seu sistema operativo, substituindo <yourconnectionstring> pela cadeia de ligação real. Este comando guarda uma variável de ambiente no computador local. No Windows, a variável de ambiente não está disponível até recarregar a Linha de Comandos ou a shell que está a utilizar.

Executar a aplicação de consola

No Visual Studio, prima F5 ou selecione Iniciar para começar a depurar a aplicação. O Visual Studio restaura automaticamente pacotes NuGet em falta se o restauro do pacote estiver configurado, visite Instalar e reinstalar pacotes com o restauro do pacote para saber mais.

É iniciada uma janela de consola e a aplicação começa a ser executada. A aplicação carrega a imagem HelloWorld.png da solução para a conta de armazenamento. A aplicação verifica se a imagem foi replicada para o ponto final RA-GZRS secundário. Em seguida, começa a transferir a imagem até 999 vezes. Cada leitura é representada por um P ou um S. Em que P representa o ponto final primário e S representa o ponto final secundário.

Captura de ecrã a mostrar a saída da aplicação consola.

No código de exemplo, a tarefa RunCircuitBreakerAsync no ficheiro Program.cs é utilizada para transferir uma imagem da conta de armazenamento através do método DownloadToFileAsync. Antes da transferência, é definido um OperationContext . O contexto de operação define os processadores de eventos que são acionados quando uma transferência é concluída com êxito ou se uma transferência falha e está a tentar novamente.

Compreender o código de exemplo

Processador de eventos de repetição

O processador de eventos OperationContextRetrying é chamado quando a transferência da imagem falha e está definida para repetir. Se for atingido o número máximo de repetições definidas na aplicação, LocationMode do pedido é alterado para SecondaryOnly. Esta definição força a aplicação a tentar transferir a imagem do ponto final secundário. Esta configuração reduz o tempo necessário para pedir a imagem, uma vez que o ponto final primário não é repetido indefinidamente.

private static void OperationContextRetrying(object sender, RequestEventArgs e)
{
    retryCount++;
    Console.WriteLine("Retrying event because of failure reading the primary. RetryCount = " + retryCount);

    // Check if we have had more than n retries in which case switch to secondary.
    if (retryCount >= retryThreshold)
    {

        // Check to see if we can fail over to secondary.
        if (blobClient.DefaultRequestOptions.LocationMode != LocationMode.SecondaryOnly)
        {
            blobClient.DefaultRequestOptions.LocationMode = LocationMode.SecondaryOnly;
            retryCount = 0;
        }
        else
        {
            throw new ApplicationException("Both primary and secondary are unreachable. Check your application's network connection. ");
        }
    }
}

Processador de eventos de pedido concluído

O processador de eventos OperationContextRequestCompleted é chamado quando a transferência da imagem é bem-sucedida. Se a aplicação estiver a utilizar o ponto final secundário, continua a utilizar este ponto final até 20 vezes. Ao fim dessas 20 vezes, a aplicação define LocationMode novamente como PrimaryThenSecondary e repete o ponto final primário. Se um pedido for bem-sucedido, a aplicação continua a ler a partir do ponto final primário.

private static void OperationContextRequestCompleted(object sender, RequestEventArgs e)
{
    if (blobClient.DefaultRequestOptions.LocationMode == LocationMode.SecondaryOnly)
    {
        // You're reading the secondary. Let it read the secondary [secondaryThreshold] times,
        //    then switch back to the primary and see if it's available now.
        secondaryReadCount++;
        if (secondaryReadCount >= secondaryThreshold)
        {
            blobClient.DefaultRequestOptions.LocationMode = LocationMode.PrimaryThenSecondary;
            secondaryReadCount = 0;
        }
    }
}

Carregar grandes quantidades de dados aleatórios para o armazenamento do Azure

Artigo relacionado: Carregar grandes quantidades de dados aleatórios em paralelo para o armazenamento do Azure

O número mínimo e máximo de threads está definido como 100 para garantir que é permitido um grande número de ligações simultâneas.

private static async Task UploadFilesAsync()
{
    // Create five randomly named containers to store the uploaded files.
    CloudBlobContainer[] containers = await GetRandomContainersAsync();

    var currentdir = System.IO.Directory.GetCurrentDirectory();

    // Path to the directory to upload
    string uploadPath = currentdir + "\\upload";

    // Start a timer to measure how long it takes to upload all the files.
    Stopwatch time = Stopwatch.StartNew();

    try
    {
        Console.WriteLine("Iterating in directory: {0}", uploadPath);

        int count = 0;
        int max_outstanding = 100;
        int completed_count = 0;

        // Define the BlobRequestOptions on the upload.
        // This includes defining an exponential retry policy to ensure that failed connections
        // are retried with a back off policy. As multiple large files are being uploaded using
        // large block sizes, this can cause an issue if an exponential retry policy is not defined.
        // Additionally, parallel operations are enabled with a thread count of 8.
        // This should be a multiple of the number of processor cores in the machine.
        // Lastly, MD5 hash validation is disabled for this example, improving the upload speed.
        BlobRequestOptions options = new BlobRequestOptions
        {
            ParallelOperationThreadCount = 8,
            DisableContentMD5Validation = true,
            StoreBlobContentMD5 = false
        };

        // Create a new instance of the SemaphoreSlim class to 
        // define the number of threads to use in the application.
        SemaphoreSlim sem = new SemaphoreSlim(max_outstanding, max_outstanding);

        List<Task> tasks = new List<Task>();
        Console.WriteLine("Found {0} file(s)", Directory.GetFiles(uploadPath).Count());

        // Iterate through the files
        foreach (string path in Directory.GetFiles(uploadPath))
        {
            var container = containers[count % 5];
            string fileName = Path.GetFileName(path);
            Console.WriteLine("Uploading {0} to container {1}", path, container.Name);
            CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName);

            // Set the block size to 100MB.
            blockBlob.StreamWriteSizeInBytes = 100 * 1024 * 1024;

            await sem.WaitAsync();

            // Create a task for each file to upload. The tasks are
            // added to a collection and all run asynchronously.
            tasks.Add(blockBlob.UploadFromFileAsync(path, null, options, null).ContinueWith((t) =>
            {
                sem.Release();
                Interlocked.Increment(ref completed_count);
            }));

            count++;
        }

        // Run all the tasks asynchronously.
        await Task.WhenAll(tasks);

        time.Stop();

        Console.WriteLine("Upload has been completed in {0} seconds. Press any key to continue", time.Elapsed.TotalSeconds.ToString());

        Console.ReadLine();
    }
    catch (DirectoryNotFoundException ex)
    {
        Console.WriteLine("Error parsing files in the directory: {0}", ex.Message);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

Além de configurar as definições de threading e de ligação, as BlobRequestOptions do método UploadFromStreamAsync estão configuradas para utilizar o paralelismo e desativar a validação do hash MD5. Os ficheiros são carregados em blocos de 100 MB e esta configuração proporciona um melhor desempenho, mas poderá ser dispendiosa se utilizar uma rede com um desempenho fraco, uma vez que se houver uma falha, todo o bloco de 100 MB é repetido.

Propriedade Valor Descrição
ParallelOperationThreadCount 8 A definição divide o blob em blocos ao carregar. Para um desempenho mais elevado, este valor deve ser oito vezes superior ao número de núcleos.
DisableContentMD5Validation true Esta propriedade desativa a verificação do hash MD5 do conteúdo carregado. Desativar a validação MD5 permite uma transferência mais rápida. Mas não confirma a validade nem a integridade dos ficheiros que estão a ser transferidos.
StoreBlobContentMD5 false Esta propriedade determina se um hash MD5 é calculado e armazenado com o ficheiro.
RetryPolicy Término de 2 segundos com máximo de 10 repetições Determina a política de repetição dos pedidos. As falhas de ligação são repetidas, neste exemplo, uma políticaExponentialRetry é configurada com um término de 2 segundos e uma contagem de repetições máxima de 10. Esta definição é importante quando a aplicação está perto de atingir os objetivos de escalabilidade do armazenamento de Blobs. Para obter mais informações, veja Metas de escalabilidade e desempenho do Armazenamento de blobs.

Transferir grandes quantidades de dados aleatórios do armazenamento do Azure

Artigo relacionado: Transferir grandes quantidades de dados aleatórios do armazenamento do Azure

A aplicação lê os contentores localizados na conta de armazenamento especificada em storageconnectionstring. Itera através dos blobs 10 de cada vez com o método ListBlobsSegmentedAsync nos contentores e transfere-os para o computador local com o método DownloadToFileAsync .

A tabela seguinte mostra os BlobRequestOptions definidos para cada blob à medida que são transferidos.

Propriedade Valor Descrição
DisableContentMD5Validation true Esta propriedade desativa a verificação do hash MD5 do conteúdo carregado. Desativar a validação MD5 permite uma transferência mais rápida. Mas não confirma a validade nem a integridade dos ficheiros que estão a ser transferidos.
StoreBlobContentMD5 false Esta propriedade determina se um hash MD5 é calculado e armazenado.
private static async Task DownloadFilesAsync()
{
    CloudBlobClient blobClient = GetCloudBlobClient();

    // Define the BlobRequestOptions on the download, including disabling MD5 
    // hash validation for this example, this improves the download speed.
    BlobRequestOptions options = new BlobRequestOptions
    {
        DisableContentMD5Validation = true,
        StoreBlobContentMD5 = false
    };

    // Retrieve the list of containers in the storage account.
    // Create a directory and configure variables for use later.
    BlobContinuationToken continuationToken = null;
    List<CloudBlobContainer> containers = new List<CloudBlobContainer>();
    do
    {
        var listingResult = await blobClient.ListContainersSegmentedAsync(continuationToken);
        continuationToken = listingResult.ContinuationToken;
        containers.AddRange(listingResult.Results);
    }
    while (continuationToken != null);

    var directory = Directory.CreateDirectory("download");
    BlobResultSegment resultSegment = null;
    Stopwatch time = Stopwatch.StartNew();

    // Download the blobs
    try
    {
        List<Task> tasks = new List<Task>();
        int max_outstanding = 100;
        int completed_count = 0;

        // Create a new instance of the SemaphoreSlim class to
        // define the number of threads to use in the application.
        SemaphoreSlim sem = new SemaphoreSlim(max_outstanding, max_outstanding);

        // Iterate through the containers
        foreach (CloudBlobContainer container in containers)
        {
            do
            {
                // Return the blobs from the container, 10 at a time.
                resultSegment = await container.ListBlobsSegmentedAsync(null, true, BlobListingDetails.All, 10, continuationToken, null, null);
                continuationToken = resultSegment.ContinuationToken;
                {
                    foreach (var blobItem in resultSegment.Results)
                    {

                        if (((CloudBlob)blobItem).Properties.BlobType == BlobType.BlockBlob)
                        {
                            // Get the blob and add a task to download the blob asynchronously from the storage account.
                            CloudBlockBlob blockBlob = container.GetBlockBlobReference(((CloudBlockBlob)blobItem).Name);
                            Console.WriteLine("Downloading {0} from container {1}", blockBlob.Name, container.Name);
                            await sem.WaitAsync();
                            tasks.Add(blockBlob.DownloadToFileAsync(directory.FullName + "\\" + blockBlob.Name, FileMode.Create, null, options, null).ContinueWith((t) =>
                            {
                                sem.Release();
                                Interlocked.Increment(ref completed_count);
                            }));

                        }
                    }
                }
            }
            while (continuationToken != null);
        }

        // Creates an asynchronous task that completes when all the downloads complete.
        await Task.WhenAll(tasks);
    }
    catch (Exception e)
    {
        Console.WriteLine("\nError encountered during transfer: {0}", e.Message);
    }

    time.Stop();
    Console.WriteLine("Download has been completed in {0} seconds. Press any key to continue", time.Elapsed.TotalSeconds.ToString());
    Console.ReadLine();
}

Ativar os registos de Análise de Armazenamento do Azure (clássico)

Artigo relacionado: Ativar e gerir registos de Análise de Armazenamento do Azure (clássico)

var storageAccount = CloudStorageAccount.Parse(connStr);  
var queueClient = storageAccount.CreateCloudQueueClient();  
var serviceProperties = queueClient.GetServiceProperties();

serviceProperties.Logging.LoggingOperations = LoggingOperations.All;  
serviceProperties.Logging.RetentionDays = 2;

queueClient.SetServiceProperties(serviceProperties);  

Modificar o período de retenção de dados do registo

Artigo relacionado: Ativar e gerir registos de Análise de Armazenamento do Azure (clássico)

O exemplo seguinte imprime na consola o período de retenção dos serviços de armazenamento de blobs e filas.

var storageAccount = CloudStorageAccount.Parse(connectionString);

var blobClient = storageAccount.CreateCloudBlobClient();
var queueClient = storageAccount.CreateCloudQueueClient();

var blobserviceProperties = blobClient.GetServiceProperties();
var queueserviceProperties = queueClient.GetServiceProperties();

Console.WriteLine("Retention period for logs from the blob service is: " +
   blobserviceProperties.Logging.RetentionDays.ToString());

Console.WriteLine("Retention period for logs from the queue service is: " +
   queueserviceProperties.Logging.RetentionDays.ToString());

O exemplo seguinte altera o período de retenção dos registos dos serviços de armazenamento de blobs e filas para 4 dias.


blobserviceProperties.Logging.RetentionDays = 4;
queueserviceProperties.Logging.RetentionDays = 4;

blobClient.SetServiceProperties(blobserviceProperties);
queueClient.SetServiceProperties(queueserviceProperties);  

Ativar as métricas do Azure Análise de Armazenamento (clássico)

Artigo relacionado: Ativar e gerir métricas do Azure Análise de Armazenamento (clássico)

var storageAccount = CloudStorageAccount.Parse(connStr);  
var queueClient = storageAccount.CreateCloudQueueClient();  
var serviceProperties = queueClient.GetServiceProperties();

serviceProperties.HourMetrics.MetricsLevel = MetricsLevel.Service;  
serviceProperties.HourMetrics.RetentionDays = 10;

queueClient.SetServiceProperties(serviceProperties);  

Configurar o Transport Layer Security (TLS) para uma aplicação cliente

Artigo relacionado: Configurar o Transport Layer Security (TLS) para uma aplicação cliente

O exemplo seguinte mostra como ativar o TLS 1.2 num cliente .NET com a versão 11.x da biblioteca de cliente do Armazenamento do Azure:

static void EnableTls12()
{
    // Enable TLS 1.2 before connecting to Azure Storage
    System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;

    // Add your connection string here.
    string connectionString = "";

    // Connect to Azure Storage and create a new container.
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

    CloudBlobContainer container = blobClient.GetContainerReference("sample-container");
    container.CreateIfNotExists();
}

Monitorizar, diagnosticar e resolver problemas Armazenamento do Microsoft Azure (clássico)

Artigo relacionado: Monitorizar, diagnosticar e resolver problemas Armazenamento do Microsoft Azure (clássico)

Se a Biblioteca de Cliente de Armazenamento lançar uma StorageException no cliente, a propriedade RequestInformation contém um objeto RequestResult que inclui uma propriedade ServiceRequestID . Também pode aceder a um objeto RequestResult a partir de uma instância OperationContext .

O exemplo de código abaixo demonstra como definir um valor ClientRequestId personalizado ao anexar um objeto OperationContext ao serviço de armazenamento. Também mostra como obter o valor ServerRequestId da mensagem de resposta.

//Parse the connection string for the storage account.
const string ConnectionString = "DefaultEndpointsProtocol=https;AccountName=account-name;AccountKey=account-key";
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConnectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

// Create an Operation Context that includes custom ClientRequestId string based on constants defined within the application along with a Guid.
OperationContext oc = new OperationContext();
oc.ClientRequestID = String.Format("{0} {1} {2} {3}", HOSTNAME, APPNAME, USERID, Guid.NewGuid().ToString());

try
{
    CloudBlobContainer container = blobClient.GetContainerReference("democontainer");
    ICloudBlob blob = container.GetBlobReferenceFromServer("testImage.jpg", null, null, oc);  
    var downloadToPath = string.Format("./{0}", blob.Name);
    using (var fs = File.OpenWrite(downloadToPath))
    {
        blob.DownloadToStream(fs, null, null, oc);
        Console.WriteLine("\t Blob downloaded to file: {0}", downloadToPath);
    }
}
catch (StorageException storageException)
{
    Console.WriteLine("Storage exception {0} occurred", storageException.Message);
    // Multiple results may exist due to client side retry logic - each retried operation will have a unique ServiceRequestId
    foreach (var result in oc.RequestResults)
    {
            Console.WriteLine("HttpStatus: {0}, ServiceRequestId {1}", result.HttpStatusCode, result.ServiceRequestID);
    }
}

Investigar problemas de desempenho do cliente – desativar o algoritmo Nagle

Artigo relacionado: Monitorizar, diagnosticar e resolver problemas Armazenamento do Microsoft Azure (clássico)

var storageAccount = CloudStorageAccount.Parse(connStr);
ServicePoint queueServicePoint = ServicePointManager.FindServicePoint(storageAccount.QueueEndpoint);
queueServicePoint.UseNagleAlgorithm = false;

Investigar problemas de latência de rede – configurar a Partilha de Recursos entre Origens (CORS)

Artigo relacionado: Monitorizar, diagnosticar e resolver problemas Armazenamento do Microsoft Azure (clássico)

CloudBlobClient client = new CloudBlobClient(blobEndpoint, new StorageCredentials(accountName, accountKey));
// Set the service properties.
ServiceProperties sp = client.GetServiceProperties();
sp.DefaultServiceVersion = "2013-08-15";
CorsRule cr = new CorsRule();
cr.AllowedHeaders.Add("*");
cr.AllowedMethods = CorsHttpMethods.Get | CorsHttpMethods.Put;
cr.AllowedOrigins.Add("http://www.contoso.com");
cr.ExposedHeaders.Add("x-ms-*");
cr.MaxAgeInSeconds = 5;
sp.Cors.CorsRules.Clear();
sp.Cors.CorsRules.Add(cr);
client.SetServiceProperties(sp);

Criar um blob de página vazio de um tamanho especificado

Artigo relacionado: Descrição geral dos blobs de páginas do Azure

Para criar um blob de páginas, criamos primeiro um objeto CloudBlobClient , com o URI base para aceder ao armazenamento de blobs da sua conta de armazenamento (pbaccount na figura 1), juntamente com o objeto StorageCredentialsAccountAndKey , conforme mostrado no exemplo seguinte. O exemplo mostra então a criação de uma referência a um objeto CloudBlobContainer e, em seguida, a criação do contentor (testvhds) se ainda não existir. Em seguida, com o objeto CloudBlobContainer , crie uma referência a um objeto CloudPageBlob ao especificar o nome do blob de página (os4.vhd) a aceder. Para criar o blob de páginas, chame CloudPageBlob.Create, transmitindo o tamanho máximo para o blob criar. O blobSize tem de ser um múltiplo de 512 bytes.

using Microsoft.Azure;
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Blob;

long OneGigabyteAsBytes = 1024 * 1024 * 1024;
// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
    CloudConfigurationManager.GetSetting("StorageConnectionString"));

// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

// Retrieve a reference to a container.
CloudBlobContainer container = blobClient.GetContainerReference("testvhds");

// Create the container if it doesn't already exist.
container.CreateIfNotExists();

CloudPageBlob pageBlob = container.GetPageBlobReference("os4.vhd");
pageBlob.Create(16 * OneGigabyteAsBytes);

Redimensionar um blob de páginas

Artigo relacionado: Descrição geral dos blobs de páginas do Azure

Para redimensionar um blob de página após a criação, utilize o método Redimensionar . O tamanho pedido deve ser múltiplo de 512 bytes.

pageBlob.Resize(32 * OneGigabyteAsBytes);

Escrever páginas num blob de páginas

Artigo relacionado: Descrição geral dos blobs de páginas do Azure

Para escrever páginas, utilize o método CloudPageBlob.WritePages .

pageBlob.WritePages(dataStream, startingOffset); 

Ler páginas a partir de um blob de páginas

Artigo relacionado: Descrição geral dos blobs de páginas do Azure

Para ler páginas, utilize o método CloudPageBlob.DownloadRangeToByteArray para ler um intervalo de bytes do blob de páginas.

byte[] buffer = new byte[rangeSize];
pageBlob.DownloadRangeToByteArray(buffer, bufferOffset, pageBlobOffset, rangeSize); 

Para determinar que páginas são suportadas por dados, utilize CloudPageBlob.GetPageRanges. Em seguida, pode enumerar os intervalos devolvidos e transferir os dados em cada intervalo.

IEnumerable<PageRange> pageRanges = pageBlob.GetPageRanges();

foreach (PageRange range in pageRanges)
{
    // Calculate the range size
    int rangeSize = (int)(range.EndOffset + 1 - range.StartOffset);

    byte[] buffer = new byte[rangeSize];

    // Read from the correct starting offset in the page blob and
    // place the data in the bufferOffset of the buffer byte array
    pageBlob.DownloadRangeToByteArray(buffer, bufferOffset, range.StartOffset, rangeSize);

    // Then use the buffer for the page range just read
}