web-dev-qa-db-ja.com

MS Graph SDKを使用して共有OneDriveフォルダーからDriveItemをダウンロードおよびアップロードする

現在、共有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メソッドを機能させることができませんでした。

誰かが私を正しい方向に向けることができれば、私はそれを高く評価します!ありがとうございました!

9
Romano Zumbé

リクエスト:

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

DriveItemのコンテンツをダウンロード エンドポイントに対応し、childItem.ParentReference.Idが---を参照する場合、のみが有効です File resource 、別のケースでは、予期された例外で失敗します:

Microsoft.Graph.ServiceException:コード:itemNotFoundメッセージ:フォルダーのコンテンツを取得できません

したがって、フォルダからコンテンツをダウンロードするには、解決策は次のようになります:

  • フォルダ内のアイテムを列挙:GET /drives/{drive-id}/items/{folderItem-id}/children
  • driveItemFileファセットに対応する場合、すべてのアイテムごとに明示的にコンテンツをダウンロードします: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);

    }
 }

ファイルのコンテンツをダウンロード/アップロードする代わりに、実際にはDriveItemcopy または move 操作だと思います。 1つの(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();
         }
      }
  }
3