Azure Blob Storage : upload par block

Azure Blob Storage : upload par block

Le service Azure Blob Storage est un service très efficace pour stoker des fichiers. Il peut être utilisé comme un CDN (content delivery network).
Dans le cas où vous stocker les fichiers larges celui-ci permet de les uploader par block.
Dans cet article nous verrons comment uploader un fichier en plusieurs block.

Upload

L’upload de fichier par block se fait en 3 étapes :

  • Calcul du md5 du fichier
  • Envoi des blocks de données
  • Envoi de la liste de blocks pour compléter l’upload

Calcul du md5 du fichier

Le calcul du hash md5 du fichier est très simple : on mets en mémoire l’intégralité du fichier sous forme de byte array puis on calcul le md5 associé.

 var bytes = await File.ReadAllBytesAsync(path, cancellationToken).ConfigureAwait(false);

var fileMD5 = Md5Helper.GetMD5String(bytes);

Ci dessous le code pour calculer le hash MD5 :

    public static class Md5Helper
    {
        public static string GetMD5String(byte[] data)
        {
            byte[] result = null;
            using (MD5 md5 = new MD5CryptoServiceProvider())
            {
                result = md5.ComputeHash(data);
            }
            return Convert.ToBase64String(result);
        }
    }

A noter : les API blob storage n’acceptent que la forme base 64 du hash Md5

Envoi des blocks de données

L’upload est assez simple il suffit de lire le fichier par block d’une taille donnée.
Dans notre exemple nous lirons le fichier par block de 10 mégas.

int blockSize = 10 * 1024 * 1024; //10 méga octets
var blockIds = new List<string>();
using (var reader = new BinaryReader(File.Open(path, FileMode.Open)))
{
  int blockId = 0;

  while (reader.BaseStream.Position != reader.BaseStream.Length)
  {
    var block = reader.ReadBytes(blockSize);
    blockIds.Add(await UploadBlockAsync(block, blobName, blockId).ConfigureAwait(false));
    blockId++;
  }

La fonction UploadBlockAsync envoyer les blocks de données au blob storage.
Pour chaque block nous calculerons le hash md5 de celui-ci que nous enverrons avec le block, ce qui permettra au blob storage de valider que les données n’est pas corrompu durant l’upload.

public async Task<string> UploadBlockAsync(byte[] blockData, string blobName, int blockId, CancellationToken cancellationToken = default)
        {

            var options = new BlobRequestOptions
            {
                DisableContentMD5Validation = false,
                ServerTimeout = TimeSpan.FromMinutes(30),
                SingleBlobUploadThresholdInBytes = blockSize,
                ParallelOperationThreadCount = 1,
                RetryPolicy = new ExponentialRetry(TimeSpan.Zero, 3),
                UseTransactionalMD5 = true,
                StoreBlobContentMD5 = true,
            };
            // l'identifiant de chaque block doit être encodé en base64 sinon l'api blob storage refuse le block
            var blockIdString = Convert.ToBase64String(Encoding.UTF8.GetBytes(blockId.ToString("d7")));

            cancellationToken.ThrowIfCancellationRequested();
            var md5Hash = Md5Helper.GetMD5String(blockData);

            var blockBlob = await GetBlockBlobRefenceAsync(blobName);

            cancellationToken.ThrowIfCancellationRequested();
            await blockBlob.PutBlockAsync(
                                        blockIdString,
                                        new MemoryStream(blockData, true),
                                        md5Hash,
                                        null,
                                        options,
                                        null);

            cancellationToken.ThrowIfCancellationRequested();
            Console.WriteLine(blockId);
            return blockIdString;
        }

Envoi de la liste de blocks pour compléter l’upload

La dernière étape pour “valider” que le fichier est envoyé correctement consiste à envoyer la liste des identifiants de chaque block uploadé.


A noter : Si vous ne faîtes pas cette étape votre blob n’est pas considéré comme complet, et au bout de quelques temps il sera automatiquement supprimé.

var options = new BlobRequestOptions
            {
                DisableContentMD5Validation = false,
                ServerTimeout = TimeSpan.FromMinutes(30),
                ParallelOperationThreadCount = 1,
                RetryPolicy = new ExponentialRetry(TimeSpan.Zero, 3),
                UseTransactionalMD5 = true,
                StoreBlobContentMD5 = true,
            };

            cancellationToken.ThrowIfCancellationRequested();

            var blockBlob = await GetBlockBlobRefenceAsync(blobName);

            cancellationToken.ThrowIfCancellationRequested();
            blockBlob.Properties.ContentMD5 = md5;
            await blockBlob.PutBlockListAsync(blockIds, null, options, null);

Et voilà, vous avez uploadé un fichier block par block sur le blob storage d’Azure !


Happy coding.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Pin It on Pinterest