使用 C# (.NET Core) 傳訊息至 Slack

公司有個臨時性需求:某個重要功能開啟或是關閉時,立即通知營運團隊及各級主管知道,讓大家在討論 production issue 有共同的討論基準。

經過一番討論後決定將功能開關通知透過 slack 來實作,雖然用 slack 整點好段時間卻沒真的自己寫過,一時間沒能快速找到程式碼可以抄XD 所以就能紀錄一篇以後就省事了 哈哈

建立 Slack workspace

  1. Create a new workspace
  2. 確認 email

    1checkemail

  3. 輸入 workspace 名稱

    2workspacename

  4. 輸入 channel 名稱

    3channelname

  5. 邀請其他人或略過

    4inviteorskip

  6. 完成基本設定

    5complete

    7initscreenshot

建立 Token

  1. 使用 user token

    • 建立個人 token : Legacy tokens

      12usertoken

      成功建立後會連帶建立 Slack API Tester app 用來發送訊息

  2. 使用 bot token

    • 透過 Build something amazing. 建立 Apps

      13buildapp

    • 填入名稱及選擇目標 workspace

      14createslackapp

    • 加入 bot 功能

      15addfeature

      16addfeature2

      17addfeature3

    • 將 app 安裝至 workspace 中

      18installapp

      19installapp2

    • 取得 Bot User OAuth Access Token

      20accesstoken

取得 channel id

23channelid

Slack 測試傳送訊息

可以透過 chat.postMessage 來測試發送訊息

  1. User Token

    21usertoken

  2. bot token

    22bottoken

傳送訊息至 Slack

Slack 的 chat.postMessage 是 REST API,以下透過 .NET Core console 搭配 HttpClientFactory 來傳送訊息

  1. 基本設定

    如果想更深入了解相關設定可以參考 在 .NET Core console 上使用 Dependency Injection - DI在 .NET Core 與 .NET Framework 上使用 HttpClientFactory

    var builder =
        //新建 HostBuilder
        new HostBuilder()
        //設定所需 service
        .ConfigureServices((hostContext, services) =>
        {
            //設定每次 request 都會建立 具名 HttpClient
           services.AddHttpClient("yowkoslacksender", c =>
            {
                c.BaseAddress = new Uri("https://slack.com/api/");
            });
        });
    
      
        
    var clientFactory =
        //使用上面建立的 host builder 來初始化 host
        builder.Build()
        //從 service provider 中取得建立的 IHttpClientFactory 服務
        .Services.GetRequiredService<IHttpClientFactory>();
    
    //由 HttpClientFactory 來建立 HttpClient
    var client = clientFactory.CreateClient("yowkoslacksender");
        
    var token = "xoxb-xxxx";//access token
    var channel = "xxxx";//channelId
    
  2. 簡易內容 (僅文字)

    var text = System.Web.HttpUtility.UrlEncode("yowko 測試");//實際內容
    //透過 Get 傳送至 slack
    client.GetAsync($"chat.postMessage?token={token}&channel={channel}&text={text}");
    

    24simpletext

  3. 格式化內容 (包含圖片、超連結、或是按鈕….)

    //準備格式化內谷實際顯示值
    var attachments = new List<Attachment>() {
                new Attachment(){
                    color="#36a64f",//實際顯示時的引用線顏色
                    pretext= "原本 text 位置內容",
                    author_name= "第一行(作者)",
                    author_link= "",
                    author_icon= "http://flickr.com/icons/bobby.jpg",
                    title= "標題",
                    title_link= "",
                    text= "實際內文",
                    fields= new List<Field>(){
                        new Field(){
                            title= "Priority",
                            value= "High"}
                    }
                    ,
                    footer= "置底內容",
                    footer_icon= "https://platform.slack-edge.com/img/default_application_icon.png",
    
                }
            };
    //格式化內容轉為 string 再進行 urlencode 以利 get 傳送
    var attachment = System.Web.HttpUtility.UrlEncode(JsonConvert.SerializeObject(attachments));
    //透過 Get 傳送至 slack
    client.GetAsync($"chat.postMessage?token={token}&channel={channel}&attachments={attachment}");
    

    25richcontent

    格式化內容相關設定可以參考 Basic message formatting

心得

Slack 文件滿雜亂的,感覺起來應該歷經了許多演化,就連 API 的使用也有類似的影子,就以傳送訊息為例,可以找到好幾種做法,每種做法間似乎又沒有什麼脈絡可以依循,很容易搞混

另外最令我困擾的是 REST API 的說明,明明文件說要用 POST,但怎麼用就是失敗,查了資料才發現很多人說應該是 GET 才對XD 將程式改為 GET 問題就解決了,不知道官方的立場是什麼 感覺不是基本的錯誤而是有其他層面的考量

參考資訊

  1. Create a new workspace
  2. Legacy tokens
  3. Build something amazing.
  4. Types of tokens
  5. chat.postMessage
  6. 在 .NET Core console 上使用 Dependency Injection - DI
  7. 在 .NET Core 與 .NET Framework 上使用 HttpClientFactory
  8. Basic message formatting