web-dev-qa-db-fra.com

Téléchargez et téléchargez DriveItem à partir du dossier OneDrive partagé avec MS Graph SDK

J'essaie actuellement de mettre en œuvre plusieurs tâches qui impliquent la liste, le téléchargement et le téléchargement de fichiers à partir d'un dossier OneDrive partagé. Ce dossier est accessible via les utilisateurs connectés OneDrive (visible dans son dossier racine). La partie liste fonctionne assez bien jusqu'à présent, en utilisant ce code:

string remoteDriveId = string.Empty;
private GraphServiceClient graphClient { get; set; }
// Get the root of the owners OneDrive
DriveItem ownerRoot = await this.graphClient.Drive.Root.Request().Expand("thumbnails,children($expand=thumbnails)").GetAsync();
// Select the shared folders general information
DriveItem sharedFolder = ownerRoot.Children.Where(c => c.Name == "sharedFolder").FirstOrDefault();

// Check if it is a remote folder
if(sharedFolder.Remote != null)
{
    remoteDriveId = item.RemoteItem.ParentReference.DriveId;

    // Get complete Information of the shared folder
    sharedFolder = await graphClient.Drives[remoteDriveId].Items[sharedFolder.RemoteItem.Id].Request().Expand("thumbnails,children").GetAsync();
}

Donc, évidemment, je dois récupérer les informations des dossiers partagés du OneDrive qui les a partagées avec l'autre OneDrive. La partie suivante pour moi consiste à répertorier le contenu de ce dossier partagé, qui fonctionne également assez bien comme ceci:

foreach (DriveItem child in sharedFolder.Children)
{
    DriveItem childItem = await graphClient.Drives[remoteDriveId].Items[child.Id].Request().Expand("thumbnails,children").GetAsync();

    if(childItem.Folder == null)
    {
         string path = Path.GetTempPath() + Guid.NewGuid();
         // Download child item to path
    }
}

Mon problème commence avec la partie "Télécharger l'élément enfant vers le chemin". Là, je veux tout télécharger, ce n'est pas un dossier dans un fichier temporaire. Le problème est que OneDrive répond toujours à ma demande avec un message d'erreur, que le fichier est introuvable. Ce que j'ai essayé jusqu'à présent, c'est:

using (var stream = await graphClient.Drives[remoteDriveId].Items[childItem.Id].Content.Request().GetAsync())
using (var outputStream = new System.IO.FileStream(path, System.IO.FileMode.Create))
{
    await stream.CopyToAsync(outputStream);
}

Dans une autre variante, j'ai essayé d'utiliser l'ID de childItem ParentReference (mais je pense que cela ne me mènera qu'à l'ID OneDrives distant de sharedFolder):

using (var stream = await graphClient.Drives[remoteDriveId].Items[childItem.ParentReference.Id].Content.Request().GetAsync())
using (var outputStream = new System.IO.FileStream(path, System.IO.FileMode.Create))
{
    await stream.CopyToAsync(outputStream);
}

Après avoir téléchargé les fichiers, je veux les modifier et les re-télécharger vers un chemin différent dans le dossier partagé. Ce chemin est créé par moi (qui fonctionne déjà) comme ceci:

DriveItem folderToCreate = new DriveItem { Name = "folderName", Folder = new Folder() };
await graphClient.Drives[remoteDriveId].Items[sharedFolder.Id].Children.Request().AddAsync(folderToCreate);

Le téléchargement échoue alors. Je l'ai essayé comme ça:

using (var stream = new System.IO.FileStream(@"C:\temp\testfile.txt", System.IO.FileMode.Open))
{
    await graphClient.Drives[remoteDriveId].Items[sharedFolder.Id].Content.Request().PutAsync<DriveItem>(stream);
}

Et aussi comme ça (qui fonctionne si ce n'est pas un dossier partagé et j'utilise donc Drive au lieu de Drives):

using (var stream = new System.IO.FileStream(@"C:\temp\testfile.txt", System.IO.FileMode.Open))
{
    string folderPath = sharedFolder.ParentReference == null ? "" : sharedFolder.ParentReference.Path.Remove(0, 12) + "/" + Uri.EscapeUriString(sharedFolder.Name);
    var uploadPath = folderPath + "/" + uploadFileName;
    await graphClient.Drives[remoteDriveId].Root.ItemWithPath(uploadPath).Content.Request().PutAsync<DriveItem>(stream);
}

Je n'ai pas pu faire fonctionner la méthode AddAsync (comme dans la création de dossier) car je ne sais pas comment créer un DriveItem à partir d'un Stream.

Si quelqu'un pouvait m'orienter dans la bonne direction, je l'apprécierais beaucoup! Je vous remercie!

9
Romano Zumbé

La demande:

graphClient.Drives[remoteDriveId].Items[childItem.ParentReference.Id].Content.Request().GetAsync()

correspond à Télécharger le contenu d'un DriveItem endpoint et est uniquement valide si childItem.ParentReference.Id fait référence à une ressource File , dans un autre cas, elle échoue avec l'exception attendue:

Microsoft.Graph.ServiceException: Code: itemNotFound Message: vous ne pouvez pas obtenir le contenu d'un dossier

Donc, pour télécharger du contenu depuis un dossier la solution serait de:

  • énumérer les éléments dans le dossier: GET /drives/{drive-id}/items/{folderItem-id}/children
  • pour chaque élément, téléchargez explicitement son contenu si driveItem correspond à une facette File: GET /drives/{drive-id}/items/{fileItem-id}/content

Exemple

var sharedItem = await graphClient.Drives[driveId].Items[folderItemId].Request().Expand(i => i.Children).GetAsync();
foreach (var item in sharedItem.Children)
{
    if (item.File != null)
    {
        var fileContent = await graphClient.Drives[item.ParentReference.DriveId].Items[item.Id].Content.Request()
                    .GetAsync();
        using (var fileStream = new FileStream(item.Name, FileMode.Create, System.IO.FileAccess.Write))
           fileContent.CopyTo(fileStream);

    }
}

Exemple 2

L'exemple montre comment télécharger un fichier à partir d'un dossier source et le télécharger dans un dossier cible:

  var sourceDriveId = "--source drive id goes here--";
  var sourceItemFolderId = "--source folder id goes here--";
  var targetDriveId = "--target drive id goes here--";
  var targetItemFolderId = "--target folder id goes here--";

 var sourceFolder = await graphClient.Drives[sourceDriveId].Items[sourceItemFolderId].Request().Expand(i => i.Children).GetAsync();
 foreach (var item in sourceFolder.Children)
 {
    if (item.File != null)
    {
        //1. download a file as a stream
        var fileContent = await graphClient.Drives[item.ParentReference.DriveId].Items[item.Id].Content.Request()
            .GetAsync();
        //save it into file 
        //using (var fileStream = new FileStream(item.Name, FileMode.Create, System.IO.FileAccess.Write))
        //    fileContent.CopyTo(fileStream);


        //2.Upload file into target folder
        await graphClient.Drives[targetDriveId]
             .Items[targetItemFolderId]
             .ItemWithPath(item.Name)
             .Content
             .Request()
             .PutAsync<DriveItem>(fileContent);

    }
 }

Au lieu de télécharger/télécharger le contenu du fichier, je pense que ce que vous recherchez réellement est DriveItemcopy ou move opérations . Disons qu'il y a des fichiers qui doivent être - copiés d'un dossier (source) dans un autre (target), puis l'exemple suivant montre comment l'accomplir :

  var sourceDriveId = "--source drive id goes here--";
  var sourceItemFolderId = "--source folder id goes here--";
  var targetDriveId = "--target drive id goes here--";
  var targetItemFolderId = "--target folder id goes here--";

  var sourceFolder = await graphClient.Drives[sourceDriveId].Items[sourceItemFolderId].Request().Expand(i => i.Children).GetAsync();
  foreach (var item in sourceFolder.Children)
  {
      if (item.File != null)
      {
          var parentReference = new ItemReference
          {
               DriveId = targetDriveId,
               Id = targetItemFolderId
          };
          await graphClient.Drives[sourceDriveId].Items[item.Id]
              .Copy(item.Name, parentReference)
              .Request()
              .PostAsync();
         }
      }
  }
3
Vadim Gremyachev