C#でSharePointを操作する方法|CSOM・Graph APIの使い方と実装例

はじめに

C#でSharePointを操作できるようになると、リストデータの取得・更新、ドキュメントライブラリへのファイルアップロード、社内システムとのデータ連携、定期バッチ処理などを自動化できます。特にSharePoint OnlineをMicrosoft 365の業務基盤として利用している企業では、C#アプリケーションからSharePointに接続してデータを扱うニーズが多くあります。

C#からSharePointを操作する代表的な方法には、CSOM(Client-Side Object Model)とMicrosoft Graph APIがあります。CSOMはSharePoint固有の操作に強く、既存のSharePoint向け実装でもよく使われます。一方、Microsoft Graph APIはSharePointだけでなく、Teams、OneDrive、Outlook、ユーザー情報などMicrosoft 365全体を統一的に扱えるAPIです。

この記事では、C#でSharePointを操作する方法を、CSOMとMicrosoft Graph APIの両方から解説します。SharePointリストの取得・追加・更新・削除、ドキュメントライブラリのファイル操作、認証設定、エラー対処、実運用での注意点まで、実装例を交えて整理します。

1. C#でSharePointを操作する前に知っておきたい基礎

1-1. C#からSharePointを操作する主な方法

C#からSharePointを操作する方法には、主に次の選択肢があります。

1つ目はCSOMです。CSOMはSharePointのクライアント側オブジェクトモデルで、ClientContextWebListListItemFolderFileなどのクラスを使ってSharePointサイト、リスト、ファイルを操作します。Microsoftのドキュメントでも、CSOMを使ってSharePointのデータを取得・更新・管理できることが説明されています。Microsoft Learn

2つ目はMicrosoft Graph APIです。Graph APIはMicrosoft 365全体にアクセスするためのREST APIで、SharePointサイト、リスト、リストアイテム、ドライブ、ファイルなどを操作できます。SharePointのファイルやフォルダーはGraph API上では主にdriveItemとして扱われ、SharePointドキュメントライブラリ内のファイルもdriveItemまたはlistItemとして表現できます。Microsoft Learn

3つ目はSharePoint REST APIです。HTTPベースでSharePointにアクセスする方法ですが、C#アプリケーションではCSOMまたはMicrosoft Graph APIを使うケースが多いため、この記事ではCSOMとGraph APIを中心に解説します。

1-2. CSOMとMicrosoft Graph APIの違い

CSOMはSharePointに特化したAPIです。SharePointリスト、サイト、Web、ライブラリ、フォルダー、権限、コンテンツタイプなど、SharePoint固有の操作を細かく扱いやすい点が特徴です。既存のSharePoint連携システムや、SharePoint固有機能を深く操作したい場合に向いています。

Microsoft Graph APIは、SharePointをMicrosoft 365の一部として扱うAPIです。SharePointだけでなく、OneDrive、Teams、Outlook、ユーザー、グループなどと一貫した認証・エンドポイントで連携できます。新規開発では、Microsoft 365全体との連携やクラウドネイティブな構成を考慮して、Graph APIを優先するケースが増えています。

大きな違いは、操作対象の範囲と設計思想です。CSOMはSharePoint中心、Graph APIはMicrosoft 365全体中心です。たとえば、SharePointリストを細かく操作するならCSOM、Teamsやユーザー情報とSharePointファイルをまとめて扱うならGraph APIが適しています。

1-3. SharePoint OnlineとSharePoint Serverで使えるAPIの違い

SharePoint Onlineでは、CSOM、Microsoft Graph API、SharePoint REST APIを利用できます。ただし、認証はMicrosoft Entra IDを使ったOAuthベースの先進認証が基本です。CSOM for .NET Standardでは、従来のSharePointOnlineCredentialsによるユーザー名・パスワード認証は利用できず、OAuthアクセストークンを取得してSharePoint Onlineへ渡す必要があります。Microsoft Learn

一方、オンプレミスのSharePoint Serverでは、Graph APIで操作できる範囲はSharePoint Onlineほど広くありません。CSOMの.NET Framework版やSharePoint REST APIを利用するケースが中心です。Microsoftのドキュメントでも、CSOM for .NET StandardはオンプレミスSharePointをサポートせず、オンプレミス開発では.NET Framework版CSOMを使う方針が示されています。Microsoft Learn

そのため、C#でSharePointを操作する際は、対象がSharePoint OnlineなのかSharePoint Serverなのかを最初に確認することが重要です。

1-4. この記事で実装する操作内容

この記事では、C#でSharePointを操作するために、次の内容を実装します。

CSOMでは、SharePoint Onlineへの接続、リスト一覧の取得、リストアイテムの取得・追加・更新・削除、CAML Queryによる条件検索、ドキュメントライブラリのファイル一覧取得、ファイルアップロード、ダウンロード、フォルダー作成、メタデータ更新を扱います。

Microsoft Graph APIでは、アプリ登録、APIアクセス許可、Graph SDKの導入、SharePointサイト情報の取得、リスト操作、リストアイテム操作、ドキュメントライブラリ内のファイル取得、アップロード、ダウンロード、driveItemを使ったファイル操作を扱います。

2. C#でSharePointを操作する開発環境の準備

2-1. 必要なツールと前提条件

C#でSharePointを操作するには、次の環境を用意します。

開発環境としてはVisual StudioまたはVisual Studio Codeを利用します。プロジェクトは.NET 6以降、または既存環境に合わせて.NET Frameworkを選択します。SharePoint Onlineを対象にする場合は、Microsoft 365テナント、SharePointサイト、操作対象のリストまたはドキュメントライブラリが必要です。

Graph APIを使う場合は、Microsoft Entra IDでアプリ登録を行い、クライアントID、テナントID、クライアントシークレットまたは証明書を用意します。Microsoft Graphのアプリ専用認証では、ClientSecretCredentialを使ってhttps://graph.microsoft.com/.defaultスコープのトークンを取得する構成が公式チュートリアルでも紹介されています。 Microsoft Learn

CSOMを使う場合は、Microsoft.SharePointOnline.CSOMをNuGetでインストールします。認証処理を簡略化したい場合は、PnP FrameworkのAuthenticationManagerを利用する方法もあります。PnP FrameworkのAuthenticationManagerは、認証済みのCSOM ClientContextを取得するためのクラスです。pnp

2-2. Visual StudioでC#プロジェクトを作成する

Visual StudioでC#プロジェクトを作成する場合は、コンソールアプリを選ぶと検証しやすくなります。

プロジェクト作成時は、次のような構成にしておくと管理しやすいです。

SharePointCsomSample
├─ Program.cs
├─ appsettings.json
└─ Services
├─ CsomService.cs
└─ GraphSharePointService.cs

接続情報をソースコードに直接書くと、Gitなどに誤って認証情報を公開するリスクがあります。そのため、開発時はappsettings.json、ユーザーシークレット、環境変数などを使い、本番環境ではAzure Key Vaultなどのシークレット管理サービスを利用するのが望ましいです。

2-3. NuGetで必要なライブラリをインストールする

CSOMを使う場合は、次のパッケージをインストールします。

PowerShell
Install-Package Microsoft.SharePointOnline.CSOM

認証処理にPnP Frameworkを使う場合は、次のパッケージも追加します。

PowerShell
Install-Package PnP.Framework

Microsoft Graph APIを使う場合は、次のパッケージをインストールします。

PowerShell
Install-Package Microsoft.Graph
Install-Package Azure.Identity

Graph SDKを使うと、REST APIを直接組み立てなくても、GraphServiceClientからSharePointサイト、リスト、ファイルへアクセスできます。Microsoft Graph SDKのクライアントは、Graph APIを簡単に呼び出すためのクライアントとして説明されています。Microsoft Learn

2-4. SharePointサイトURL・テナント情報を確認する

SharePoint連携では、次の情報を事前に確認しておきます。

SharePointサイトURL:
https://contoso.sharepoint.com/sites/dev

テナントID:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

クライアントID:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

クライアントシークレット:
開発環境ではユーザーシークレットや環境変数に保存

ホスト名:
contoso.sharepoint.com

サイトパス:
sites/dev

Graph APIでサイトを取得する場合、サイトIDだけでなく、ホスト名とサーバー相対パスを使ってサイトを取得できます。たとえば/sites/{hostname}:/{server-relative-path}という形式でSharePointサイトにアクセスできます。Microsoft Learn

3. CSOMを使ってC#からSharePointへ接続する方法

3-1. CSOMとは

CSOMはClient-Side Object Modelの略で、C#などのクライアントアプリケーションからSharePointを操作するためのライブラリです。サーバー側で直接SharePointオブジェクトモデルを実行するのではなく、クライアント側からリクエストを組み立て、ExecuteQuery()でSharePointへ送信します。

CSOMでは、ClientContextを中心に操作します。ClientContextはSharePointサイトへの接続情報とリクエストの実行単位を管理します。リストやファイルを取得する場合も、まずClientContextを作成し、対象オブジェクトをLoad()してからExecuteQuery()で実際に通信します。

3-2. CSOMで利用する主要クラス

CSOMでよく使う主要クラスは次のとおりです。

クラス役割
ClientContextSharePointサイトへの接続とリクエスト実行を管理する
WebSharePointサイト内のWebを表す
ListSharePointリストまたはドキュメントライブラリを表す
ListItemリスト内の1件のアイテムを表す
CamlQueryCAMLを使ってリストアイテムを条件検索する
FolderSharePoint上のフォルダーを表す
FileSharePoint上のファイルを表す
FileCreationInformationファイルアップロード時の情報を表す

CSOMでは、プロパティを参照する前にcontext.Load()で取得対象を指定し、context.ExecuteQuery()を呼び出す必要があります。これはCSOM初心者がつまずきやすいポイントです。

3-3. SharePoint Onlineへ認証する方法

SharePoint Onlineでは、現在はMicrosoft Entra IDを使ったOAuthベースの認証を前提に考えるべきです。CSOM for .NET Standardでは、従来のSharePointOnlineCredentialsによる認証は利用できず、OAuthアクセストークンを取得してCSOMリクエストに付与する必要があります。Microsoft Learn

実装方法は大きく分けて2つあります。

1つは、MSALを使ってアクセストークンを取得し、ClientContext.ExecutingWebRequestでAuthorizationヘッダーにBearerトークンを付与する方法です。

もう1つは、PnP FrameworkのAuthenticationManagerを使って、認証済みのClientContextを取得する方法です。PnP Frameworkには証明書認証、デバイスログイン、対話型ログインなどに対応したメソッドが用意されています。pnp+1

本番運用では、クライアントシークレットよりも証明書認証やマネージドIDを検討するのが安全です。特にサーバーサイドのバッチや常駐サービスでは、ユーザー名とパスワードを使った認証は避けるべきです。

3-4. ClientContextを使った接続サンプル

ここでは、PnP Frameworkを使って証明書認証でClientContextを取得する例を示します。

C#
using Microsoft.SharePoint.Client;
using PnP.Framework;

var siteUrl = "https://contoso.sharepoint.com/sites/dev";
var tenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var clientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var certificatePath = @"C:\certs\sharepoint-app.pfx";
var certificatePassword = "certificate-password";

using var authManager = AuthenticationManager.CreateWithCertificate(
clientId,
certificatePath,
certificatePassword,
tenantId
);

using var context = authManager.GetContext(siteUrl);

context.Load(context.Web, web => web.Title, web => web.Url);
context.ExecuteQuery();

Console.WriteLine($"Title: {context.Web.Title}");
Console.WriteLine($"Url: {context.Web.Url}");

このコードでは、AuthenticationManagerで認証済みのClientContextを取得し、SharePointサイトのタイトルとURLを読み込んでいます。context.Load()で取得するプロパティを指定し、context.ExecuteQuery()でSharePointにリクエストを送信する流れがCSOMの基本です。

3-5. CSOMを使うメリット・デメリット

CSOMのメリットは、SharePoint固有の操作に強いことです。リスト、ビュー、CAML Query、ファイル、フォルダー、メタデータなど、SharePointの概念をそのままC#のオブジェクトとして扱えます。既存のSharePoint向けC#コードがある場合も、CSOMの知識を活かしやすいです。

一方で、CSOMはSharePoint中心のAPIです。Microsoft 365全体のユーザー、Teams、メール、カレンダーなどと統合的に扱うにはMicrosoft Graph APIの方が向いています。また、認証方式の移行や.NET Standard対応の違いに注意が必要です。たとえばCSOM for .NET StandardではSharePointOnlineCredentialsが使えないため、OAuthベースの認証設計が必須になります。Microsoft Learn

4. CSOMでSharePointリストを操作する実装例

4-1. SharePointリストの一覧を取得する

SharePointサイト内のリスト一覧を取得するには、context.Web.Listsを読み込みます。

C#
using Microsoft.SharePoint.Client;

var lists = context.Web.Lists;

context.Load(
lists,
collection => collection.Include(
list => list.Title,
list => list.Id,
list => list.BaseTemplate,
list => list.Hidden
)
);

context.ExecuteQuery();

foreach (var list in lists)
{
Console.WriteLine($"{list.Title} / {list.Id} / Template: {list.BaseTemplate}");
}

Hiddentrueのリストには、システム内部で使われるリストが含まれることがあります。業務リストだけを表示したい場合は、Hidden == falseで絞り込むとよいでしょう。

4-2. リストアイテムを取得する

特定のリストからアイテムを取得するには、GetByTitle()でリストを取得し、CamlQuery.CreateAllItemsQuery()を使います。

C#
using Microsoft.SharePoint.Client;

var list = context.Web.Lists.GetByTitle("Tasks");
var query = CamlQuery.CreateAllItemsQuery(100);

var items = list.GetItems(query);

context.Load(items);
context.ExecuteQuery();

foreach (var item in items)
{
Console.WriteLine($"ID: {item.Id}");
Console.WriteLine($"Title: {item["Title"]}");
}

SharePointリストでは、画面に表示される列名と内部名が異なる場合があります。C#から値を取得するときは、基本的に内部名を使います。たとえば「タイトル」列は多くの場合Titleです。

4-3. リストアイテムを追加する

リストアイテムを追加するには、ListItemCreationInformationを作成し、list.AddItem()を呼び出します。

C#
using Microsoft.SharePoint.Client;

var list = context.Web.Lists.GetByTitle("Tasks");

var itemCreateInfo = new ListItemCreationInformation();
var item = list.AddItem(itemCreateInfo);

item["Title"] = "C#から追加したタスク";
item["Status"] = "未着手";

item.Update();
context.ExecuteQuery();

Console.WriteLine($"Created Item ID: {item.Id}");

選択肢列、ユーザー列、ルックアップ列、日付列などは、列の種類に応じて設定方法が異なります。まずはテキスト列や数値列で動作を確認し、その後に列タイプごとの実装を追加すると安全です。

4-4. リストアイテムを更新する

既存アイテムを更新するには、GetItemById()で対象アイテムを取得し、列値を変更してUpdate()を呼び出します。

C#
using Microsoft.SharePoint.Client;

var list = context.Web.Lists.GetByTitle("Tasks");
var item = list.GetItemById(1);

item["Title"] = "C#から更新したタスク";
item["Status"] = "対応中";

item.Update();
context.ExecuteQuery();

Console.WriteLine("Item updated.");

複数人で同じリストを更新する場合は、更新競合に注意が必要です。重要な業務データでは、更新前に現在値を取得し、意図しない上書きが起きないように設計しましょう。

4-5. リストアイテムを削除する

リストアイテムを削除するには、対象アイテムに対してDeleteObject()を呼び出します。

C#
using Microsoft.SharePoint.Client;

var list = context.Web.Lists.GetByTitle("Tasks");
var item = list.GetItemById(1);

item.DeleteObject();
context.ExecuteQuery();

Console.WriteLine("Item deleted.");

削除処理は取り消しが難しい場合があります。実運用では、物理削除ではなく「削除フラグ」列を用意して論理削除にする設計も検討してください。

4-6. CAML Queryで条件指定してデータを取得する

CAML Queryを使うと、SharePointリストに対して条件を指定してアイテムを取得できます。CAMLのQueryスキーマは、SharePointのリストデータに対するクエリ定義に使われます。Microsoft Learn

C#
using Microsoft.SharePoint.Client;

var list = context.Web.Lists.GetByTitle("Tasks");

var query = new CamlQuery
{
ViewXml = @"
<View>
<Query>
<Where>
<Eq>
<FieldRef Name='Status' />
<Value Type='Text'>未着手</Value>
</Eq>
</Where>
<OrderBy>
<FieldRef Name='ID' Ascending='FALSE' />
</OrderBy>
</Query>
<RowLimit>100</RowLimit>
</View>"
};

var items = list.GetItems(query);

context.Load(items);
context.ExecuteQuery();

foreach (var item in items)
{
Console.WriteLine($"{item.Id}: {item["Title"]} / {item["Status"]}");
}

大量データを扱う場合は、RowLimitを設定し、必要に応じてページング処理を実装します。SharePointリストにはしきい値があるため、条件列にはインデックスを設定しておくと安定しやすくなります。

5. CSOMでSharePointドキュメントライブラリを操作する実装例

5-1. ドキュメントライブラリのファイル一覧を取得する

ドキュメントライブラリは、CSOMではListとして扱えます。ファイル一覧を取得するには、ライブラリのRootFolder.Filesを読み込みます。

C#
using Microsoft.SharePoint.Client;

var library = context.Web.Lists.GetByTitle("Documents");
var rootFolder = library.RootFolder;

context.Load(
rootFolder.Files,
files => files.Include(
file => file.Name,
file => file.ServerRelativeUrl,
file => file.Length,
file => file.TimeLastModified
)
);

context.ExecuteQuery();

foreach (var file in rootFolder.Files)
{
Console.WriteLine($"{file.Name} / {file.Length} bytes / {file.ServerRelativeUrl}");
}

フォルダー配下のファイルを取得する場合は、GetFolderByServerRelativeUrl()で対象フォルダーを取得してからFilesを読み込みます。

5-2. C#からファイルをアップロードする

CSOMでファイルをアップロードするには、FileCreationInformationを使います。

C#
using Microsoft.SharePoint.Client;

var localPath = @"C:\temp\sample.pdf";
var fileName = Path.GetFileName(localPath);

var targetFolder = context.Web.GetFolderByServerRelativeUrl(
"/sites/dev/Shared Documents"
);

using var stream = new FileStream(localPath, FileMode.Open, FileAccess.Read);

var fileInfo = new FileCreationInformation
{
ContentStream = stream,
Url = fileName,
Overwrite = true
};

var uploadedFile = targetFolder.Files.Add(fileInfo);

context.Load(uploadedFile, file => file.ServerRelativeUrl);
context.ExecuteQuery();

Console.WriteLine($"Uploaded: {uploadedFile.ServerRelativeUrl}");

ServerRelativeUrlは、/sites/dev/Shared Documents/sample.pdfのように、SharePointホスト名を除いたパスで指定します。URLエンコードや日本語ファイル名を扱う場合は、実際のライブラリ名とパスを確認してから実装してください。

5-3. SharePoint上のファイルをダウンロードする

CSOMでファイルをダウンロードするには、OpenBinaryStream()を使います。

C#
using Microsoft.SharePoint.Client;

var serverRelativeUrl = "/sites/dev/Shared Documents/sample.pdf";
var downloadPath = @"C:\temp\downloaded-sample.pdf";

var file = context.Web.GetFileByServerRelativeUrl(serverRelativeUrl);
var streamResult = file.OpenBinaryStream();

context.ExecuteQuery();

using var fileStream = new FileStream(downloadPath, FileMode.Create, FileAccess.Write);
streamResult.Value.CopyTo(fileStream);

Console.WriteLine("Downloaded.");

CSOM for .NET Standardでは、従来のSaveBinaryDirectOpenBinaryDirectは利用できないため、通常のファイルAPIを使う必要があります。Microsoftのドキュメントでも、.NET Standard版CSOMではSaveBinaryDirect / OpenBinaryDirect APIが使えないことが示されています。Microsoft Learn

5-4. ファイルやフォルダーを作成・削除する

フォルダーを作成するには、対象ライブラリのRootFolder.Folders.Add()を使います。

C#
using Microsoft.SharePoint.Client;

var library = context.Web.Lists.GetByTitle("Documents");
var folder = library.RootFolder.Folders.Add("Reports");

folder.Update();
context.ExecuteQuery();

Console.WriteLine("Folder created.");

ファイルを削除するには、GetFileByServerRelativeUrl()でファイルを取得し、DeleteObject()を呼び出します。

C#
using Microsoft.SharePoint.Client;

var file = context.Web.GetFileByServerRelativeUrl(
"/sites/dev/Shared Documents/old-file.pdf"
);

file.DeleteObject();
context.ExecuteQuery();

Console.WriteLine("File deleted.");

フォルダー削除も同様に、対象フォルダーを取得してDeleteObject()を呼び出します。

C#
using Microsoft.SharePoint.Client;

var folder = context.Web.GetFolderByServerRelativeUrl(
"/sites/dev/Shared Documents/Reports"
);

folder.DeleteObject();
context.ExecuteQuery();

Console.WriteLine("Folder deleted.");

5-5. ファイルのメタデータを更新する

ドキュメントライブラリのファイルには、リストアイテムと同じようにメタデータ列を設定できます。CSOMでは、ファイルのListItemAllFieldsから列値を更新します。

C#
using Microsoft.SharePoint.Client;

var file = context.Web.GetFileByServerRelativeUrl(
"/sites/dev/Shared Documents/sample.pdf"
);

context.Load(file, f => f.ListItemAllFields);
context.ExecuteQuery();

var item = file.ListItemAllFields;

item["Title"] = "サンプル資料";
item["Category"] = "営業資料";

item.Update();
context.ExecuteQuery();

Console.WriteLine("Metadata updated.");

ドキュメントライブラリでメタデータ管理を行う場合は、アップロード直後にファイルのメタデータを更新する流れがよく使われます。ファイル本体とメタデータ更新を一連の処理としてログに残しておくと、運用時の調査がしやすくなります。

6. Microsoft Graph APIを使ってC#からSharePointを操作する方法

6-1. Microsoft Graph APIとは

Microsoft Graph APIは、Microsoft 365のデータにアクセスするための統一APIです。SharePointサイト、リスト、リストアイテム、ドキュメントライブラリ、OneDrive、Teams、ユーザー、グループなどを同じ認証基盤で操作できます。

SharePoint連携では、サイトはsite、リストはlist、リストアイテムはlistItem、ファイルやフォルダーはdriveItemとして扱います。Graph APIでは、SharePointドキュメントライブラリ内のファイルもdriveItemとして操作できるため、ファイルアップロードやダウンロードを実装しやすいです。Microsoft Learn

6-2. Azure Entra IDでアプリ登録を行う

Graph APIをC#から使うには、Microsoft Entra IDでアプリ登録を行います。

Microsoft Entra管理センターで「アプリの登録」を開き、「新規登録」を選択します。アプリ名を入力し、利用するアカウントの種類を選びます。サーバーサイドのバッチやAPI連携で使う場合は、シングルテナント構成にすることが多いです。

登録後、アプリケーションの概要画面でクライアントIDとテナントIDを確認します。これらはC#コードでGraphServiceClientを初期化するときに使用します。

6-3. APIアクセス許可を設定する

SharePointをGraph APIで操作するには、必要なAPIアクセス許可を設定します。たとえばリストアイテムを作成する場合、Microsoft Graphの公式ドキュメントでは、アプリケーション権限の最小権限としてSites.ReadWrite.Allが示されています。Microsoft Learn

ただし、Sites.ReadWrite.Allはテナント内の広い範囲のSharePointサイトにアクセスできる強い権限です。最小権限を重視する場合は、Sites.Selectedなどの選択的な権限も検討します。Microsoft Graphには、OneDriveやSharePointに対して選択されたスコープを使い、特定リソース単位でより細かく同意を管理する仕組みがあります。Microsoft Learn

開発初期は検証しやすさを優先して広めの権限を使うこともありますが、本番運用では必要最小限の権限に絞ることが重要です。

6-4. クライアントID・テナントID・シークレットを取得する

アプリ登録後、次の情報を取得します。

TenantId: Microsoft Entra IDのテナントID
ClientId: アプリケーションID
ClientSecret: クライアントシークレット

クライアントシークレットは一度しか表示されないため、作成直後に安全な場所へ保存します。ソースコードに直接書かず、環境変数、ユーザーシークレット、Azure Key Vaultなどで管理します。

開発用のappsettings.jsonに書く場合でも、Git管理から除外するか、ユーザーシークレットへ移すべきです。

6-5. Microsoft Graph SDKをC#プロジェクトに導入する

Graph SDKを使うには、次のNuGetパッケージを追加します。

PowerShell
Install-Package Microsoft.Graph
Install-Package Azure.Identity

C#コードでは、ClientSecretCredentialを作成し、GraphServiceClientに渡します。

C#
using Azure.Identity;
using Microsoft.Graph;

var tenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var clientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var clientSecret = "client-secret";

var credential = new ClientSecretCredential(
tenantId,
clientId,
clientSecret
);

var scopes = new[] { "https://graph.microsoft.com/.default" };

var graphClient = new GraphServiceClient(credential, scopes);

https://graph.microsoft.com/.defaultは、アプリ登録で同意済みのアプリケーション権限を使ってトークンを取得するためのスコープです。Microsoft Graphのアプリ専用認証チュートリアルでも、ClientSecretCredential.defaultスコープを使う例が紹介されています。Microsoft Learn

6-6. Graph APIでSharePointへ接続するサンプル

SharePointサイトに接続するには、まずサイト情報を取得します。

C#
using Azure.Identity;
using Microsoft.Graph;

var tenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var clientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var clientSecret = "client-secret";

var credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(
credential,
new[] { "https://graph.microsoft.com/.default" }
);

var hostName = "contoso.sharepoint.com";
var sitePath = "sites/dev";

var site = await graphClient
.Sites[$"{hostName}:/{sitePath}"]
.GetAsync();

Console.WriteLine($"Site ID: {site?.Id}");
Console.WriteLine($"Site Name: {site?.Name}");
Console.WriteLine($"Web URL: {site?.WebUrl}");

Graph APIでは、SharePointサイトIDを取得しておくと、その後のリスト操作やファイル操作で使いやすくなります。

7. Graph APIでSharePointサイト・リスト・ファイルを操作する実装例

7-1. SharePointサイト情報を取得する

Graph APIでサイト情報を取得するには、サイトID、またはホスト名とサイトパスを使います。

C#
var hostName = "contoso.sharepoint.com";
var sitePath = "sites/dev";

var site = await graphClient
.Sites[$"{hostName}:/{sitePath}"]
.GetAsync();

var siteId = site?.Id;

Console.WriteLine(siteId);
Console.WriteLine(site?.DisplayName);
Console.WriteLine(site?.WebUrl);

Graph APIでは、ルートサイト、サイトID、サーバー相対URLなど複数の形式でSharePointサイトを取得できます。公式ドキュメントでは、テナントのルートサイトやサーバー相対URLによる取得方法が示されています。Microsoft Learn

7-2. サイト内のリストを取得する

サイト内のリスト一覧を取得するには、Sites[siteId].Lists.GetAsync()を使います。

C#
var lists = await graphClient
.Sites[siteId]
.Lists
.GetAsync();

foreach (var list in lists?.Value ?? [])
{
Console.WriteLine($"{list.DisplayName} / {list.Id}");
}

ドキュメントライブラリもSharePoint上ではリストの一種ですが、Graph APIでファイル操作を行う場合はdriveまたはdriveItemとして扱う方が自然です。

7-3. リストアイテムを取得・追加・更新・削除する

リストアイテムを取得するには、Expand = ["fields"]を指定すると列値を取得できます。

C#
var listId = "list-id";

var items = await graphClient
.Sites[siteId]
.Lists[listId]
.Items
.GetAsync(request =>
{
request.QueryParameters.Expand = new[] { "fields" };
});

foreach (var item in items?.Value ?? [])
{
var fields = item.Fields?.AdditionalData;

Console.WriteLine($"ID: {item.Id}");

if (fields != null && fields.TryGetValue("Title", out var title))
{
Console.WriteLine($"Title: {title}");
}
}

リストアイテムを追加するには、ListItemFieldsFieldValueSetを設定します。Graph APIの公式ドキュメントでも、fieldsTitleや任意の列値を指定してリストアイテムを作成する例が示されています。Microsoft Learn

C#
using Microsoft.Graph.Models;

var newItem = new ListItem
{
Fields = new FieldValueSet
{
AdditionalData = new Dictionary<string, object>
{
{ "Title", "Graph APIから追加" },
{ "Status", "未着手" }
}
}
};

var createdItem = await graphClient
.Sites[siteId]
.Lists[listId]
.Items
.PostAsync(newItem);

Console.WriteLine($"Created: {createdItem?.Id}");

リストアイテムを更新するには、対象アイテムのfieldsに対してPATCHします。Graph APIでは、PATCH /sites/{site-id}/lists/{list-id}/items/{item-id}/fieldsで指定した列だけを更新できます。Microsoft Learn

C#
using Microsoft.Graph.Models;

var itemId = "1";

var updateFields = new FieldValueSet
{
AdditionalData = new Dictionary<string, object>
{
{ "Status", "完了" },
{ "Title", "Graph APIから更新" }
}
};

await graphClient
.Sites[siteId]
.Lists[listId]
.Items[itemId]
.Fields
.PatchAsync(updateFields);

Console.WriteLine("Updated.");

リストアイテムを削除するには、対象アイテムに対してDeleteAsync()を呼び出します。

C#
var itemId = "1";

await graphClient
.Sites[siteId]
.Lists[listId]
.Items[itemId]
.DeleteAsync();

Console.WriteLine("Deleted.");

Graph APIで列を扱う場合も、SharePoint列の内部名を使う点に注意してください。表示名に日本語を使っている場合、内部名が_x65e5__x672c_のような形式になっていることがあります。

7-4. ドキュメントライブラリ内のファイルを取得する

SharePointサイトの既定ドキュメントライブラリは、Graph APIではdriveとして扱えます。ルート直下のファイルやフォルダーを取得するには、Drive.Root.Childrenを使います。

C#
var children = await graphClient
.Sites[siteId]
.Drive
.Root
.Children
.GetAsync();

foreach (var item in children?.Value ?? [])
{
Console.WriteLine($"{item.Name} / {item.Id} / {item.WebUrl}");
}

特定フォルダー配下のファイルを取得したい場合は、ItemWithPath()を使います。

C#
var folderItems = await graphClient
.Sites[siteId]
.Drive
.Root
.ItemWithPath("Reports")
.Children
.GetAsync();

foreach (var item in folderItems?.Value ?? [])
{
Console.WriteLine($"{item.Name} / {item.Size}");
}

Graph APIのフォルダー配下取得APIでは、対象アイテムのchildrenコレクションとしてdriveItem一覧が返されます。Microsoft Learn

7-5. ファイルをアップロード・ダウンロードする

小さなファイルをアップロードする場合は、Content.PutAsync()を使います。Graph APIでは、単一リクエストでアップロードできるファイルサイズは最大250MBです。大きなファイルではアップロードセッションを使います。Microsoft Learn

C#
var localPath = @"C:\temp\sample.txt";
var targetPath = "Reports/sample.txt";

using var uploadStream = new FileStream(localPath, FileMode.Open, FileAccess.Read);

var uploaded = await graphClient
.Sites[siteId]
.Drive
.Root
.ItemWithPath(targetPath)
.Content
.PutAsync(uploadStream);

Console.WriteLine($"Uploaded: {uploaded?.WebUrl}");

ファイルをダウンロードするには、対象のdriveItemContent.GetAsync()を使います。

C#
var targetPath = "Reports/sample.txt";
var downloadPath = @"C:\temp\downloaded-sample.txt";

var downloadStream = await graphClient
.Sites[siteId]
.Drive
.Root
.ItemWithPath(targetPath)
.Content
.GetAsync();

using var fileStream = new FileStream(downloadPath, FileMode.Create, FileAccess.Write);
await downloadStream!.CopyToAsync(fileStream);

Console.WriteLine("Downloaded.");

大きなファイルをアップロードする場合は、アップロードセッションを作成し、分割アップロードを行います。Graph APIのアップロードセッションは、ファイルを範囲ごとにアップロードでき、接続が切断された場合の再開にも対応します。Microsoft Learn

C#
using Microsoft.Graph.Drives.Item.Items.Item.CreateUploadSession;
using Microsoft.Graph.Models;

var largeFilePath = @"C:\temp\large-video.mp4";
var uploadPath = "Reports/large-video.mp4";

var uploadSessionRequestBody = new CreateUploadSessionPostRequestBody
{
Item = new DriveItemUploadableProperties
{
AdditionalData = new Dictionary<string, object>
{
{ "@microsoft.graph.conflictBehavior", "replace" }
}
}
};

var uploadSession = await graphClient
.Sites[siteId]
.Drive
.Root
.ItemWithPath(uploadPath)
.CreateUploadSession
.PostAsync(uploadSessionRequestBody);

var maxSliceSize = 320 * 1024;
using var fileStream = new FileStream(largeFilePath, FileMode.Open, FileAccess.Read);

var uploadTask = new LargeFileUploadTask<DriveItem>(
uploadSession,
fileStream,
maxSliceSize,
graphClient.RequestAdapter
);

var uploadResult = await uploadTask.UploadAsync();

if (uploadResult.UploadSucceeded)
{
Console.WriteLine($"Uploaded: {uploadResult.ItemResponse?.WebUrl}");
}

7-6. DriveItemを使ったファイル操作の考え方

Graph APIでSharePointファイルを扱うときは、driveItemの考え方を理解しておくと実装しやすくなります。

driveItemは、OneDriveやSharePointドキュメントライブラリ上のファイル、フォルダー、その他のアイテムを表すリソースです。ドキュメントライブラリ内のアイテムは、listItemとしてもdriveItemとしても扱える場合があります。Microsoft Learn

ファイル本体のアップロード・ダウンロード・フォルダー配下取得はdriveItemで扱うのが自然です。一方、ドキュメントライブラリの列値、つまりメタデータを更新する場合は、ファイルに紐づくlistItemfieldsを更新する考え方になります。

C#
var driveItem = await graphClient
.Sites[siteId]
.Drive
.Root
.ItemWithPath("Reports/sample.txt")
.GetAsync();

Console.WriteLine(driveItem?.Id);
Console.WriteLine(driveItem?.Name);
Console.WriteLine(driveItem?.WebUrl);

ファイル操作ではパス指定とID指定の両方を使えます。固定パスで操作するならItemWithPath()、一度取得したファイルを継続的に操作するならdriveItem.Idを使うとよいでしょう。

8. CSOMとGraph APIはどちらを使うべきか

8-1. CSOMが向いているケース

CSOMが向いているのは、SharePoint固有の機能を細かく操作したいケースです。

たとえば、既存のSharePointリスト連携がCSOMで実装されている場合、無理にGraph APIへ移行せず、認証方式だけを先進認証に対応させる方が現実的なことがあります。また、CAML Queryを使った複雑なリスト検索、SharePoint固有のメタデータ操作、既存コード資産の活用が必要な場合もCSOMが候補になります。

オンプレミスのSharePoint Serverを対象にする場合も、Graph APIではなくCSOMやSharePoint REST APIを検討することが多いです。

8-2. Graph APIが向いているケース

Graph APIが向いているのは、SharePointだけでなくMicrosoft 365全体と連携するケースです。

たとえば、SharePointのファイルをTeamsのチャネル情報やユーザー情報と組み合わせて処理する、OneDriveとSharePointのファイルを同じ設計で扱う、Azure FunctionsやWeb APIからクラウドネイティブに連携する、といった用途ではGraph APIが適しています。

新規開発でSharePoint Onlineを対象にする場合は、まずGraph APIで実現できるかを確認し、Graph APIで難しいSharePoint固有操作がある場合にCSOMを検討する流れが扱いやすいです。

8-3. 既存システム連携での選び方

既存システムでCSOMを使っている場合は、すぐにGraph APIへ全面移行する必要はありません。まず確認すべきなのは、現在の認証方式です。

SharePointOnlineCredentialsやユーザー名・パスワード依存の実装が残っている場合は、OAuthベースの認証へ移行する必要があります。CSOM for .NET StandardではSharePointOnlineCredentialsが利用できないため、Microsoft Entra IDアプリ登録、証明書認証、PnP Framework、MSALなどを組み合わせた構成を検討します。Microsoft Learn

一方、既存システムの機能追加でTeamsやユーザー情報も扱う予定がある場合は、新規機能部分だけGraph APIで実装するハイブリッド構成も選択肢になります。

8-4. 新規開発で推奨される選択肢

SharePoint Online向けの新規開発では、まずMicrosoft Graph APIを検討するのがおすすめです。理由は、Microsoft 365全体の統一APIとして利用でき、認証や権限管理もMicrosoft Entra IDに集約しやすいためです。

ただし、Graph APIですべてのSharePoint固有機能を完全に代替できるとは限りません。リスト、ファイル、基本的なメタデータ操作はGraph APIで対応しやすい一方、SharePoint固有の管理操作や細かな機能ではCSOMの方が扱いやすいことがあります。

実務では、「基本はGraph API、SharePoint固有処理はCSOM」という分担にすると、保守性と実装効率のバランスを取りやすくなります。

8-5. 機能・認証・保守性の比較表

比較項目CSOMMicrosoft Graph API
主な対象SharePoint中心Microsoft 365全体
C#実装ClientContext中心GraphServiceClient中心
リスト操作得意対応可能
ファイル操作対応可能driveItemで扱いやすい
CAML Query利用可能基本はODataクエリ
SharePoint固有機能強い一部制限あり
認証OAuth対応が必要Microsoft Entra ID前提
新規開発要件次第優先候補
既存資産活用向いている移行設計が必要
Microsoft 365連携限定的強い

9. C#でSharePointを操作する際によくあるエラーと対処法

9-1. 認証エラーが発生する原因と対処法

認証エラーの代表例は、テナントID、クライアントID、クライアントシークレット、証明書、スコープ、APIアクセス許可のいずれかが誤っているケースです。

Graph APIでは、ClientSecretCredentialで認証している場合、シークレットの期限切れや値のコピー間違いがよくあります。https://graph.microsoft.com/.defaultを使う場合は、アプリ登録側で必要なアプリケーション権限が付与され、管理者同意が完了している必要があります。

CSOMでは、OAuthトークンをAuthorizationヘッダーに正しく付与できていないと認証に失敗します。PnP Frameworkを使う場合は、アプリ登録、証明書、テナントID、サイトURLが正しいかを確認します。

9-2. アクセス権限不足によるエラー

HTTP 403 ForbiddenやAccess deniedが発生する場合は、認証には成功しているものの、対象SharePointサイトやリストにアクセスする権限が不足している可能性があります。

Graph APIでは、アプリケーション権限としてSites.Read.AllSites.ReadWrite.AllSites.Selectedなどを設定します。ただし、権限を付けただけではなく、管理者同意が必要です。Sites.Selectedを使う場合は、アプリ登録に権限を与えた後、対象サイトにも明示的に権限を割り当てる必要があります。Microsoft GraphのSelectedスコープは、同意後に明示的な割り当てが必要になる仕組みです。Microsoft Learn

CSOMでは、アプリまたはユーザーが対象サイト、リスト、ライブラリに対して必要な権限を持っているかを確認します。

9-3. ファイルアップロード時のエラー

ファイルアップロード時によくあるエラーには、パス間違い、ファイルサイズ超過、同名ファイルの競合、ライブラリ権限不足があります。

Graph APIで単一リクエストのアップロードを行う場合、対応サイズは最大250MBです。250MBを超える可能性がある場合は、アップロードセッションを使った大容量ファイルアップロードに切り替える必要があります。Microsoft Learn+1

CSOMでは、ServerRelativeUrlの指定ミスがよくあります。https://contoso.sharepoint.comを含めず、/sites/dev/Shared Documents/sample.pdfのようなサーバー相対パスを指定しているか確認してください。

9-4. リストアイテム取得時のエラー

リストアイテム取得でエラーが出る場合、リスト名、リストID、列の内部名、アクセス権限、しきい値制限を確認します。

CSOMでGetByTitle()を使う場合、表示名が完全一致している必要があります。Graph APIでは、リスト名ではなくリストIDを使う方が安定します。

列値を取得できない場合は、列の表示名ではなく内部名を指定しているか確認します。Graph APIでは、Expand = ["fields"]を指定していないと、列値が取得できないことがあります。

大量データ取得では、ページングや条件指定が必要です。CSOMではCAML QueryにRowLimitを設定し、Graph APIではページングレスポンスを処理する設計にします。

9-5. CSOMとGraph APIでエラー内容を確認する方法

CSOMでは、ServerExceptionをキャッチして、エラーメッセージや相関IDを出力します。

C#
using Microsoft.SharePoint.Client;

try
{
context.ExecuteQuery();
}
catch (ServerException ex)
{
Console.WriteLine($"Message: {ex.Message}");
Console.WriteLine($"ServerErrorCode: {ex.ServerErrorCode}");
Console.WriteLine($"ServerErrorTypeName: {ex.ServerErrorTypeName}");
Console.WriteLine($"CorrelationId: {ex.ServerErrorTraceCorrelationId}");
}

Graph APIでは、ODataエラーを確認します。

C#
using Microsoft.Graph.Models.ODataErrors;

try
{
var site = await graphClient.Sites[siteId].GetAsync();
}
catch (ODataError ex)
{
Console.WriteLine($"Code: {ex.Error?.Code}");
Console.WriteLine($"Message: {ex.Error?.Message}");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

本番運用では、エラーメッセージだけでなく、リクエスト対象のサイトURL、リストID、アイテムID、ファイルパス、実行ユーザーまたはアプリID、相関ID、HTTPステータスコードをログに残しておくと調査しやすくなります。

10. C#でSharePoint連携を実装する際の注意点

10-1. アクセス権限と最小権限の考え方

SharePoint連携では、必要以上に強い権限を与えないことが重要です。開発中は動作確認のために広い権限を付けがちですが、本番運用では対象サイト、対象リスト、必要な操作に合わせて権限を絞るべきです。

Graph APIであれば、読み取りだけなら読み取り権限、更新が必要なら書き込み権限を検討します。テナント全体にアクセスできる権限を使う場合は、業務上本当に必要かを確認してください。特定サイトだけに限定したい場合は、Sites.Selectedなどの利用も検討します。

CSOMでも、アプリやユーザーにサイトコレクション管理者権限を安易に付けるのではなく、リストやライブラリ単位で必要な権限を設計することが大切です。

10-2. クライアントシークレットの安全な管理方法

クライアントシークレットや証明書パスワードをソースコードに直接書いてはいけません。GitHubや社内リポジトリに漏洩すると、SharePoint上の業務データへ不正アクセスされるリスクがあります。

開発環境では、次の方法を検討します。

・.NET User Secrets
・環境変数
・ローカルのシークレット管理ファイル

本番環境では、次のような方法が望ましいです。

・Azure Key Vault
・マネージドID
・証明書認証
・CI/CDのシークレットストア

また、クライアントシークレットには有効期限があります。期限切れによる障害を防ぐため、更新時期を監視し、ローテーション手順を運用に組み込みましょう。

10-3. 大量データ取得時のパフォーマンス対策

SharePointリストから大量データを取得する場合、一度にすべてのアイテムを取得しないようにします。

CSOMでは、CAML QueryのRowLimitを使い、必要な列だけを取得します。Graph APIでは、ページング、$select$filter$topなどを活用します。Graph APIのリストアイテム取得では、$filterを使ってリストアイテムを絞り込めますが、フィルターはインデックス付き列で使うのが推奨されます。Microsoft Learn

また、SharePointリスト側でよく検索する列にインデックスを設定しておくと、しきい値エラーやパフォーマンス低下を防ぎやすくなります。

10-4. API制限・スロットリングへの対応

SharePoint OnlineやMicrosoft Graph APIでは、大量リクエストや短時間の連続アクセスによりスロットリングが発生することがあります。スロットリングが発生した場合、すぐにリトライを繰り返すと状況が悪化します。

実装では、次の対策を入れておくと安全です。

・リトライ回数の上限を設定する
・指数バックオフで待機する
・Retry-Afterヘッダーを確認する
・一括処理を小さな単位に分割する
・不要なAPI呼び出しを減らす
・差分取得を活用する

ファイルアップロードや大量リスト処理は、特にスロットリングの影響を受けやすいため、ログとリトライ設計を最初から組み込んでおきましょう。

10-5. 本番運用でログ出力すべき内容

C#でSharePoint連携を本番運用する場合、最低限次の情報をログに残すことをおすすめします。

・処理開始日時、終了日時
・対象SharePointサイトURL
・対象リスト名またはリストID
・対象ファイルパス
・操作内容
・処理件数
・成功件数、失敗件数
・HTTPステータスコード
・エラーコード
・エラーメッセージ
・SharePointの相関ID
・Graph APIのリクエストID
・リトライ回数

特にSharePointやGraph APIの障害調査では、相関IDやリクエストIDが重要になります。単に「失敗しました」だけでは原因を追跡できないため、運用担当者が調査できる粒度でログを出力しましょう。

まとめ

C#でSharePointを操作する方法には、主にCSOMとMicrosoft Graph APIがあります。CSOMはSharePoint固有の操作に強く、既存のSharePoint連携システムやCAML Queryを使ったリスト操作、細かなメタデータ更新に向いています。一方、Microsoft Graph APIはSharePointだけでなくMicrosoft 365全体を統一的に扱えるため、新規開発やクラウド連携、TeamsやOneDriveとの連携に適しています。

SharePoint Onlineを対象にする場合は、認証方式に注意が必要です。CSOM for .NET Standardでは従来のSharePointOnlineCredentialsは利用できないため、OAuthベースの先進認証を前提に設計します。Graph APIでは、Microsoft Entra IDのアプリ登録、APIアクセス許可、管理者同意、GraphServiceClientの初期化が基本になります。

実装では、リストアイテムの取得・追加・更新・削除、ドキュメントライブラリのファイルアップロード・ダウンロード、メタデータ更新などを要件に応じて組み合わせます。新規開発ではまずGraph APIで実現できるかを確認し、SharePoint固有の細かな操作が必要な場合はCSOMを併用するとよいでしょう。

C#とSharePointの連携は、認証、権限、パス指定、列の内部名、API制限など、つまずきやすいポイントが多い分、正しく設計すれば業務自動化に大きく役立ちます。小さなサンプルから動作確認を行い、最小権限、シークレット管理、ログ出力、リトライ処理まで含めて本番運用に耐える構成を整えていきましょう。