OneDrive にファイルをアップロードする - C#

C#のプログラムで、OneDriveにファイルをアップロードするコードを紹介します。

概要

C#のプログラムから、OneDriveにファイルをアップロードします。
ファイルをアップロードするには、ファイルを配置するフォルダのDriveItemオブジェクトを取得し、DriveItem オブジェクトの ItemWithPath メソッドを呼び出し、 ファイルの要素を作成します。アップロード用のストリームは、ItemWithPath メソッドの戻り値のIDriveItemRequestBuilder オブジェクトのContent.Request().PutAsync()メソッドを呼び出し、 PutAsyncメソッドのパラメータにアップロード用のストリームを与えます。

事前準備

プログラムの準備

OneDriveのAPIを呼び出すプログラムを作成する前に、アプリケーションの登録や設定が必要です。
以下の準備をする必要があります。手順の詳細はこちらの記事を参照してください。
  • Azure Active Directory へのプログラム登録
  • パブリック クライアント フローを有効にする
  • ファイルAPIのAPIアクセス許可を追加
  • APIのアクセス許可
  • Microsoft.Graph ライブラリのインストール

アップロードするファイルの準備

アップロードするファイルを準備します。プロジェクトファイルのディレクトリにテキストファイル("test.txt") を配置します。
ファイルのプロパティを変更し[出力ディレクトリにコピー]の設定を"常にコピーする"に変更します。


テキストファイルの内容は以下の通りです。

OneDrive

こちらのOneDriveのルートフォルダにアップロードします。

プログラム例

UI

下図のフォームを作成します。ボタンとMultiline プロパティを True に設定した複数行のテキストボックスを配置します。

コード

下記コードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Identity.Client;
using Microsoft.Graph;

namespace SimpleCallApi
{
  public partial class FormUpload : Form
  {
    public static IPublicClientApplication PublicClientApp;
    private string ClientId = "(クライアントID)";
    private string TenantId = "(テナントID)";

    public FormUpload()
    {
      InitializeComponent();
    }

    private async void button1_Click(object sender, EventArgs e)
    {
      PublicClientApplicationBuilder app = PublicClientApplicationBuilder.Create(ClientId);
      app = app.WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient");
      app = app.WithAuthority(AzureCloudInstance.AzurePublic, TenantId);
      PublicClientApp = app.Build();
      //
      string[] scopes = new string[] { "User.ReadWrite.All" };
      string password = "(OneDriveにサインインするアカウントのパスワード)";
      System.Security.SecureString secpass = new System.Security.SecureString();

      foreach (char c in password) secpass.AppendChar(c);

      AcquireTokenByUsernamePasswordParameterBuilder builder = PublicClientApp.AcquireTokenByUsernamePassword(scopes, "(OneDriveにサインインするアカウント)", secpass);
      AuthenticationResult authResult = await builder.ExecuteAsync();

      DelegateAuthenticationProvider prov = new DelegateAuthenticationProvider(
        (requestMessage) =>
        {
          requestMessage.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", authResult.AccessToken);
          return Task.FromResult(0);
        }
        );
      GraphServiceClient client = new GraphServiceClient(prov);

      System.IO.StreamReader reader = System.IO.File.OpenText("test.txt");
      
      DriveItem item = await client.Me.Drive.Root.ItemWithPath("upload-test.txt").Content.Request().PutAsync<DriveItem>(reader.BaseStream);

      textBox1.Text += "アップロードしました。";
    }
  }
}

解説

OneDriveのライブラリの初期化やOneDriveへのサインイン、アクセストークンの取得についてはこちらの記事を参照してください。

GraphServiceClient オブジェクトを作成します。
   GraphServiceClient client = new GraphServiceClient(prov);

AtreamReader オブジェクトを作成し、test.txt ファイルを開いてストリームを準備します。
  System.IO.StreamReader reader = System.IO.File.OpenText("test.txt");

GraphServiceClient オブジェクトのMe.Drive.Root.ItemWithPath()メソッドを呼び出します。ItemWithPathの第一引数にはアップロードして配置するファイル名を設定します。 今回は "upload-test.txt" を与えていますので、アップロードしたファイルは、OneDriveでは "upload-test.txt" の名前で配置されます。
アップロードの処理は、Contentプロパティの DriveItemオブジェクトに対して、.PutAsync<DriveItem>()メソッドを呼び出します。
PutAsync メソッドの引数にアップロードするファイルのストリームを与えます。
  DriveItem item = await client.Me.Drive.Root.ItemWithPath("upload-test.txt").Content.Request().PutAsync<DriveItem>(reader.BaseStream);

アップロード完了時にテキストボックスにメッセージを表示します。
  textBox1.Text += "アップロードしました。";

実行結果

上記のプロジェクトを実行します。下図のウィンドウが表示されます。


[button1]ボタンをクリックします。ボタンクリックから、しばらく時間が経過すると下図の「アップロードしました。」のメッセージがテキストボックスに表示されます。


メッセージ表示後OneDriveを確認します。"upload-test.txt"ファイルが追加されていることが確認できます。


"upload-test.txt" ファイルを確認します。用意したテキストファイルと同じ内容であることも確認できました。

プログラム例2 : サブフォルダにファイルをアップロードする場合

UI

下図のフォームを作成します。ボタンとMultiline プロパティを True に設定した複数行のテキストボックスを配置します。
ボタンが3つ設置されていますが、今回のプログラムでは[button3]のみを利用します。

コード

下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Identity.Client;
using Microsoft.Graph;

namespace SimpleCallApi
{
  public partial class FormUpload : Form
  {
    public static IPublicClientApplication PublicClientApp;
    private string ClientId = "(クライアントID)";
    private string TenantId = "(テナントID)";

    public FormUpload()
    {
      InitializeComponent();
    }

    private async void button3_Click(object sender, EventArgs e)
    {
      PublicClientApplicationBuilder app = PublicClientApplicationBuilder.Create(ClientId);
      app = app.WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient");
      app = app.WithAuthority(AzureCloudInstance.AzurePublic, TenantId);
      PublicClientApp = app.Build();
      //
      string[] scopes = new string[] { "User.ReadWrite.All" };
      string password = "(OneDriveにサインインするアカウントのパスワード)";
      System.Security.SecureString secpass = new System.Security.SecureString();

      foreach (char c in password) secpass.AppendChar(c);

      AcquireTokenByUsernamePasswordParameterBuilder builder = PublicClientApp.AcquireTokenByUsernamePassword(scopes, "(OneDriveにサインインするアカウント)", secpass);
      AuthenticationResult authResult = await builder.ExecuteAsync();

      DelegateAuthenticationProvider prov = new DelegateAuthenticationProvider(
        (requestMessage) =>
        {
          requestMessage.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", authResult.AccessToken);
          return Task.FromResult(0);
        }
        );
      GraphServiceClient client = new GraphServiceClient(prov);

      System.IO.StreamReader reader = System.IO.File.OpenText("test.txt");
      
      DriveItem item = await client.Me.Drive.Items["01VGRRKKKQLB2XGUSLJ5BYYUI23ZDCQCLZ"].ItemWithPath("upload-test.txt").Content.Request().PutAsync<DriveItem>(reader.BaseStream);

      textBox1.Text += "アップロードしました。";
    }
  }
}

解説

GraphServiceClient オブジェクトの取得までの処理についてはこちらの記事を参照してください。

アップロードするファイルを開き、ストリームを取得します。今回のプログラムでは、FileオブジェクトのOpenTextメソッドを呼び出して、 テキストファイルを開き、ストリームを取得しています。
    System.IO.StreamReader reader = System.IO.File.OpenText("test.txt");

アップロード先のフォルダとアップロードされる項目を指定します。アップロード先のフォルダのIDを事前取得しておく必要があります。GraphServiceClient オブジェクトの Me.Drive.Items["(アップロード先のフォルダのID)"]を指定して、アップロード先のフォルダの項目を取得します。ItemWithPath() メソッドを呼び出し、アップロードする項目を作成します。メソッドの第一引数にアップロード先のファイル名を与えます。
アップロード処理は、.Content.Request().PutAsync<DriveItem>() メソッドで実行します。PutAsync メソッドの第一引数に アップロードするファイルのストリームを与えます。
アップロードは非同期で実行されるため、await で処理の終了までメインスレッドをブロックせずに待ちます。
    DriveItem item = await client.Me.Drive.Items["01VGRRKKKQLB2XGUSLJ5BYYUI23ZDCQCLZ"].ItemWithPath("upload-test.txt").Content.Request().PutAsync<DriveItem>(reader.BaseStream);

アップロード完了後にテキストボックスにメッセージを表示します。
    textBox1.Text += "アップロードしました。";

実行結果


OneDriveのアップロード先のフォルダを確認します。下図のファイルが配置されています。


プロジェクトを実行します。下図のウィンドウが表示されます。


[button3]をクリックします。アップロード処理が実行され、テキストボックスに[アップロードしました。]のメッセージが表示されます。


OneDriveのフォルダを参照します。新しくファイルが作成されていることが確認できます。ファイル名は"upload-test.txt" となっており、コードで設定したファイル名が作成できています。


ファイルの項目をクリックして内容を確認します。準備したテキストファイルと同じ内容でアップロードされていることが確認できます。

プログラム例3 : ファイルサイズが大きいファイルの場合

ファイルサイズが大きいファイルでは、進行状況を表示したい場合があります。
サイズの大きいファイルのアップロード方法を紹介します。

アップロードファイルの準備

アップロードするファイルを準備します。今回は、下図の画像を準備します。ファイル名は "test.png" とします。


ファイルのプロパティを表示し、[出力ディレクトリにコピー]の値を "常にコピーする" に設定します。

UI

下図のフォームを作成します。
ボタンとMultilineプロパティを"True"に設定した複数行テキストボックスを配置します。(button1は配置されていますが、このプログラムでは使いません。)

コード

下記のコードを記述します。[button2]のClickイベントを実装します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Identity.Client;
using Microsoft.Graph;

namespace SimpleCallApi
{
  public partial class FormUpload : Form
  {
    public static IPublicClientApplication PublicClientApp;
    private string ClientId = "(クライアントID)";
    private string TenantId = "(テナントID)";


    public FormUpload()
    {
      InitializeComponent();
    }

    private async void button2_Click(object sender, EventArgs e)
    {
      PublicClientApplicationBuilder app = PublicClientApplicationBuilder.Create(ClientId);
      app = app.WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient");
      app = app.WithAuthority(AzureCloudInstance.AzurePublic, TenantId);
      PublicClientApp = app.Build();
      //
      string[] scopes = new string[] { "User.ReadWrite.All" };
      string password = "(OneDrive にサインインするアカウントのパスワード)";
      System.Security.SecureString secpass = new System.Security.SecureString();

      foreach (char c in password) secpass.AppendChar(c);

      AcquireTokenByUsernamePasswordParameterBuilder builder = PublicClientApp.AcquireTokenByUsernamePassword(scopes, "(OneDrive にサインインするアカウント)", secpass);
      AuthenticationResult authResult = await builder.ExecuteAsync();

      DelegateAuthenticationProvider prov = new DelegateAuthenticationProvider(
        (requestMessage) =>
        {
          requestMessage.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", authResult.AccessToken);
          return Task.FromResult(0);
        }
        );
      GraphServiceClient client = new GraphServiceClient(prov);

      System.IO.FileStream stream = System.IO.File.OpenRead("test.png");

      UploadSession session = await client.Me.Drive.Root.ItemWithPath("upload-test.png").CreateUploadSession().Request().PostAsync();

      int maxSliceSize = 320 * 1024; //320KiBの倍数の必要がある。
      LargeFileUploadTask<DriveItem> uptask = new LargeFileUploadTask<DriveItem>(session, stream, maxSliceSize);

      IProgress<long> progress = new Progress<long>(prog =>
      {
        textBox1.Text += string.Format("アップロードしました。{0} Bytes: {1} Total\r\n", prog, stream.Length);
      }
      );

      UploadResult<DriveItem> uploadResult = await uptask.UploadAsync(progress);

      if (uploadResult.UploadSucceeded) {
        textBox1.Text += string.Format("アップロードが完了しました。ID:{0}",uploadResult.ItemResponse.Id);
      }
      else {
        textBox1.Text += "アップロードに失敗しました。\r\n";
      }
    }
  }
}

解説

GraphServiceClient オブジェクトの取得までの処理についてはこちらの記事を参照してください。

アップロードするファイルのストリームを作成します。今回はFileオブジェクトのOpenReadメソッドを利用してファイルストリームを作成しています。
      System.IO.FileStream stream = System.IO.File.OpenRead("test.png");

client.Me.Drive.Root.ItemWithPath("upload-test.png") メソッドを呼び出して、アップロードするファイルの項目を作成します。
ItemWithPathメソッドで取得される、IDriveItemRequestBuilderオブジェクトのCreateUploadSession() メソッドを呼び出し、アップロード用のUploadSession オブジェクトを取得します。
オブジェクトは非同期で取得するため、.Request().PostAsync(); メソッドを呼び出して取得します。
      UploadSession session = await client.Me.Drive.Root.ItemWithPath("upload-test.png").CreateUploadSession().Request().PostAsync();

ファイルアップロードのタスク LargeFileUploadTask オブジェクトを作成します。コンストラクタの第一引数には先に作成した、UploadSession オブジェクトを与えます。 第二引数にアップロードするファイルのストリームを、第三引数にスライスの最大サイズを与えます。スライスのサイズは、320KBの倍数にする必要があります。
      int maxSliceSize = 320 * 1024; //320KiBの倍数の必要がある。
      LargeFileUploadTask<DriveItem> uptask = new LargeFileUploadTask<DriveItem>(session, stream, maxSliceSize);

進行状況を検出するIProgressオブジェクトを作成します。
コンストラクタの第一引数にに進行状況に応じて呼び出されるデリゲートを与えます。 下記のコードではデリゲートをラムダ式で記述しています。
デリゲート内では、テキストボックスにメッセージを表示するコードを記述しています。
      IProgress<long> progress = new Progress<long>(prog =>
      {
        textBox1.Text += string.Format("アップロードしました。{0} Bytes: {1} Total\r\n", prog, stream.Length);
      }
      );

アップロードを実行します。アップロードは先に作成した、LargeFileUploadTask オブジェクトの UploadAsync メソッドを呼び出すことで実行できます。 UploadAsync メソッドの第一引数に進行状況を検出するIProgressオブジェクトを与えます。
アップロードが進むごとに、IProgressオブジェクトのコンストラクタに与えたデリゲートのメソッドが呼び出されます。
      UploadResult<DriveItem> uploadResult = await uptask.UploadAsync(progress);

アップロード完了後、UploadResult オブジェクトの UploadSucceeded プロパティの値を参照してアップロードが成功したか失敗したかを判定できます。 アップロードの成功、失敗のメッセージをテキストボックスに表示します。
      if (uploadResult.UploadSucceeded) {
        textBox1.Text += string.Format("アップロードが完了しました。ID:{0}",uploadResult.ItemResponse.Id);
      }
      else {
        textBox1.Text += "アップロードに失敗しました。\r\n";
      }

実行結果

アップロード前のOneDriveのルートディレクトリです。


プロジェクトを実行します。下図のウィンドウが表示されます。


[button2]ボタンをクリックします。メッセージが表示され、アップロードが実行されます。 アップロードが完了するとアップロード完了のメッセージと、アップロードされたOneDriveのファイルのIDがテキストボックスに表示されます。


OneDrive のルートディレクトリを確認します。新しく"upload-test.png" ファイルが追加されていることが確認できます。~

"upload-test.png" ファイルを開きます。準備した画像ファイルがアップロードできていることが確認できます。

実行結果:大きなファイル

大きなファイルの場合、スライスのサイズアップロードされるごとに、メッセージがテキストボックスに表示されます。



著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2022-12-14
作成日: 2021-06-09
iPentec all rights reserverd.