[LINE] For C#er (ASP.NET Core),  Line Botの作成 - Part 1 - メッセージの受信

本日はLINE APIを使ってLINE BOTを構築します。

LINEユーザーからのメッセージはWebhook経由で受信します。Azure Functionsを使ってこのWebhookを受け取り、返信をする仕組みを作ってみます。

# Azure環境の構築

Azure Functionsを構築します。[こちらのドキュメント](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-create-first-azure-function)を参照ください。もしくはこちらの過去記事「[Azure Functions - とりあえず立ち上げて公開](https://qiita.com/syantien/items/de58efcb217e0fcfa7fb)」

# Line Channelの準備など

## オフィシャルアカウント
次にチャンネル（LINEオフィシャルアカウント）の準備をします。[こちらのドキュメント](https://developers.line.biz/ja/docs/messaging-api/getting-started/)をご参照ください。



## アクセストークン、Webhook Url
オフィシャルアカウントを開設したあとは、設定よりアクセストークンとWebhook URLの設定を行います。[こちらのドキュメント](https://developers.line.biz/ja/docs/messaging-api/building-bot/)をご参照ください。

こちらの準備ができたら、オフィシャルアカウントを友達登録し、さっそく構築へと進みます。

# メッセージの受信 (Webhookの受信）

Webhookにはリクエストヘッダーとボディーがあり、下記の情報がLINEから送られてきます。

|リクエストヘッダー|説明|
|:---|:--|
|X-Line-Signature|署名の検証に使う署名|

|プロパティ|タイプ|説明|
|:---|:--|:--|
|destination|String|Webhookイベントを受信すべきボットのユーザーID。ユーザーIDの値は、U[0-9a-f]{32}の正規表現にマッチする文字列です。|
|events|Webhookイベントオブジェクトの配列|イベントの情報|

## レスポンス例
レスポンス例はこちら

```json
{
  "destination": "xxxxxxxxxx", 
  "events": [
    {
      "replyToken": "0f3779fba3b349968c5d07db31eab56f",
      "type": "message",
      "timestamp": 1462629479859,
      "source": {
        "type": "user",
        "userId": "U4af4980629..."
      },
      "message": {
        "id": "325708",
        "type": "text",
        "text": "Hello, world"
      }
    },
    {
      "replyToken": "8cf9239d56244f4197887e939187e19e",
      "type": "follow",
      "timestamp": 1462629479859,
      "source": {
        "type": "user",
        "userId": "U4af4980629..."
      }
    }
  ]
}
```

このレスポンスをC#のオブジェクトで受け取るためにはjson2csharpeを使います。JSONレスポンスデータをコピペするだけでC#のモデルを生成してくれます。
http://json2csharp.com/

結果はこちらです。

```csharp
public class Source
{
    public string type { get; set; }
    public string userId { get; set; }
}

public class Message
{
    public string id { get; set; }
    public string type { get; set; }
    public string text { get; set; }
}

public class Event
{
    public string replyToken { get; set; }
    public string type { get; set; }
    public object timestamp { get; set; }
    public Source source { get; set; }
    public Message message { get; set; }
}

public class RootObject
{
    public string destination { get; set; }
    public List<Event> events { get; set; }
}
```

`RootObject`ではわかりずらいので、`RootObject`を`ineWebhookMessageObject`に変更します。

このモデルを使って送信されてきたテキストをLogに表示をしてみます。

```csharp
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using LineApiApp.Models;

namespace LineApiApp
{
   public class LineReply
    {
        [FunctionName("ReplyToMessage")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous,"post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("Req: " + req.Body.ToString());

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

            var data = JsonConvert.DeserializeObject<LineWebhookMessageObject>(requestBody);

            log.LogInformation("Message is : " + data.events[0].message.text);

            return new OkResult();
        }
    }
}
```

### 結果


LINEでメッセージを送信
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241909/9ecc0e32-9f02-9c2e-0429-b99ec3e6ff6f.png)

FunctionsのLogsを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241909/af1d0148-79f8-120a-e5b1-ea1ad07d280e.png)


参考ドキュメント
https://developers.line.biz/ja/reference/messaging-api/#anchor-46a7f4db6a6b07848d6f7dd012f053442547ccc5

## LINEからのリクエスト！？

公開されてないとは言え、Webhookを受け取るためのAPIはネット上にあるため、先ほど受けとったWebhookが本物かどうか確認をする必要があります。

そのためにすべてのWebhook HeaderにはX-Line-Signatureという値が渡されます。この値を、HMAC-SHA256アルゴリズムを使用してリクエストボディのダイジェスト値を取得し、ダイジェスト値をBase64エンコードした値とリクエストヘッダーにある署名が一致することを確認します。

下記が確認コードになります。

```csharp
 /// <summary>
 /// Return if signature matches
 /// </summary>
 /// <param name="signature"></param>
 /// <param name="text"></param>
 /// <param name="key"></param>
 /// <returns></returns>
 private bool IsSingatureOk(string signature, string text, string key)
 {
   var textBytes = Encoding.UTF8.GetBytes(text);
   var keyBytes = Encoding.UTF8.GetBytes(key);

   using (HMACSHA256 hmac = new HMACSHA256(keyBytes))
   {
      var hash = hmac.ComputeHash(textBytes, 0, textBytes.Length);
      var hash64 = Convert.ToBase64String(hash);

      return signature == hash64;
   }
}
```

# 次

次は受信したデータに対して返信をする仕組みを作ります。

次→「[For C#er (ASP.NET Core), Line Botの作成 - Part 2](https://qiita.com/syantien/items/e4116c719af2fae7cdfe)」