Help us understand the problem. What is going on with this article?

C#コードを評価して結果を返すSlackBotをAzureFunctionsで実装する

More than 3 years have passed since last update.

C#コードを評価して結果を返すbotを実装してみようと思います。
結果はこのような感じです。
botsample.png

Slack の Integration 設定

Slack で bot を作るには Integration を利用すると良さそうです。

Outgoing Webhooks

何か発言に対して反応したい場合はOutgoingWebhooksを利用できそうです。
"@C#:"と先頭についている場合に反応するようにTriggerWordを設定します。
反応する発言があった場合にデータを送信するURLは後述するAzureFunctionsで実装したAPIのURLをセットします。
outgoing.png

Incoming Webhooks

何か発言をする場合はIncomingWebhooksを利用できそうです。
設定画面に発言データ(payload)を送りつけるURLが書いてあります。
発言するチャンネルはpayloadで上書きできるので
疎通確認用のチャンネル等にしておくと良いのでは無いでしょうか。
incoming.png

AzureFunctions で bot の実装

OutgoingWebhook で送られてきたデータを処理して IncomingWebhook に返す処理を AzureFunctions に実装します。
AzureFunctions に関してはぎたぱそ先生のブログが参考になります。

Integrate タブの WebHook type を Not a WebHook にする

OutgoingWebhook を受け取る為に設定します。
じんぐる先生のブログに記述されていました。

Nuget のインストール

Nugetパッケージを利用できるようにコンソールからインストールします。
この記事読めばできますね。

C#コードの評価

Roslyn の CSharpScripting を使えば簡単です。

今回実装したコード

長々と書きなぐっていて美しさには欠けますがこのようになりました。

project.json
{
 "frameworks": {
   "net46":{
     "dependencies": {
       "Microsoft.CodeAnalysis.Scripting": "1.2.1",
       "Newtonsoft.Json" : "8.0.3"
     }
   }
 }
}
run.csx
#r "System.Collections"
#r "System.Configuration"
#r "System.Runtime"
#r "System.Reflection"
#r "System.Threading.Tasks"
#r "System.Web"

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Threading.Tasks;
using System.Web;
using Newtonsoft.Json;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.CodeAnalysis.CSharp.Scripting;

private static readonly string[] DefaultImports =
{
    "System",
    "System.Collections.Generic",
    "System.IO",
    "System.Linq",
    "System.Text",
};

private static readonly Assembly[] DefaultReferences =
{
    typeof(Enumerable).Assembly,
    typeof(List<string>).Assembly,
};

private const string INCOMING_URL_KEY = "IncomingWebhookUrl";

private const string TRIGGER_WORD = "@C#:";

public static async Task<object> Run(HttpRequestMessage req, TraceWriter log)
{
    log.Verbose("Webhook was triggered!");

    var content = await req.Content.ReadAsStringAsync();
    log.Verbose(content);

    var data = content
        .Split('&')
        .Select(x => x.Split('='))
        .ToDictionary(x => x[0], x => HttpUtility.HtmlDecode(HttpUtility.UrlDecode(x[1])));

    if (data["user_name"] == "slackbot")
    {
        return req.CreateResponse(HttpStatusCode.OK, new {
            body = "Cannot Support Messages From SlackBot.",
        });
    }

    var text = data["text"] as string ?? "";
    log.Verbose(text);

    var code = text.Replace(TRIGGER_WORD, "");

    object result = null;
    try
    {
        result = await CSharpScript.EvaluateAsync(code ?? "コードが空ニャ", 
            ScriptOptions.Default
                .WithImports(DefaultImports)
                .WithReferences(DefaultReferences));
    }
    catch (Exception ex)
    {
        result = ex.Message;
    }

    var resultText = result?.ToString() ?? "";
    if (resultText.StartsWith(TRIGGER_WORD))
    {
        resultText = resultText.Replace(TRIGGER_WORD, "");
    }

    log.Verbose(resultText);

    var payload = new
    {
        channel = "#" + data["channel_name"],
        username = "C#と和解せよ",
        text = string.IsNullOrWhiteSpace(resultText) ? "空だニャ" : resultText,
        icon_emoji = ":cat:",
    };
    var jsonString = JsonConvert.SerializeObject(payload);
    using (var client = new HttpClient())
    {
    var incomingUrl = ConfigurationManager.AppSettings[INCOMING_URL_KEY];
        var res = await client.PostAsync(incomingUrl, new FormUrlEncodedContent(new[]
        {
            new KeyValuePair<string, string>("payload", jsonString)
        }));
        return req.CreateResponse(res.StatusCode, new {
            body = resultText,
        });
    }
}

IncomingWebhookのUrlはAppSettingsに格納しています。
こちらを見ればできます。

手軽に bot が作れて良いですね。

nk9k
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした