Microsoft Graph API を使って、Microsoft 365 の SharePoint のドキュメントを取得するときに、 {site-id} がわかりにくかったのでメモを残します。
Microsoft Graph を使用して、OneDrive、OneDrive for Business、および SharePoint のドキュメント ライブラリに配置されるファイルに接続するアプリケーションを作成する場合、以下のドキュメントが参考になります。
Azure Active Directory にアプリケーション登録
前回記事「Microsoft Graph で Microsoft 365 Enterprise 組織内のメールを取得する」の「Azure Active Directory にアプリケーション登録」を参考に、アプリケーション登録を行ってください。今回は「Files.Read.All」と「Sites.Read.All」を使います。
SharePoint にサイトを作成してファイルをアップロード
SharePointにサイトを作成します。今回は「Communication Site」を選択しました。(既にSharePointサイトをお持ちの方は次の章にスキップしてください。)
デザインは「Topic」、サイト名を「azure」で作成しました。
完成したサイトの「Documents」を選択します。
Documentsにファイルをアップロードしておきます。
バックグランドサービスとして動くアプリを作成
前回記事「Microsoft Graph で Microsoft 365 Enterprise 組織内のメールを取得する」の「バックグランドサービスとして動くアプリを作成」と同じようにプログラムを作成します。
注意点としては、/sites/{site-id} を使用して取得した別のサイトIDを使用して /sites/{site-id}/drive などにアクセスします。なお、初めに使用する /sites/{site-id} の {site-id} は、"{hostname}:/{server-relative-path}" のようなフォーマットになります。
using Microsoft.Graph;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace GraphFileSample
{
public class GraphHelper
{
private static GraphServiceClient graphClient;
public static void Initialize(IAuthenticationProvider authProvider)
{
graphClient = new GraphServiceClient(authProvider);
}
public static async Task<Site> GetSiteAsync(string siteId)
{
// siteId format is "{hostname}:/{server-relative-path}"
try
{
var site = await graphClient.Sites[siteId].Request().GetAsync();
return site;
}
catch (ServiceException ex)
{
Console.WriteLine($"Error getting events: {ex.Message}");
return null;
}
}
public static async Task<IEnumerable<DriveItem>> GetDriveRootChildrenAsync(string siteObjId)
{
// siteObjId format is "xxxxxxxx,xxxxxxxxx,xxxxxxxxx"
try
{
List<DriveItem> dirobjects = new List<DriveItem>();
var resultPage = await graphClient.Sites[siteObjId].Drive.Root.Children.Request().GetAsync();
while (true)
{
dirobjects.AddRange(resultPage);
if (resultPage.NextPageRequest == null)
{
break;
}
resultPage = resultPage.NextPageRequest.GetAsync().Result;
}
return dirobjects;
}
catch (ServiceException ex)
{
Console.WriteLine($"Error getting events: {ex.Message}");
return null;
}
}
public static async Task<Stream> GetDriveContentAsync(string siteObjId, string itemId)
{
// siteObjId format is "xxxxxxxx,xxxxxxxxx,xxxxxxxxx"
try
{
var result = await graphClient.Sites[siteObjId].Drive.Items[itemId].Content.Request().GetAsync();
return result;
}
catch (ServiceException ex)
{
Console.WriteLine($"Error getting events: {ex.Message}");
return null;
}
}
}
}
作成したGraphHelper.csを使用して、SharePointのサイトの、ドキュメントのルートに存在するファイルを全てダウンロードします。
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Graph;
namespace GraphFileSample
{
class Program
{
static Dictionary<string, string> LoadClientSecretAppSettings()
{
Dictionary<string, string> result = null;
// Get config ftom AppSettings
var appConfig = new ConfigurationBuilder()
.AddUserSecrets<Program>()
.Build();
var appId = appConfig["appId"];
var scopes = appConfig["scopes"];
var tenantId = appConfig["tenantId"];
var clientSecret = appConfig["clientSecret"];
var siteId = appConfig["siteId"];
if (string.IsNullOrEmpty(appId) == false &&
string.IsNullOrEmpty(scopes) == false &&
string.IsNullOrEmpty(tenantId) == false &&
string.IsNullOrEmpty(clientSecret) == false &&
string.IsNullOrEmpty(siteId) == false)
{
result = new Dictionary<string, string>()
{
{"appId", appId},
{"scopes", scopes},
{"tenantId", tenantId},
{"clientSecret", clientSecret},
{"siteId", siteId}
};
}
return result;
}
static void GetSiteDocuments(string siteId)
{
var site = GraphHelper.GetSiteAsync(siteId).Result;
var items = GraphHelper.GetDriveRootChildrenAsync(site.Id).Result;
foreach (var item in items)
{
Console.WriteLine($"Entity.Id: {item.Id}");
Console.WriteLine($"BaseItem.File: {item.Name}");
using (var itemContent = GraphHelper.GetDriveContentAsync(site.Id, item.Id).Result)
using (var fileStream = new FileStream(item.Name, FileMode.Create, FileAccess.Write, FileShare.None))
{
itemContent.CopyTo(fileStream);
}
}
}
static void Main(string[] args)
{
IAuthenticationProvider authProvider = null;
var appConfig = LoadClientSecretAppSettings();
if (appConfig == null)
{
Console.WriteLine("Missing or invalid AppSettings");
return;
}
var appId = appConfig["appId"];
var scopesString = appConfig["scopes"];
var scopes = scopesString.Split(';');
var tenantId = appConfig["tenantId"];
var clientSecret = appConfig["clientSecret"];
var siteId = appConfig["siteId"];
// Initialize the auth provider
authProvider = new ClientSecretAuthProvider(appId, scopes, tenantId, clientSecret);
// Initialize Graph client
GraphHelper.Initialize(authProvider);
// Get Files
GetSiteDocuments(siteId);
}
}
}
実行する
上で書いたコードは、githubにおいてあるので、cloneします。
git clone https://github.com/KentaroAOKI/GraphFileSample.git
cd GraphFileSample
Azure Active Directory でアプリケーション登録をした際にメモした値を使って設定します。
dotnet user-secrets init
dotnet user-secrets set appId "{アプリケーション(クライアント)ID}"
dotnet user-secrets set scopes "https://graph.microsoft.com/.default"
dotnet user-secrets set tenantId "{ディレクトリ(テナント)ID}"
dotnet user-secrets set clientSecret "{クライアントシークレット}"
dotnet user-secrets set siteId "{テナント}.sharepoint.com:/sites/{サイト}"
今回作成した SharePoint サイトの siteId は、"xxxxx.sharepoint.com:/sites/azure" になります。
ビルドして実行すると、JAZUG(5).pptx がローカルにダウンロードされます。
dotnet build
dotnet run
さいごに
Graph API のサイトIDで、かなり時間をかけてしてしまいましたが、知っていれば簡単に自分のアプリで使えそうです。
Microsoft 365との連携は色々面白いことができそうなので、引き続き他の機能も試していきたいです。