LoginSignup
7
3

More than 1 year has passed since last update.

LINE bot作成 C#+AWS(Lambda)

Last updated at Posted at 2021-06-10

概要

自分でLINE botを作成した際、C#+AWS(Lambda)環境で実装してみたのですが、
この技術スタックでの情報が全く見つかりませんでした。
(自分の探し方が悪かっただけかもしれませんが…)
そこで、今後C#+AWS(Lambda)で作成したい!という方のために手順をまとめておきます。

本記事では、LINEから送信された文字をオウム返しするbotが作成できます。
このベースさえ作ってしまえば、LINE公式ドキュメントを参考に色々いじって楽しめると思います!

内容としては、LINE Developers登録からLambda関数のプログラミング、AWSへのデプロイから最終的に実際にLINEで確認するところまでやってしまいます。

※AWS Lambdaへのデプロイは、Windowsの場合、Visual Studioを使用すればGUIポチポチで完了するので簡単ですが、
Visual Studio for Macの場合はそうはいかないので、
今回はどの環境でも対応できるようCUIからデプロイする操作を記載しております。

事前準備編(LINE Developers登録)

LINE Developers登録及びチャンネル作成

LINE botを作成するにあたり、「LINE Developers」に登録する必要があります。
手順は簡単で、申請待ち時間も無いので数分で登録可能です。
下記サイトを参考に、アカウントの作成及びチャンネルの作成まで行います。
※1アカウントで「チャンネル」を複数作成することが可能で、「チャンネル」ごとに別のbotを作成できます。

チャンネルアクセストークンの発行

LINE botを作成するにあたり、最低限「チャンネルアクセストークン」は発行する必要があります。

チャンネルの作成まで完了したら、Line Develpersにログインし、作成したチャンネルのページにアクセスします。

スクリーンショット 2021-06-03 17.16.16.png

「Messagin API設定」タブをクリックします。

スクリーンショット 2021-06-03 17.22.44.png

ページ下部までスクロースし、「チャネルアクセストークン」の発行ボタンをクリックします。
発行されたキーは後ほど使用するのでどこかにメモをしておいて下さい。
※後ほど再度このページにアクセスして発行済のキーを確認することは可能です。

スクリーンショット 2021-06-03 17.25.05.png

プログラミング編

無事アクセストークンの発行が完了したら、続いてプログラミングを行っていきます。
C#でのLambda関数プログラミングは、Windowsの場合はVisual Studioを使用すればあらかじめテンプレートが用意されているので簡単ですが、
Visual Studio for Macには用意されていないため、gitにテンプレートを用意しておきました。
※AWSへデプロイするための設定ファイル等も同梱してあります。

ローカルにプロジェクトの準備が完了したら、「Function.cs」ファイルを開きます。
この中の「FunctionHandler()」メソッドがLambda実行時に呼び出されるメソッドです。
つまり、LINEのMessagingAPIからWebhookで呼び出されることになります。

今回はサンプルでbot利用ユーザが入力された文章をそのままオウム返しするようにしてみます。

●LINEからLambdaへのリクエスト内容をモデリング

WebHookRequestModel.cs
using System.Collections.Generic;
using Newtonsoft.Json;

namespace LambdaSample.Models
{
    public class WebHookRequestModel
    {
        [JsonProperty("events")]
        public List<EventModel> EventModels { get; set; }
    }
}
EventModel.cs
using Newtonsoft.Json;

namespace LambdaSample.Models
{
    public class EventModel
    {
        [JsonProperty("message")]
        public MessageModel Message { get; set; }

        [JsonProperty("replyToken")]
        public string ReplyToken { get; set; }
    }
}
MessageModel.cs
using Newtonsoft.Json;

namespace LambdaSample.Models
{
    public class MessageModel
    {
        [JsonProperty("type")]
        public string Type { get; set; }

        [JsonProperty("text")]
        public string Text { get; set; }
    }
}

●LambdaからLINEへのリプライモデル

ReplyRequestModel.cs
using System.Collections.Generic;
using Newtonsoft.Json;

namespace LambdaSample.Models
{
    public class ReplyRequestModel
    {
        [JsonProperty("replyToken")]
        public string ReplyToken { get; set; }

        [JsonProperty("messages")]
        public List<MessageModel> Messages { get; set; }

        /// <summary>
        /// true: ユーザに通知されない(デフォルト)
        /// false: ユーザに通知される
        /// </summary>
        [JsonProperty("notificationDisabled")]
        public bool NotificationDisabled { get; set; }
    }
}

●メインの処理

Function.cs
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
using BasicExtension;
using LambdaSample.Models;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace LambdaSample
{
    public class Function
    {
        public Function()
        {
            _httpClient = new HttpClient();
            _httpClient.DefaultRequestHeaders.AcceptCharset.Add(new StringWithQualityHeaderValue("utf-8"));
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
                Environment.GetEnvironmentVariable("CHANNEL_ACCESS_TOKEN"));
        }

        public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest input, ILambdaContext context)
        {
            WebHookRequestModel webHookRequestModel = input.Body.ToObject<WebHookRequestModel>();

            string replyToken = webHookRequestModel.EventModels[0].ReplyToken;
            MessageModel message = webHookRequestModel.EventModels[0].Message;

            ReplyToLine(replyToken, message.Text);

            return CreateLambdaApiResponse();
        }

        private void ReplyToLine(string replyToken, string inputText)
        {
            string stringRequest = CreateReplyRequestModel(replyToken, inputText).ToJson();
            StringContent stringContent = new StringContent(stringRequest, Encoding.UTF8, "application/json");
            _httpClient.PostAsync("https://api.line.me/v2/bot/message/reply", stringContent).Wait();
        }

        private ReplyRequestModel CreateReplyRequestModel(string replyToken, string inputText)
        {
            ReplyRequestModel replyRequestModel = new ReplyRequestModel();
            replyRequestModel.ReplyToken = replyToken;
            replyRequestModel.Messages = new List<MessageModel>()
            {
                new MessageModel()
                {
                    Type = "text",
                    Text = inputText
                }
            };
            replyRequestModel.NotificationDisabled = false;

            return replyRequestModel;
        }

        private APIGatewayProxyResponse CreateLambdaApiResponse()
        {
            return new APIGatewayProxyResponse
            {
                StatusCode = 200,
                Body = null,
                IsBase64Encoded = false,
                Headers = new Dictionary<string, string>() { { "Content-Type", "application/json" } }
            };
        }

        private readonly HttpClient _httpClient;
    }
}

AWSへデプロイ

こちらの記事をご参考下さい。
https://qiita.com/ryohei0109_develop/items/ff05cfad2cb276af1169

今回の例ではjsonファイルはこのようになります。
※「function-role」だけはどうしても書き換えて下さい!

aws-lambda-tools-defaults.json
{
  "Information": [
    "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
    "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
    "dotnet lambda help",
    "All the command line options for the Lambda command can be specified in this file."
  ],
  "configuration": "Release",
  "framework": "netcoreapp3.1",
  "profile": "default", // AWS CLI プロフィール
  "region": "ap-northeast-1", // AWSリージョン指定
  "function-runtime": "dotnetcore3.1", // Lambbda実行ランタイム
  "function-memory-size": 512, // Lambdaメモリ(MB)
  "function-timeout": 30, // Lambdaタイムアウト時間(seconds)
  "function-handler": "LambdaSample::LambdaSample.Function::FunctionHandler", // Lambda実行時にコールするメソッドを指定
  "function-name": "LambdaSample", // Lambda名称
  "function-role": "arn:aws:iam::123456789012:role/xxxxxRole" // AWSロール名
}

Lambda環境変数にチャンネルアクセストークンを設定

チャンネルアクセストークンを環境変数に設定しておくと、今後チャンネルアクセストークンの変更があった際、
プログラムを変更することなくGUIから操作するだけで対応可能になります。

AWSマネジメントコンソールにログイン->Lambda->先程デプロイした関数を選択->「設定」タブをクリック。
test.png

「編集」ボタンをクリック。
スクリーンショット 2021-06-12 11.09.43.png

キーに「CHANNEL_ACCESS_TOKEN」を指定し、
値に先程Line Develpersで発行した「チャネルアクセストークン」を入力し、「保存」ボタンをクリック。
スクリーンショット 2021-06-12 11.13.56.png

これで環境変数の設定は完了です!

ここで設定した環境変数は、C#側からは以下のような形で参照することができます。

string value = Environment.GetEnvironmentVariable("CHANNEL_ACCESS_TOKEN")

LambdaをAPI化

Lambda関数を作成しただけでは、まだLINEからのWebhookを受けることができません。
そこで「API Gateway」を行い、先程作成したLambda関数をAPI化します。

AWSのApiGatewayにアクセスし、「APIを作成」ボタンをクリックします。
スクリーンショット 2021-06-04 18.38.32.png

少し下にスクロールし、「REST API」の「構築」ボタンをクリックします。
スクリーンショット 2021-06-04 18.41.19.png

任意の「API名」を入力し、「APIの作成」ボタンをクリックします。
スクリーンショット 2021-06-04 18.43.56.png

APIの大枠が作成できたら、続いてリソースを作成していきます。

「アクション」から「リソースの作成」をクリックします。
リソースの作成_1.png

任意のリソース名を入力し、「API Gateway CROSを有効にする」にチェックを入れ、「リソースの作成」ボタンをクリックします。
ほげ1.png

作成したリソースにPOSTメソッドを追加していきます。
「アクション」から「メソッドの作成」をクリックします。
ほげ2_2.png

プルダウンから「POST」を選択し、
ほげ3.png

チェックアイコンをクリックすると、POSTメソッドが作成できます。
ほげ4.png

「Lambdaプロキシ統合の使用」にチェックし、
先程作成したLambda関数名を入力します。(※サジェストしてくれます)
完了したら「保存」ボタンをクリックします。
ほげ5.png

「Lambda 関数に権限を追加する」というダイアログボックスが表示されるので、
「OK」ボタンをクリックするとPOSTメソッドの作成が完了します。
a.png

POSTメソッドの作成が完了したので、続いてデプロイを行います。
「アクション」から「APIのデプロイ」をクリックします。
スクリーンショット 2021-06-04 19.01.57.png

「デプロイされるステージ」に「新しいステージ」を選択し、
「ステージ名」に任意の名前を入力し、「デプロイ」ボタンをクリックします。
スクリーンショット 2021-06-05 10.38.40.png

これでAPI化の準備は完了です!
「POST」を選択し、「URLの呼び出し」に表示されているURLがAPIのエンドポイントになるので、メモしておきます。
スクリーンショット 2021-06-05 10.42.20.png

自動応答メッセージをOFF

デフォルトの設定では、ユーザがLINEで文章を送ると自動的にメッセージが返信される設定になっています。
今回は作成したbotから返信を行うので、デフォルトの自動応答メッセージ機能をOFFにする必要があります。

LINE Official Account Managerにログインします。

作成したチャンネルをクリックします。
スクリーンショット 2021-06-10 18.24.06.png

画面右上の「設定」をクリックします。
test4.png

レフトナビの「応答設定」をクリックします。
※ちなみにこの画面でアカウント名やプロフィール画像を変更できます。
スクリーンショット 2021-06-10 18.32.15.png

・応答モード: 「Bot」
   「チャットモード」にすると、Webhookが利用できません。

・あいさつメッセージ: 「オン」or「オフ」
   友達登録時の初回自動送信メッセージのON/OFF切り替えになります。
   こちらは好みで良いと思います。

・応答メッセージ: 「オフ」
   今回は自分で作成したプログラムから応答するので、オフにしておきます。

・Webhook: 「オン」
   オンでないとLINE botが作成できないですね!

スクリーンショット 2021-06-10 18.34.21.png

これでこの画面での設定は完了です。
あともう少しです!がんばりましょう!

Webhook登録

先程発行したAPIのエンドポイントを、LINE DevelopersにてWebhook URLとして登録します。

LINE Developersにアクセスし、
作成したチャンネルのページにアクセスし、
「Messaging API設定」タブを選択します。

スクリーンショット 2021-06-05 11.19.40.png

・ページ下部までスクロールし、Webhookの利用をON
・Webhook設定の「編集」をクリックし、先程発行したAPIのURLを登録します。
test01.png

Webhook URLの設定が完了したら、「検証」ボタンをクリックし、疎通確認を行います。
正常に疎通できている場合は、「成功」と表示されます。
スクリーンショット 2021-06-10 18.16.19.png

LINEアプリで最終確認

最後は先程の画面に表示されているQRコードを読み取って友達登録を行い、
LINEアプリからも正常に動作するか確認してみましょう!

以上です!お疲れ様でした!

蛇足

参考までに今回私が作成したconpassのイベント検索ができるLINE botも紹介させて下さい。
048dzyjf.png

git: https://github.com/ryohei0109-develop/SearchConnpassLineBot

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3