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

Rom*_*mbé 9 c# onedrive microsoft-graph

我目前正在尝试执行一些任务,这些任务涉及从共享的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();
}
Run Code Online (Sandbox Code Playgroud)

因此,显然我需要从与另一个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
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题始于“将子项下载到路径”部分。我要在那里下载所有内容,而不是将其下载到临时文件的文件夹。问题在于,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);
}
Run Code Online (Sandbox Code Playgroud)

在另一个变体中,我尝试使用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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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);
}
Run Code Online (Sandbox Code Playgroud)

并且也这样(如果它不是共享文件夹,则可以使用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);
}
Run Code Online (Sandbox Code Playgroud)

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

如果有人能指出正确的方向,我将不胜感激!谢谢!

Vad*_*hev 7

请求:

graphClient.Drives[remoteDriveId].Items[childItem.ParentReference.Id].Content.Request().GetAsync()
Run Code Online (Sandbox Code Playgroud)

对应于下载 DriveItem 端点的内容,并且childItem.ParentReference.Id在引用File资源时才有效,在另一种情况下,它会失败并出现预期的异常:

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

    }
}
Run Code Online (Sandbox Code Playgroud)

实施例2

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

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

    }
 }
Run Code Online (Sandbox Code Playgroud)

我认为您实际上追求的是操作,而不是下载/上传文件DriveItem copy内容move。假设需要将一些文件从一个 ( ) 文件夹复制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();
         }
      }
  }
Run Code Online (Sandbox Code Playgroud)