Azure Communication Services ことはじめ (1) : チャットができるまで

Azure Communication Services は、リアルタイム コミュニケーション基盤となるサービスで、テキスト | 音声 | ビデオ によるコミュニケーションのハブとなり、接続やコントロールを行うアプリやサービスを SDK などを用いて容易に開発できます。

今回は、Azure Communication Services を使ったアプリ開発の第一歩として、チャットができるまでを手順を追って確認し、コンソールアプリを作成してみます。

## Azure Communication Services SDK

SDK は C# | JavaScript | Java(J2EE) | Python、モバイルアプリ用に Objective-C / Swift, Java (Android) が用意されています。SDK のライブラリーは以下のようなものがあります (言語によってあるものとないものがあります)。

| ライブラリ | 内容 |
|:----------|:----------|
| Azure.Communiation | 共通クラス |
| Azure.Communication.Administration | ユーザー、アクセストークンの管理など |
| Azure.Communication.Chat | チャット機能 |
| Azure.Communication.SMS | SMS機能　|
| Azure.Communication.Calling | 音声、ビデオ、画面共有機能 |
| Azure.ResourceManager.Communication | Azure でのリソース管理 |

[Microsoft Docs > Azure Communication Services > クライアントライブラリと Rest API](https://docs.microsoft.com/ja-jp/azure/communication-services/concepts/sdk-options)

## 開発環境

- 開発環境
    - Windows 10 (Build 19042)
    - Visual Studio 2019 (ver 16.7.4)
        - [Azure の開発] ワークロード構成込み
- 開発するアプリ
    - .NET Core 3.1 Console (C#)

> 今回のアプリは、Visual Studio Code + .NET Core 3.1 (C#) 開発環境でも構築可能です。

## 0. 事前準備

Azure Portal から Azure Communication Services のサービスを新規作成します。
作成した Azure Communication Services から、接続文字列とエンドポイントを取得しておきます。

![ACS_0_準備_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/9e934c40-58e7-a2eb-2276-fae92b5aa7df.png)

## 1. チャットができるまで

今回は C#、コンソールアプリを念頭に、チャットができるまでの手順を確認します。

> 非同期(Async) 対応のメソッドも用意されていますので、Web アプリなどの場合はそちらを利用したほうが良いでしょう。

### 1-1. ユーザーを作成し、アクセストークンを取得する

接続文字列を用いて CommunicationIdentityClient を新規作成し、ユーザーの作成とアクセストークンの取得を行います。接続文字列には Azure Communication Services　にアクセスするキーが含まれています。アクセストークンの種類は Chat を指定します。(他に Calling, SMS があります)  
作成したユーザーと取得したトークンを用いて、チャットをコントロールする ChatClient を作成しておきます。

> YOUR_CONNECTION_STRING は 事前準備で取得した 接続文字列、YOUR_ENDPOINT はエンドポイントに置き換えてください。

```
var identityClient = new CommunicationIdentityClient(YOUR_CONNECTION_STRING);

CommunicationUser user = identityClient.CreateUser().Value;
string userToken = identityClient.IssueToken(
    user, scopes: new[] { CommunicationTokenScope.Chat }
    ).Value.Token;
var chatClient = new ChatClient(YOUR_ENDPOINT, new CommunicationUserCredential(userToken));
```

### 1-2. スレッドを作成し、ユーザーをメンバーとして追加する

コミュニケーションをまとめる単位としてスレッド (ChatThread) という概念(オブジェクト) があり、スレッドの中でユーザーの管理やメッセージのやり取りを行います。
ここでは ChatThread をコントロールする ChatThreadClient を作成し、ユーザーを追加します。

```
var chatThreadMember = new ChatThreadMember(user) { DisplayName = "annie" };
ChatThreadClient chatThreadClient = chatClient.CreateChatThread(
    topic: "Annie's thread", members: new[] { chatThreadMember });
```

### 1-3. メッセージをスレッドに投稿する

作成した ChatThread に ChatThreadClient からメッセージを投稿します。

```
chatThreadClient.SendMessage("Hello world!", ChatMessagePriority.Normal, "annie");
```

### 1-4. スレッドのメッセージを取得する

ChatThread に投稿されたメッセージを ChatThreadClient で読み出します。

```
Pageable<ChatMessage> chatMessages = chatThreadClient.GetMessages();
```

### 1-5. 既存のスレッドにユーザーを追加する

Step 1&2 と同様に、ユーザーを作成したあと、スレッドに追加します。

```
CommunicationUser newUser = identityClient.CreateUser().Value;
var newMember = new ChatThreadMember(new CommunicationUser(newUser.Id));
chatThreadClient.AddMembers(new[] { newMember });
```

## 2. コンソールアプリの開発

以上の手順を踏まえて、Visual Studio 2019 で C# .NET Core 3.1 コンソールアプリを作成します。

> Visual Studio Code の手順は Micrsoft Docs の [クイックスタート](https://docs.microsoft.com/ja-jp/azure/communication-services/quickstarts/chat/get-started?pivots=programming-language-csharp) を参考にしてください。

### 2-1. プロジェクトの新規作成

Visual Studio 2019 の起動画面で、**新しいプロジェクトの作成** を選択し、**コンソールアプリ(.NET Core)** を選択して作成します。

![ACS_2_開発_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/2fcfd595-69db-41a7-bbab-a4724a23a15a.png)

### 2-2. Azure Communication Services の ライブラリ をインストール

プロジェクトが作成されたら、NuGet パッケージマネージャーからライブラリをインストールします。
**Azure.Communication.Chat** を検索してインストールします。ライブラリーもまだ Beta のため (2020年10月現在)、**プレスリリースを含める** をチェックしないと表示されません。

![ACS_2_開発_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/b4ec949b-5078-6221-92e0-010ad6e0d217.png)

### 2-3. コーディング

Program.cs にコードを記述していきます。

#### 利用ライブラリー

今回は、これらのライブラリーを利用します。

> 前手順の 2. でパッケージをインストールさえしておけば、利用時に Visual Studio が自動で検出して追記します。

```Program.cs
using Azure;
using Azure.Communication;
using Azure.Communication.Administration;
using Azure.Communication.Chat;
using Azure.Communication.Identity;
```

#### 接続文字列、エンドポイントを記載する

Program の冒頭に connectionString, endpoint を記載しておきます。

> YOUR_CONNECTION_STRING は 事前準備で取得した 接続文字列、YOUR_ENDPOINT はエンドポイントに置き換えてください。

> セキュリティの観点から別の設定ファイルなどに記載して読み出すのが一般的ですが、今回は動作を確認するのみのアプリなので本体に記載しています。

```Program.cs
static string connectionString = "YOUR_CONNECTION_STRING";
static Uri endpoint = new Uri("YOUR_ENDPOINT");
```

#### CommunicationUser の作成、Token の取得、ChatThread の新規作成

まず、ユーザーには名前を入力してもらい、その名前で CommunicationUser を作成します。
新規で ChatThread を作成し、CommunicationUser を追記します。

```Program.cs
Console.WriteLine("Type your name...");
string userName = Console.ReadLine();
var identityClient = new CommunicationIdentityClient(connectionString);

CommunicationUser user = identityClient.CreateUser().Value;
var chatThreadMember = new ChatThreadMember(user) { DisplayName = userName };

string userToken = identityClient.IssueToken(user, scopes: new[] { CommunicationTokenScope.Chat }).Value.Token;
var chatClient = new ChatClient(endpoint, new CommunicationUserCredential(userToken));

chatThreadClient = chatClient.CreateChatThread(topic: userName + "'s thread", members: new[] { chatThreadMember });
```

#### メッセージの投稿、取得、表示

次にメッセージを入力してもらい、それを SendMessage で ChatThread に投稿します。

```Program.cs
Console.WriteLine("Type your message...");
string userMessage = Console.ReadLine();
chatThreadClient.SendMessage(userMessage, ChatMessagePriority.Normal, userName);
```

GetMessages で ChatThread の全メッセージを取得します。
ChatThread には投稿されたメッセージの他にスレッドの管理情報も含まれるため、メッセージのみを取り出すために message.Type == "Text" に限定して出力しています。
出力内容はお好みですが、各メッセージに付与される Id (message.Id)、ユーザー名 (message.SenderDisplayName)、メッセージ (message.content)、最初に投稿された日時 (message.CreatedOn) も合わせて出力してみます。


```Program.cs
Pageable<ChatMessage> chatMessages = chatThreadClient.GetMessages();
foreach (var message in chatMessages)
{
    if (message.Type == "Text")
    {
        Console.WriteLine("[" + message.Id + "] " + message.SenderDisplayName + ": " 
        + message.Content + " (" + message.CreatedOn + ")");
    }
}
```

以上で正しく稼働するか確認を行ってください。


## 3. ２つのコンソールアプリでチャットを行う

既存のスレッドに他のユーザーを追加できるように、加筆修正を行ったものが以下のコードになります。

[AzCommSrvsDemo202010](https://github.com/ayako/AzCommSrvsDemo202010/blob/main/ACSConsole202010/Program.cs)

コンソールを 2 つ起動することで、ユーザーを既存スレッドに追加する動作が確認できます。

![ACSConsole202010.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/c6970c98-b569-7a14-a160-d6c9957f6389.gif)