C#からSlackAPIを利用して、指定期間内に投稿されたメッセージを取得する


はじめに

本記事はC#からSlackAPIを利用して、指定期間内に投稿されたメッセージを取得する方法をまとめることを目的としています。
なお、以前に以下のようなSlackAPIに関する記事を投稿していますので、こちらの記事を先に読んでいただくことをお勧めします。

利用するAPIとAPI引数

メッセージを取得するためにはこちらのAPIを使います。
投稿時間を指定するためには以下のoldest, latest引数を設定してAPIを呼び出す必要があります。

oldestは取得するメッセージの投稿時間の最小値、latestは取得するメッセージの投稿時間の最大値を表します。つまり、oldestとlatestを両方設定すると、oldest~latest間のメッセージを取得することができます。

oldest, latestの指定方法

こちらの公式文書に書かれているようにSlackでは時間をUNIX時間形式で扱っています。UNIX時間はUNIX系のコンピューターシステムで標準的に使われている時刻表現のことです。詳細はこちらを参照ください。
そのため、例えば2020年7月1日に投稿されたメッセージを取得する場合は、oldest, latestにそれぞれ以下のような値を入れて、APIを呼び出します。

  • oldest
    2020年7月1日 0:00を表現するUNIX時間

  • latest
    2020年7月2日 0:00を表現するUNIX時間

C#でUNIX時間を作り出す方法

C#上でUNIX時間を作り出すには、DateTimeOffset構造体から変換するのが簡単だと思います。
手順としては、以下になります。

  1. DateTime構造体でUNIX時間に変換したい日時情報を作成
  2. 1でつくったDateTime型の値を使って、DateTimeOffset構造体を作成(リファレンスはこちら)
  3. 2のDateTimeOffset型の値をこちらのメソッドでUNIX時間に変換

時間を指定してメッセージを取得するサービス

これまでの内容を活かして、投稿時間を指定してメッセージを取得するサービスを作成します。こちらの記事で作成したメッセージを取得するGetMessagesメソッドを拡張して、実現します。

/// <summary>
/// Slackメッセージの取得に必要な機能を提供するサービス
/// </summary>
public class SlackMessageGetService
{
    #region 定数

    /// <summary>
    /// アクセストークン用のクエリパラメータ名
    /// </summary>
    private const string c_AccessTokenQueryParameterName = "token";

    /// <summary>
    /// チャンネルID用のクエリパラメータ名
    /// </summary>
    private const string c_ChannelIdQueryParameterName = "channel";

    /// <summary>
    /// 取得メッセージ数用のクエリパラメータ名
    /// </summary>
    private const string c_MessageCountQueryParameterName = "limit";

    /// <summary>
    /// 投稿時間の最小値用のクエリパラメータ名
    /// </summary>
    private const string c_OldestQueryParameterName = "oldest";

    /// <summary>
    /// 投稿時間の最大値用のクエリパラメータ名
    /// </summary>
    private const string c_LatestQueryParameterName = "latest";

    ・・・

    #endregion

    #region フィールド

    /// <summary>
    /// SlackにPOST,GETするために使用するHttpClient
    ///
    /// ユーザーの利用方法を想定したとき、接続先のホストは[チーム名].slack.comしかありえないため、
    /// HttpClientは単一インスタンスのみとする
    /// </summary>
    // ReSharper disable once InconsistentNaming
    private static readonly HttpClient m_HttpClient = new HttpClient();

    #endregion

    #region 公開サービス

    /// <summary>
    /// メッセージを取得する
    /// </summary>
    /// <param name="accessToken">アクセストークン</param>
    /// <param name="channelId">チャンネルID</param>
    /// <param name="messageCount">取得するメッセージ数</param>
    /// <param name="oldest">投稿時間の最小値</param>
    /// <param name="latest">投稿時間の最大値</param>
    /// <returns>取得メッセージ一覧</returns>
    public async Task<IEnumerable<Message>> GetMessages(string accessToken, string channelId, int messageCount, DateTime oldest, DateTime latest)
    {
        var messages = new List<Message>();

        // latestとoldestをUNIX時間に変換
        var oldestDateTimeOffset = new DateTimeOffset(oldest);
        var oldestUnixTime = oldestDateTimeOffset.ToUnixTimeSeconds();
        var latestDateTimeOffset = new DateTimeOffset(latest);
        var latestUnixTime = latestDateTimeOffset.ToUnixTimeSeconds();

        // クエリパラメータを作成するためにディクショナリを作成
        // ディクショナリのKeyがクエリパラメータ名、ディクショナリのValueがクエリパラメータの値
        var parameters = new Dictionary<string, string>()
        {
            { c_AccessTokenQueryParameterName, accessToken},
            { c_ChannelIdQueryParameterName, channelId},
            { c_MessageCountQueryParameterName, messageCount.ToString()},
            { c_OldestQueryParameterName, oldestUnixTime.ToString()},
            { c_LatestQueryParameterName, latestUnixTime.ToString()}
        };

        try
        {
            // クエリパラメータを作成し、文字列で読み出す
            var parametersString = await new FormUrlEncodedContent(parameters).ReadAsStringAsync();
            // 読みだしたクエリパラメータを使ってリクエストURLを作成する。
            var requestBaseUrl = "https://slack.com/api/conversations.history";
            var requestUrl = $"{requestBaseUrl}?{parametersString}";
            var response = await m_HttpClient.GetAsync(requestUrl).ConfigureAwait(false);
            // レスポンスのコンテンツをstringで読み出す
            var responseBodyString = await response.Content.ReadAsStringAsync();
            // 読みだしたJsonを、オブジェクトにデシリアライズする
            var responceObject = JsonConvert.DeserializeObject<GetSlackMessagesResponce>(responseBodyString);

            // 戻り値用のメッセージ一覧を作成
            foreach (var messageResponce in responceObject.messages)
            {
                // 本文を設定
                var message = new Message()
                {
                    Text = messageResponce.text
                };

                // 添付ファイルを設定
                foreach (var file in messageResponce.files)
                {
                    var addFile = new File()
                    {
                        FileURL = file.url_private,
                        Id = file.id,
                    };
                    message.Files.Add(addFile);
                }

                messages.Add(message);
            }

            return messages;
        }
        catch
        {
            return messages;
        }
    }

    ・・・

    #endregion
}

メソッドに新たに追加したロジックである、引数oldestとlatestをUNIX時間に変換する箇所を細かく説明します。
引数oldestとlatestはDateTime型なので、その値を使ってDateTimeOffset構造体の値を作ります。コンストラクタにDataTime型の値を渡すだけで作成できます。その後、ToUnixTimeSecondsメソッドでUNIX時間に変換します。
その後は、元々API引数として渡していたchannelIdなどと同様にディクショナリに情報を詰めます。ディクショナリのKey値がAPI引数名(oldestやlatest)、Value値が実際の値です。ディクショナリをどのようにAPI引数とするかの細かい説明は以前の記事を参照ください。

これらのロジック追加によって、oldest,latestを指定してAPIを呼び出すことが可能になりました。

まとめ

本記事では、C#からSlackAPIを利用して指定期間内に投稿されたメッセージを取得する方法をまとめました。
最も伝えたかったのは、以下2点です。

  • SlackAPIにおいて時間はUNIX時間で表現される
  • C#でUNIX時間を作るにはDateTimeOffset構造体を使うのが簡単