Adaptive CardsでImBackに準ずる動作をさせる方法

Bot Builder SDK V4リリース記念ということで、Adaptive CardでボタンをクリックされたときにHeroCardなどのImBackに準じたメッセージをBotサービス側に送る方法をシェアします。

## ImBackとは？
ImBackというのは、以下のようなHeroCardに付いている「Adaptive Card」ボタンをクリックすると、あたかもユーザー側から「Adaptive」というテキストが入力されたかのようにBot側にメッセージを返す仕掛けです。
![HeroCard.png](https://qiita-image-store.s3.amazonaws.com/0/245269/55be9e8e-fecc-3a17-d8a3-999080578399.png)

## HeroCardでImBackするには
コードで表すとこういった感じ。

```C#:HeroCardSample.cs
// <copyright file="HeroCardSample.cs" company="Shunji Sumida">
// Copyright (c) Shunji Sumida. All rights reserved.
// </copyright>

namespace Shunji.AdaptiveCard.Cards
{
	using System.Collections.Generic;
	using Microsoft.Bot.Schema;

	/// <summary>
	/// The sample hero card.
	/// </summary>
	public class HeroCardSample : HeroCard
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="HeroCardSample"/> class.
		/// </summary>
		public HeroCardSample()
		{
			this.Title = "Hero Card";
			this.Text = "This is Hero Card. Which card do you want to show?";
			this.Images = new List<CardImage>
            {
				new CardImage("http://adaptivecards.io/content/cats/2.png"),
			};
			this.Buttons = new List<CardAction>
            {
				new CardAction(ActionTypes.ImBack, "Adaptive Card", value: "Adaptive"),
				new CardAction(ActionTypes.ImBack, "Hero Card", value: "Hero"),
			};
		}
	}
}
```

``new CardAction()``内で``ActionTypes.ImBack``とすることで、ボタンがクリックされた時に``value``に指定された文字列をBotに送信します。

## Adaptive CardでImBackするには
一方、Adaptive CardでBotにデータを送信するためには、以下のようなAdaptive Cardの定義ファイル（JSON形式）の``actions``で定義された``type``に``Action.Submit``をセットします。

```son:AdaptiveCardSample.json
{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.0",
  "body": [
    {
      "type": "Image",
      "url": "http://adaptivecards.io/content/cats/2.png",
      "size": "",
      "spacing": "none"
    },
    {
      "type": "TextBlock",
      "text": "Adaptive Card",
      "size": "medium",
      "weight": "bolder"
    },
    {
      "type": "TextBlock",
      "text": "This is Adaptive Card. Which do you want to show?"
    }
  ],
  "actions": [
    {
      "type": "Action.Submit",
      "title": "Adaptive Card",
      "data": "Adaptive!"
    },
    {
      "type": "Action.Submit",
      "title": "HeroCard",
      "data": "Hero"
    }
  ]
}
```

しかし、これだけではただHTMLのFormでPOSTするのと同様です。Input要素がなければ何もデータは送信されないので、ボタンクリック時にユーザー入力として送信したいテキストデータを``actions``の``data``にセットします。そうすると、従来のHeroCardのようなRich CardでImBackを設定した場合と同様に、Botに``data``で設定したテキストがユーザー入力として送られます。

## Botアプリケーション側では
``data``要素をつけると、他のRichCardと同様にユーザー入力としてBotに送られるということはとても大事なポイントです。もしも、AdaptiveCardで``data``要素がない場合、SubmitされただけなのでBot側では受け取る```Activity.Text```はnullになります。例えば、押されたボタンの情報をInput要素として送るようにしても、それらのデータは```Activity.Value```に格納されてしまうので同じロジックで従来のRichCardと同様に扱えないことを意味します。

```C#:EchoWithCounterBot.cs
public async Task OnTurnAsync(ITurnContext context, CancellationToken token = default(CancellationToken))
{
	if (context.Activity.Type == ActivityTypes.Message)
	{
		if (!string.IsNullOrWhiteSpace(context.Activity.Text))
		{
			Activity reply = context.Activity.CreateReply();
			reply.Attachments = new List<Attachment>();
			switch (context.Activity.Text)
			{
				case "Adaptive":
					reply.Attachments.Add(this.CreateAdaptiveCardAttachment());
					break;
				case "Hero":
					reply.Attachments.Add(new HeroCardSample().ToAttachment());
					break;
				default:
					break;
			}

			await context.SendActivityAsync(reply);
		}
	}
}
```

このAdaptive Cardで「HeroCard」ボタンをクリックすると、以下のように「Hero」というテキストがBotに送信されるようになりました。
![AdaptiveCard.png](https://qiita-image-store.s3.amazonaws.com/0/245269/48786d93-a924-e311-f826-9f1e5e887aa6.png)
呼び出されたHeroCard。
![HeroCard.png](https://qiita-image-store.s3.amazonaws.com/0/245269/b916651b-4597-d7dc-5021-7b9d8c3dc88e.png)
以降、何度でもHeroCardとAdaptiveCardを行き来できるようになりました。Bot側のコードも従来のRichCardと同様のコードでAdaptiveCardに対応できています。

## コード全体
コードの全体は以下のリポジトリにアップロードしてあります。
[https://github.com/narista/BotBuilderSamples](https://github.com/narista/BotBuilderSamples)

## 参考
[Bot Builder SDK V4 サンプル集](https://github.com/Microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore)
[Adaptive Card](http://adaptivecards.io/)