Partager via


Tutoriel pour la migration de contenu d’Stockage Blob Azure conteneur vers un conteneur SharePoint Embedded

Objectif

Ce tutoriel vous guide tout au long de la migration du contenu de Stockage Blob Azure (ABS) vers SharePoint Embedded (SPE) à l’aide de C#. Cela est utile pour les clients qui ont 500 documents dans le conteneur de stockage d’objets blob.

Configuration requise

  1. Une inscription d’application Microsoft Entra ID. Consultez Inscrire une application.

  2. Votre locataire Microsoft Entra ID dispose d’un abonnement Microsoft 365.

  3. Locataire Microsoft Entra ID. Si vous n’avez pas de locataire, créez un compte Azure gratuit pour obtenir un abonnement gratuit.

  4. Un compte avec au moins le rôle Administrateur général ou Administrateur SharePoint Incorporé.

  5. SDK .NET Core version 8.0.303

  6. Environnement Dotnet pour exécuter l’exemple d’application

    • Il peut être exécuté sur Windows, Linux et macOS
  7. Conteneur SharePoint Embedded

    • Pour plus d’informations sur la configuration d’un conteneur SPE
  8. Stockage Blob Azure conteneur

    • Pour plus d’informations sur la configuration d’un conteneur ABS

Authentification

Stockage Blob Azure

  1. Informations d’identification : URL de signature d’accès partagé (SAS) au niveau du conteneur.
  2. Autorisation - Lecture et liste

SharePoint Embedded

  1. Un compte Azure

  2. Un locataire SharePoint dans lequel vous allez créer vos conteneurs et son ID de locataire

  3. UN ID d’application intégré (parfois appelé ID client) et son ContainerTypeId correspondant

  4. Créez une inscription d’application dans Microsoft Entra ID portail.

  5. Dans Inscription d’application, ajoutez une nouvelle plateforme d’application Console mobile & dans Microsoft Entra ID portail d’authentification de l’inscription des applications

    Capture d’écran de Microsoft Entra ID configuration de l’application

  6. Un ContainerType

  7. Un conteneur

  8. Avoir l’application inscrite dans le locataire consommateur (même si le propriétaire de l’application est le même que le consommateur)

  9. Avoir le containerType inscrit dans le locataire consommateur (même si le propriétaire du CT est le même que le consommateur)

  10. Utilisation du nom d’utilisateur et des informations d’identification de mot de passe du locataire : sera nécessaire pour authentifier le client Microsoft Graph

  11. Autorisation : « User.Read », « FileStorageContainer.Selected »

Migration de données d’Stockage Blob Azure conteneur vers un conteneur SharePoint Embedded

Description

Cette section fournit des extraits de code sur la façon d’effectuer la migration. Toutes les validations ont été supprimées pour des fins de lisibilité.

Connexion à Stockage Blob Azure conteneur

_containerClient = new BlobContainerClient(new Uri(_containerLevelSASUrl));

Connexion à SharePoint Embedded

string[] _scopes = { "User.Read", "FileStorageContainer.Selected" };
InteractiveBrowserCredentialOptions interactiveBrowserCredentialOptions = new InteractiveBrowserCredentialOptions()
  {
    ClientId = clientId,
    RedirectUri = new Uri("http://localhost"),
  };
InteractiveBrowserCredential interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveBrowserCredentialOptions);

_graphClient = new GraphServiceClient(interactiveBrowserCredential, scopes, null);

// Will open up a browser to provide your consuming tenant admin credentials
var user = await _graphClient.Me.GetAsync();

Obtention de la liste des objets blob

var blobs = new List<string>();
await foreach (var blobItem in _containerClient.GetBlobsAsync())
{
  blobs.Add(blobItem.Name);
}
return blobs;

Regroupement de threads

private CountdownEvent _countdown;

// This is how the thread pool knows how many files are being migrated
_countdown = new CountdownEvent(blobs.Count);

FileStructure

public class FileStructure
{
  public string blobName { get; set; }
  public string parentFolderId { get; set; }
}

Parcourir la liste des objets blob

// It creates a new folder in the destination. The name of the folder is the blob's container name.
// root means it is the root of the document library.
// If you want to copy it to another drive item, you can put the drive item ID here.
containerFolder = await _graphClient.CreateFolder(_containerName, "root");

// Traverse the blob list
foreach (var blobName in fileList)
{
  FileStructure fs = new FileStructure() { blobName = blobName };

  // This function parses the flat file into the folder hierarchy and creates the folder structure in the destination. It will retrieve the parentFolderId that the file should be copied to.
  // If you are going to copy it to root you can comment this line out. The parentFolderId will be containerFolder.Id
  fs.parentFolderId = TraverseBlobName(fs, containerFolder.Id)

  // This is where the thread pool happens.
  // It takes in a callback function and an Object parameter.
  ThreadPool.QueueUserWorkItem(MigrateFile, fs);
}

// Call so the program doesn't end, it waits for all the files to be processed
_countdown.Wait();

Parcourir le nom de l’objet blob

// Parse for folder path not including the file name and put it in an array
var pathSegments = filePath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
string[] directoriesParts = pathSegments.Take(pathSegments.Length - 1).ToArray();

// Traverse the folder listing and create 1 folder at a time
string relativePath = _containerName;
string newFolderId = parentFolderId;
foreach (string folderName in directoriesParts)
{
  string newPath = relativePath + _separator + folderName;
  ...

  DriveItem subFolder = await _graphClient.CheckIfItemExists(folderName, newFolderId);
  if (subFolder == null)
  {
    subFolder = await _graphClient.CreateFolder(folderName, newFolderId);
    ...
  }
  newFolderId = subFolder.Id;

  relativePath = newPath;
}

return newFolderId;

Vérifier si l’élément existe

var item = await _graphClient.Drives[_containerId].Items[parentFolderId].ItemWithPath(itemPath).GetAsync();

Créer un dossier

var folder = new DriveItem
{
  Name = folderName,
  Folder = new Folder(),
  AdditionalData = new Dictionary<string, object>()
  {
    { "@microsoft.graph.conflictBehavior", "fail" }
  }
};
var createdFolder = await _graphClient.Drives[_containerId].Items[parentFolderId].Children.PostAsync(folder);

Migrer un fichier

// The parameter must be of type Object.
internal async void MigrateFile(Object stateInfo)
{
  var fileStructure = (FileStructure)stateInfo;

  // Check if the file exists in the destination. If it exists
  // - don't upload
  // - check if the file is newer in the source than the destination - then upload
  ...

  // Migrate the file
  // This is where you download the blob as a stream from abs (code below)
  ...

  // Then upload the stream to SPE (code below)
  ...

  // Signal the countdown event that a file has been migrated
  _countdown.Signal();

  return;
}

Téléchargement à partir de l’objet blob à partir de ABS en tant que Stream

BlobClient blobClient = _containerClient.GetBlobClient(blobName);

MemoryStream memoryStream = new MemoryStream();
await blobClient.DownloadToAsync(memoryStream);
memoryStream.Position = 0; // Reset the stream position to the beginning

Chargement du Stream dans SPE

int _maxChunkSize = 320 * 1024;

var uploadSessionRequestBody = new CreateUploadSessionPostRequestBody()
{
  AdditionalData = new Dictionary<string, object>
  {
    // Fail is set here, so it doesn't get upload again if it already exist
    { "@microsoft.graph.conflictBehavior", "fail" }
  }
};

var uploadSession = await _graphClient.Drives[_containerId]
    .Items[parentFolderId]
    .ItemWithPath(fileName)
    .CreateUploadSession
    .PostAsync(uploadSessionRequestBody);

// The stream is the same stream from the downloading the blob
var fileUploadTask = new LargeFileUploadTask<DriveItem>(uploadSession, memoryStream, _maxChunkSize, _graphClient.RequestAdapter);
IProgress<long> progress = new Progress<long>(prog => Console.WriteLine($"Uploaded {fileName} {prog} bytes"));

// Check uploadResult.UploadSucceeded to see if it is successful
var uploadResult = await fileUploadTask.UploadAsync(progress);

Vue d’ensemble de l’exemple d’application

Description

Exemple d’application appelée MigrateABStoSPE conçue pour migrer des fichiers d’un conteneur Stockage Blob Azure (ABS) vers un conteneur SharePoint Embedded (SPE). Les extraits de code fournis dans le conteneur Migration de données de Stockage Blob Azure conteneur vers SharePoint Embedded proviennent de l’exemple d’application.

Il utilise les bibliothèques Azure.Storage.Blobs et Newtonsoft.Json pour travailler avec des données ABS et JSON respectivement. L’application s’authentifie avec ABS et SPE à l’aide des informations d’identification du client et effectue la migration des fichiers.

Packages

  1. Sdk Microsoft Graph (version 5.56.0)
  2. Azure.Identity (version 1.12.0)
  3. Azure.Storage.Blobs (version 12.21.0)
  4. CommandLineParser (version 2.9.1)
  5. Newtonsoft.Json (13.0.3)

Hors de portée

  1. Comment traiter les fichiers qui existent déjà dans la destination : elle échoue, elle ne remplace pas ou ne renomme pas
  2. Comment gérer ABS version plus récente que la destination : elle échoue, car le fichier existe déjà dans la destination

Exécution de l’exemple d’application

  1. Ouvrez un terminal ou une invite de commandes.

  2. Accédez au répertoire où se trouve le fichier Program.cs.

  3. Vérifiez que le SDK .NET Core est installé sur votre ordinateur. Vous pouvez case activée cela en exécutant la commande dotnet --version dans le terminal. Si la commande n’est pas reconnue, vous pouvez télécharger et installer le Kit de développement logiciel (SDK) .NET Core à partir du site web officiel de Microsoft.

  4. Une fois que vous avez confirmé que le Kit de développement logiciel (SDK) .NET Core est installé, vous pouvez générer l’application en exécutant la commande dotnet build. Cela compilera le code et générera les fichiers binaires nécessaires.

  5. Une fois le processus de génération terminé, vous pouvez exécuter l’application en exécutant la commande dotnet run suivie des arguments requis. Les arguments requis sont les suivants :

    • URL SAS au niveau du conteneur : IL s’agit d’une URL SAS au niveau du conteneur d’objets blob Azure. Il fournit l’accès au conteneur et à ses objets blob.
    • ID de locataire SPE : il s’agit du locataire sur lequel vous vous authentifiez dans le spe.
    • ID client SPE : il s’agit du client sur lequel vous vous authentifiez dans le spe.
    • ID de conteneur SPE : il s’agit du conteneur vers lequel vous migrez du contenu dans le spe. Pour plus d’informations sur l’obtention de l’ID de conteneur
    • (facultatif) Nom de fichier avec le chemin d’accès complet qui contient la liste d’objets blob.
    • (facultatif) Nom de fichier avec le chemin d’accès complet où générer les objets blob ayant échoué.

Par exemple, la commande pour exécuter l’application avec les arguments requis ressemblerait à ceci :

dotnet run Program.cs -- --sasurl "<sas url>" --tenantid "<tenant id>" --clientid "<client id>" --containerid "<container id>" [ --blobfile "<file name>" --outputfile "<file name>" ]

Structure d’objet blob et d’élément SPE

ABS conteneur n’adhère pas à une structure de dossiers, tous les objets blob sont stockés dans une structure de liste plate. Lors de la migration vers SPE, l’exemple d’application analyse le nom de l’objet blob et crée la structure de dossiers dans l’ID de conteneur fourni, avec le nom du conteneur comme dossier supérieur. Si vous migrez vers le dossier racine, vous pouvez ignorer cette section.

Source

  • Nom du conteneur : Container1
    • Nom de l’objet blob : FolderA/blob1.txt
    • Nom de l’objet blob : FolderA/FolderB/blob2.txt
    • Nom de l’objet blob : FolderA/FolderB/FolderC/blob3.txt

Destination

  • Dossier d’élément de lecteur
    • Container1
      • FolderA
        • blob1.txt
        • FolderB
          • blob2.txt
          • FolderC
            • blob3.txt

Gestion des erreurs et des exceptions

Problèmes courants

  1. Le fichier existe déjà dans la destination

    • Cette application vérifie si le nom de fichier existe dans la destination avant son chargement. S’il existe un fichier portant exactement le même nom, le chargement n’est pas à nouveau fait. Il imprime sur stdout un message indiquant que le fichier existe déjà. Pour résoudre ce problème, vous pouvez supprimer le fichier de la destination ou modifier conflictBehavior pour remplacer et ne pas appeler CheckIfItemExists lors du chargement.
  2. Le fichier de la liste des objets blob est introuvable

  3. Format de la liste des objets blob : un objet blob par ligne, sans guillemets autour du nom de l’objet blob

  4. Ne pas accorder suffisamment d’autorisations pour accéder au conteneur ABS

    • Les autorisations minimales sont Lecture et Liste
  5. Ne pas accorder suffisamment d’autorisations au conteneur SPE

    • L’étendue requise est « User.Read » et « FileStorageContainer.Selected »
    • N’oubliez pas d’accorder le consentement de l’administrateur
    • N’oubliez pas de créer l’application de plateforme console mobile &

Test de la migration

Vérification

  1. Lorsque le fichier est mis en file d’attente, il s’imprime sur stdout
  2. Il affiche les statistiques du nombre total d’objets blob qui ont été traités : total, réussite, existe dans la destination et échec.
  3. En cas d’erreurs, il envoie la liste des objets blob ayant échoué à un fichier. Le nom de fichier sera imprimé dans stdout. Il imprime également une commande pour une réexécutation incrémentielle.

Conclusion

Résumé

Dans ce tutoriel, nous avons exploré comment migrer du contenu de ABS conteneur vers un conteneur SPE. En suivant les étapes décrites, il est facile d’écrire votre propre application pour migrer du contenu.

Pour résumer, nous :

  1. Authentifié avec ABS et Graph
  2. Comment utiliser un pool de threads pour mettre en file d’attente la migration d’un objet blob
  3. Vérifier si l’élément existe dans la destination
  4. Récupération de la liste d’objets blob à partir de ABS conteneur
  5. Chargement de l’objet blob dans le conteneur SPE

Il est essentiel de comprendre ces étapes pour migrer du contenu d’ABS conteneur vers un conteneur SPE. Maintenant, essayez d’implémenter ces étapes dans vos propres projets et voyez la différence qu’elles font !

Bonne programmation !

Étapes suivantes

Annexe

Référentiel de code

L’exemple d’application se trouve dans le référentiel d’exemples SharePoint Embedded.