【C#】Teamsからチャット履歴を取得する

Teamsからチャットの履歴を取得するよう仰せつかったため、いろいろと調べながら実装をしてみたので備忘録として残します。

開発はVisual Studio 2022、C#コンソールアプリケーションとして作成しています。
パッケージのバージョンも記載しておかないと、メソッドやプロパティの変更などある可能性もありますので下記に記載。
■ パッケージバージョン ■
Azure.Identity ... 1.10.0
Microsoft.Graph ... 5.24.0

■ 概要 ■
Teamsからチャットの履歴を取得し、スレッドごとに番号を付けます。
その結果をDataTable型変数に格納しています。

```csharp
// まずはパッケージのインポート
using Azure.Identity;
using Microsoft.Graph;
using System.Data;
using System.Text.RegularExpressions;
```

```csharp
// Azure.Identityを使う準備
var clientId = "アプリケーション (クライアント) ID";
var tenantId = "ディレクトリ (テナント) ID";
var clientSecret = "クライアントシークレット";

var options = new ClientSecretCredentialOptions
{
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
};

var clientSecretCredential = new ClientSecretCredential(
    tenantId, clientId, clientSecret, options);
```

```csharp
// Teamsにアクセスする準備
var teamId = "チームID";
var channelId = "チャンネルID";

var graphClient = new GraphServiceClient(clientSecretCredential, scopes);

// DataTable準備
DataTable dt = new DataTable();
dt.Columns.Add("日付");
dt.Columns.Add("件名");
dt.Columns.Add("スレッド");
dt.Columns.Add("内容");
```

```csharp
// Teamsからチャット履歴を取得し、DataTableへ格納
int threadCount = 1; // スレッド用のカウンター
bool loop = true; // 繰り返しフラグ

// Teamsからメッセージを50件取得（1回目）
var messages = await graphClient.Teams[teamId].Channels[channelId].Messages.Delta.GetAsync((requestConfiguration) => {
    requestConfiguration.QueryParameters.Top = 50;
});

while(loop)
{
    // 取得したメッセージ数繰り返す
    foreach (var message in messages.Value)
    {
        // Datatableにデータを格納
        DataRow dr = dt.NewRow();
        dr["日付"] = message.CreatedDateTime;
        dr["件名"] = message.Subject;
        if(message.Body.Content != null)
        {
            // タグが付いているので適当に置換
            dr["内容"] = Regex.Replace(message.Body.Content, "<.*?>", String.Empty);
        }
        else
        {
            dr["内容"] = "";
        }
        
        dr["スレッド"] = threadCount;
        dt.Rows.Add(dr);

        // スレッド内のやり取りを取得
        var replies = await graphClient.Teams[teamId].Channels[channelId].Messages[message.Id].Replies.GetAsync();

        foreach (var rep in replies.Value)
        {
            // Datatableにデータを格納
            DataRow dr2 = dt.NewRow();
            dr2["日付"] = rep.CreatedDateTime;
            dr2["件名"] = rep.Subject;
            if(rep.Body.Content != null)
            {
                // タグが付いているので適当に置換
                dr2["内容"] = Regex.Replace(rep.Body.Content, "<.*?>", String.Empty);
            }
            else
            {
                dr2["内容"] = "";
            }
            
            dr2["スレッド"] = threadCount;

            dt.Rows.Add(dr2);
        }
        threadCount++;
    }

    // Teamsから取得できるデータ数は上限が決まっているため、次のデータへのリンクがある場合は再度繰り返す
    if(messages.OdataNextLink != null)
    {
        var deltaRequestBuilder = new Microsoft.Graph.Teams.Item.Channels.Item.Messages.Delta.DeltaRequestBuilder(messages.OdataNextLink, graphClient.RequestAdapter);
        messages = await deltaRequestBuilder.GetAsync();
    } else
    {
        loop = false;
    }
}

```

繰り返しの処理のロジックがなんかな…という感じはあるかもしれませんが急ごしらえの割にはちゃんと動いてくれたのでこのまま残します。
あとは、DataTableをCSVにするなりなんなりすれば完成です。

■ 全容 ■
```csharp
using Azure.Identity;
using Microsoft.Graph;
using System.Data;
using System.Text.RegularExpressions;

namespace TeamsAPI
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var scopes = new[] { "https://graph.microsoft.com/.default" };

            var clientId = "アプリケーション (クライアント) ID";
            var tenantId = "ディレクトリ (テナント) ID";
            var clientSecret = "クライアントシークレット";

            var options = new ClientSecretCredentialOptions
            {
                AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
            };

            var clientSecretCredential = new ClientSecretCredential(
                tenantId, clientId, clientSecret, options);

            var teamId = "チームID";
            var channelId = "チャンネルID";

            var graphClient = new GraphServiceClient(clientSecretCredential, scopes);

            DataTable dt = new DataTable();
            dt.Columns.Add("日付");
            dt.Columns.Add("件名");
            dt.Columns.Add("スレッド");
            dt.Columns.Add("内容");

            // Teamsからチャット履歴を取得し、DataTableへ格納
            int threadCount = 1; // スレッド用のカウンター
            bool loop = true; // 繰り返しフラグ

            // Teamsからメッセージを50件取得（1回目）
            var messages = await graphClient.Teams[teamId].Channels[channelId].Messages.Delta.GetAsync((requestConfiguration) =>
            {
                requestConfiguration.QueryParameters.Top = 50;
            });

            while (loop)
            {
                // 取得したメッセージ数繰り返す
                foreach (var message in messages.Value)
                {
                    // Datatableにデータを格納
                    DataRow dr = dt.NewRow();
                    dr["日付"] = message.CreatedDateTime;
                    dr["件名"] = message.Subject;
                    if (message.Body.Content != null)
                    {
                        // タグが付いているので適当に置換
                        dr["内容"] = Regex.Replace(message.Body.Content, "<.*?>", String.Empty);
                    }
                    else
                    {
                        dr["内容"] = "";
                    }

                    dr["スレッド"] = threadCount;
                    dt.Rows.Add(dr);

                    // スレッド内のやり取りを取得
                    var replies = await graphClient.Teams[teamId].Channels[channelId].Messages[message.Id].Replies.GetAsync();

                    foreach (var rep in replies.Value)
                    {
                        // Datatableにデータを格納
                        DataRow dr2 = dt.NewRow();
                        dr2["日付"] = rep.CreatedDateTime;
                        dr2["件名"] = rep.Subject;
                        if (rep.Body.Content != null)
                        {
                            // タグが付いているので適当に置換
                            dr2["内容"] = Regex.Replace(rep.Body.Content, "<.*?>", String.Empty);
                        }
                        else
                        {
                            dr2["内容"] = "";
                        }

                        dr2["スレッド"] = threadCount;

                        dt.Rows.Add(dr2);
                    }
                    threadCount++;
                }

                // Teamsから取得できるデータ数は上限が決まっているため、次のデータへのリンクがある場合は再度繰り返す
                if (messages.OdataNextLink != null)
                {
                    var deltaRequestBuilder = new Microsoft.Graph.Teams.Item.Channels.Item.Messages.Delta.DeltaRequestBuilder(messages.OdataNextLink, graphClient.RequestAdapter);
                    messages = await deltaRequestBuilder.GetAsync();
                }
                else
                {
                    loop = false;
                }
            }
        }
    }
}
```