使用MS Graph SDK从共享的OneDrive文件夹下载和上传DriveItem

时间:2019-07-15 06:51:46

标签: c# microsoft-graph onedrive

我当前正在尝试执行一些任务,这些任务涉及从共享的OneDrive文件夹列出,上传和下载文件。该文件夹可通过已登录的用户OneDrive访问(在其根文件夹中可见)。到目前为止,使用以下代码,清单部分的效果很好:

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();
}

因此,很明显,我需要从与另一个OneDrive共享的OneDrive中检索共享文件夹信息。 对我来说,下一部分是列出此共享文件夹的内容,它也可以像这样很好地工作:

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
    }
}

我的问题始于“将子项下载到路径”部分。我要在那里下载所有内容,而不是将其下载到临时文件的文件夹。问题是OneDrive始终以错误消息回答我的请求,但找不到该文件。到目前为止,我尝试过的是:

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);
}

在另一个变体中,我尝试使用childItem ParentReference的ID(但是我认为这只会导致我找到sharedFolder的远程OneDrives ID):

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);
}

下载文件后,我要编辑它们并将它们重新上传到共享文件夹中的其他路径。该路径是由我创建的(已经可以使用),如下所示:

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

然后上传失败。我已经这样尝试过了:

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);
}

也是这样(如果它不是共享文件夹,因此可以使用Drive而不是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);
}

我无法使用AddAsync方法(就像在创建文件夹中一样),因为我不知道如何从DriveItem创建Stream

如果有人可以指出正确的方向,我将非常感激!谢谢!

1 个答案:

答案 0 :(得分:3)

请求:

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

对应于Download the contents of a DriveItem端点,并且仅在childItem.ParentReference.Id引用File resource有效,在另一种情况下,它会失败并出现预期的异常:

  

Microsoft.Graph.ServiceException:代码:itemNotFound消息:您   无法获取文件夹内容

因此,要从文件夹下载内容,解决方案是:

  • 枚举文件夹GET /drives/{drive-id}/items/{folderItem-id}/children下的项目
  • 如果driveItem对应于File方面:GET /drives/{drive-id}/items/{fileItem-id}/content,每个项目都会明确下载其内容

示例

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);

    }
}

示例2

该示例演示如何从 source 文件夹下载文件并将其上传到 target 文件夹:

  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);

    }
 }

我认为您实际上所要做的是DriveItem copymove操作,而不是下载/上传文件内容。假设有一些文件需要从一个(source)文件夹中复制到另一个(target)文件夹中,然后下面的示例演示了如何实现:

  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();
         }
      }
  }