はつねの日記

Kinect, Windows 10 UWP, Windows Azure, IoT, 電子工作

Azure PortalのDiagnose and solve problems機能がすごい!

Azure PortalでSignalR Serviceの設定を色々みていたときに、ほんのちょっとの興味から[Diagnose and solve problems]をクリックしたらすごかった。

f:id:hatsune_a:20201027090909p:plain
選択式ではありますがUIがChatbotなんです。なにこれすごい(語彙www)。
ちなみにジーニーさんというらしいですよ。
ちょっとやりとりを翻訳してみましょう。

                                                                                  • -

[ジーニーさん]
こんにちは!Azure SignalRサービス診断のご紹介です。Azure SignalRサービス診断へようこそ! 私の名前はジーニーといいます。
ここでは、私がお手伝いできる可用性とパフォーマンスに関連した問題をいくつかご紹介します。あなたの問題を最もよく説明するタイルを選択してください。
[はつね]
診断設定チェックに興味がある
[ジーニーさん]
あなたのアプリを分析する間、少し時間をくださいこのタイルに関連する問題のために。検出器がロードされたら、ご自由にクリックして各トピックを調査してください。
・Connectivity log is enabled
・Messaging log is enabled

                                                                                  • -

これなら、チャットで!とかかかれているけど英語チャットとか無理!みたいなときも楽しく使えますね!

Let's use Azure Communication Services from the client

この記事は「Azure Communication Servicesをクライアントから使おう - はつねの日記」の英語翻訳となります。
This article is an English translation of "https://hatsune.hatenablog.jp/entry/2020/09/29/004734".
azure.microsoft.com
I'm looking into various ways to use Azure Commucication Services, which was announced for preview release at Microsoft Ignite 2020, through WPF apps (.NET Core).

What is Azure Communication Services?

Azure Communication Services is a service on Azure that enables communication between devices with video, voice, chat and text messaging.

It uses the same reliability and security-conscious infrastructure as Microsoft Teams, and the cloud side can add features like Teams' communication features to the app without writing any specific code.

Starting in October 2020, you'll be able to communicate via SMS and capture phone numbers to make and receive calls, but as of now, chat (remember Teams' chat) and voice and video calls (remember Teams' video conferencing) are still available in preview.

Try Chat first.

Configure the cloud side

If you want to use Azure Communication Services, create "Communication Services" in Azure Portal.
f:id:hatsune_a:20200928231054p:plain
Just specify a subscription, resource group, and name the resource to quickly create it.
f:id:hatsune_a:20200928231242p:plain
Unfortunately, you can only select the location (location) in the US yet, but we hope to be able to specify the Japanese region when the GA.
Once the creation is complete, you'll be able to create a
Resource name.communication.azure.com
An "endpoint" called "Endpoint" and a "key" to access it will be generated.
From the app, connect to Azure Communication Services with the endpoint + key.

Create the client side.

Now that we have the cloud side ready, let's create a client app. Sample apps and sample code are all examples of web apps and it's unknown how far we can go with just a Windows app, but let's try to do it as far as we can.

New Projector and Creation in WPF App (.NET Core)

Launch Visual Studio 2019 and create a new app from a WPF app (.NET Core) template. NET Core should be 3.1.

The main reason we're using .NET Core instead of .NET Framework is that we want to use a C# 8.0 asynchronous stream called await foreach. I'll explain why we want to use it later.

C# 8.0 is compatible with .NET Standard 2.1, so with the .NET Framework, there is no .NET Standard 2.1 implementation version, and .NET Core must be 3.0 or higher.

Let's nuget!

Once the new project is created, add the SDK in nuget.
f:id:hatsune_a:20200928233503p:plain
Check the Include Preview Release checkbox to add the following two SDKs

  • Azure.Communication.Administration
  • Azure.Communication.Chat

The SDK itself can be used without C# 8.0 and has been verified to work with .NET Framework 4.6.2.

Writing Code (Part 1) - Getting an access token

Get the resource name and key from Azure Portal and store them under the names ResourceName and Key.

private async Task GetAccessTokenAsync()
{
    var ConnectionString = $"endpoint=https://{this.ResourceName}.communication.azure.com/;accesskey={this.Key}";
    this.Client = new CommunicationIdentityClient(ConnectionString);
    var userResponse = await this.Client.CreateUserAsync();
    this.User = userResponse.Value;
    var tokenResponse = await this.Client.IssueTokenAsync(this.User, scopes: new[] { CommunicationTokenScope.Chat });
    this.AccessToken = tokenResponse.Value.Token;
    var expiresOn = tokenResponse.Value.ExpiresOn;

    System.Diagnostics.Debug.WriteLine($"Created a user with ID: {this.User.Id}");
    System.Diagnostics.Debug.WriteLine($"Issued a token with 'chat' scope that expires at {expiresOn}:");
    System.Diagnostics.Debug.WriteLine(this.AccessToken);
}

"Azure.Communication.Administration.CommunicationIdentityClient" with the connection string.
Then execute "CreateUserAsync" method to create the connection user.
Then, specify the connecting user and chat in the "IssueTokenAsync" method to get the access talk.

Writing Code (Part 2) - Creating Threads
var chatClient = new ChatClient(new Uri($"https://{this.ResourceName}.communication.azure.com"), new CommunicationUserCredential(this.AccessToken));
var chatThreadMember = new ChatThreadMember(this.User)
{
    DisplayName = "UserDisplayName",
    ShareHistoryTime = DateTime.UtcNow,
};
this.Thread = await chatClient.CreateChatThreadAsync(groupId, new[] { chatThreadMember });
this.ThreadId = this.Thread.Id;

Once you have obtained the access token, new "Azure.Communication.Chat.ChatClient" specifying the access token and the endpoint of Azure.Connection.Services.
Then new "Azure.Communication.Chat.ChatThreadMember" specifying the user at the time the access token was created.
Finally, execute the CreateChatThreadAsync method and you can create a new conversation thread.

Writing Code (Part 2´) - Getting the Thread

If there is already a thread, you can also get the thread by specifying the thread ID.

var item = await chatClient.GetChatThreadAsync(this.ThreadId);
Writing Code (Part 3) - Send to Chat

You can send a message to a chat thread by executing the SendMessageAsync method of the chat thread.

internal async Task SendAsync(string content)
{
    var priority = ChatMessagePriority.Normal;
    var senderDisplayName = "sender name";

    var sendChatMessageResult = await this.Thread.SendMessageAsync(content, priority, senderDisplayName);
    System.Diagnostics.Debug.WriteLine($"Send Message: {content}");
}
Writing Code (Part 4) - Receiving from Chat

Receiving messages from the chat is a bit tricky.
I'm currently trying and running a receiving loop in another thread as follows.

this.TokenSource = new CancellationTokenSource();
Task.Factory.StartNew(async () =>
{
    DateTimeOffset? startTime = DateTimeOffset.MinValue;
    while (!this.TokenSource.IsCancellationRequested)
    {
        try
        {
            var allMessages = this.Thread.GetMessagesAsync(startTime, this.TokenSource.Token);
            await foreach (var message in allMessages)
            {
                System.Diagnostics.Debug.WriteLine($"{message.Id}:{message.Sender.Id}:{message.Content}");
                startTime = (startTime < message.CreatedOn ? message.CreatedOn : startTime).GetValueOrDefault().AddSeconds(1);
            }
        }
        catch { }
    }
});

You can receive the message by executing the GetMessagesAsync method on the thread.
The result is asynchronous streaming, so we use the C# 8.0 writing style called "await foreach (var message in allMessages)" to retrieve the received messages.
When the GetMessagesAsync method is executed, the value of the first parameter- is very important.
You can specify which time you want to get the messages after the first parameter, but you can't specify the time, so you can't specify the next message after the last received message. If you specify the latest time when you got last message, you get the last message.
So we use the following method to specify last time + 1 second.

startTime = (startTime < message.CreatedOn ? message.CreatedOn : startTime).GetValueOrDefault().AddSeconds(1);

However, there is a danger that there will be an undoing when the message arrives between the last time and +1 second.

What we've learned so far (what we don't know).

I don't know how to get the differences since the last time I received a chat message (they don't exist).
I still don't know what to specify between apps to send and receive messages in the same thread between client apps.
If you look at the Azure.Communication.Services workflow, the diagram shows that even client apps have to share information to specify the same thread between apps using AppService and so on.
f:id:hatsune_a:20200929083246p:plain
Maybe it might be difficult to achieve the cloud side with just Azure.Communication.Services, but I'll look into it some more.

Azure Communication Servicesをクライアントから使おう

azure.microsoft.com
Microsoft Ignite 2020でプレビュー公開が発表されたAzure Commucication ServicesをWPFアプリ (.NET Core) から使う方法を色々調べています。

Azure Communication Servicesとは

Azure Communication Servicesは、ビデオ、音声、チャット、テキストメッセージングなどで端末間のコミュニケーションを実現するAzure上のサービスです。

Microsoft Teamsと同じ信頼性とセキュリティが考慮されたインフラストラクチャーが採用されていて、クラウド側は特に何もコードを書かずに、アプリにTeamsのコミュニケーション機能のような機能を追加できます。

2020年10月からは、SMSでの通信や電話番号を取得して電話受発信が可能になる予定ですが、現時点でも、チャット(Teamsのチャットを思い出してください)と音声およびビデオ通話(Teamsのビデオ会議を思い出してください)がプレビュー提供されています。

まずは、チャットを試してみる

クラウド側を設定する

Azure Communication Servicesを利用する場合、Azure Portalで「Communication Services」を作成します。
f:id:hatsune_a:20200928231054p:plain
サブスクリプション、リソースグループを指定して、リソース名をつけるだけでサクッと作成できます。
f:id:hatsune_a:20200928231242p:plain
残念ながら、ロケーション(場所)はまだ米国しか選択できませんが、GAされるときには日本リージョンも指定できることを期待したいです。
作成が完了すると、
リソース名.communication.azure.com
という「エンドポイント」とそこにアクセスするための「キー」が生成されます。
アプリからは、エンドポイント+キーでAzure Communication Servicesに接続します。

クライアント側を作成する

クラウド側の準備ができたので、クライアントアプリを作成しましょう。サンプルアプリやサンプルコードなどは、WEBアプリの例ばかりでWindowsアプリだけでどこまでできるのか未知数ですが、やれるところまでやってみましょう。

WPFアプリ(.NET Core)で新規プロジェクタと作成

Visual Studio 2019を起動して、WPFアプリ (.NET Core) のテンプレートから新規アプリを作成します。.NET Coreは3.1がよいでしょう。

.NET Frameworkではなく、.NET Coreにしているのは、await foreachというC# 8.0の非同期ストリームを使いたいというのが大きな理由です。なぜ、使いたいかは後述します。

C# 8.0は、.NET Standard 2.1に対応なので、.NET Frameworkだと.NET Standard 2.1の実装バージョンが存在しないし、.NET Coreも3.0以上である必要があります。

nugetしようぜ!

新規プロジェクトが作成できたら、nugetでSDKを追加します。
f:id:hatsune_a:20200928233503p:plain
[プレビューリリースを含める]チェックボックスにチェックを入れて、次の2つのSDKを追加します。

Azure.Communication.Administration
Azure.Communication.Chat
なお、SDK自体は、C# 8.0でなくても利用可能で、.NET Framework 4.6.2でも動作することは確認済です。

コードを書く(その1) - アクセストークンの取得

Azure Portalからリソース名とキーを取得して、ResourceNameとKeyという名前で格納しておきます。

private async Task GetAccessTokenAsync()
{
    var ConnectionString = $"endpoint=https://{this.ResourceName}.communication.azure.com/;accesskey={this.Key}";
    this.Client = new CommunicationIdentityClient(ConnectionString);
    var userResponse = await this.Client.CreateUserAsync();
    this.User = userResponse.Value;
    var tokenResponse = await this.Client.IssueTokenAsync(this.User, scopes: new[] { CommunicationTokenScope.Chat });
    this.AccessToken = tokenResponse.Value.Token;
    var expiresOn = tokenResponse.Value.ExpiresOn;

    System.Diagnostics.Debug.WriteLine($"Created a user with ID: {this.User.Id}");
    System.Diagnostics.Debug.WriteLine($"Issued a token with 'chat' scope that expires at {expiresOn}:");
    System.Diagnostics.Debug.WriteLine(this.AccessToken);
}

接続文字列を指定して「Azure.Communication.Administration.CommunicationIdentityClient」をnewします。
次に「CreateUserAsync」メソッドを実行して接続ユーザーを作成します。
そして、「IssueTokenAsync」メソッドに接続ユーザーとチャットを指定してアクセストークを取得します。

コードを書く(その2) - スレッドの生成
var chatClient = new ChatClient(new Uri($"https://{this.ResourceName}.communication.azure.com"), new CommunicationUserCredential(this.AccessToken));
var chatThreadMember = new ChatThreadMember(this.User)
{
    DisplayName = "UserDisplayName",
    ShareHistoryTime = DateTime.UtcNow,
};
this.Thread = await chatClient.CreateChatThreadAsync(groupId, new[] { chatThreadMember });
this.ThreadId = this.Thread.Id;

アクセストークンが取得できたならば、そのアクセストークンとAzure.Connection.Servicesのエンドポイントを指定して「Azure.Communication.Chat.ChatClient」をnewします。
そして、アクセストークンを作ったときのユーザーを指定して「Azure.Communication.Chat.ChatThreadMember」をnewします。
最後にCreateChatThreadAsyncメソッドを実行すれば、会話スレッドが新規作成できます。

コードを書く(その2´) - スレッドの取得

すでにスレッドがある場合は、スレッドIDを指定してスレッドを取得することも可能です。

var item = await chatClient.GetChatThreadAsync(this.ThreadId);
コードを書く(その3) - チャットに送信

チャットスレッドのSendMessageAsyncメソッドを実行すると、そのチャットスレッドにメッセージを送信できます。

internal async Task SendAsync(string content)
{
    var priority = ChatMessagePriority.Normal;
    var senderDisplayName = "sender name";

    var sendChatMessageResult = await this.Thread.SendMessageAsync(content, priority, senderDisplayName);
    System.Diagnostics.Debug.WriteLine($"Send Message: {content}");
}
コードを書く(その4) - チャットから受信

チャットからのメッセージ受信は少々手こずっています。
現在試行錯誤しており、次のように別スレッドで受信ループを回しています。

this.TokenSource = new CancellationTokenSource();
Task.Factory.StartNew(async () =>
{
    DateTimeOffset? startTime = DateTimeOffset.MinValue;
    while (!this.TokenSource.IsCancellationRequested)
    {
        try
        {
            var allMessages = this.Thread.GetMessagesAsync(startTime, this.TokenSource.Token);
            await foreach (var message in allMessages)
            {
                System.Diagnostics.Debug.WriteLine($"{message.Id}:{message.Sender.Id}:{message.Content}");
                startTime = (startTime < message.CreatedOn ? message.CreatedOn : startTime).GetValueOrDefault().AddSeconds(1);
            }
        }
        catch { }
    }
});

スレッドに対するGetMessagesAsyncメソッドの実行を行うと、メッセージを受信することができます。
結果は非同期ストリーミングとなるので「await foreach (var message in allMessages)」というC# 8.0の書き方で受信したメッセージを取り出します。
なお、GetMessagesAsyncメソッド実行時の第一パラメータ―の指定値が非常に重要になります。
第一パラメータにどの時刻以降のメッセージを取得するかを指定できますが、あくまでも時刻指定なので、前回受信メッセージの次のメッセージからというような明確な指定ができません。しかも、前回取得したときの最新時刻を指定すると前回メッセージを取得していまいます。
そこで、次のようにして前回+1秒後を指定するようにしています。

startTime = (startTime < message.CreatedOn ? message.CreatedOn : startTime).GetValueOrDefault().AddSeconds(1);

しかし前回と+1秒の間にメッセージが届いたときには取りこぼしが発生しそうな危険性があります。

ここまでで分かったこと(わからないこと)

チャットのメッセージを受信するときに前回以降の差分を取得する方法が分からない(存在しない)
クライアントアプリ間で同じスレッドにメッセージを送受信するには、アプリ同士で何を指定すればよいかがまだわからない
Azure.Communication.Servicesの動作フローを見るとクライアントアプリでもAppServiceなどを使ってアプリ間で同じスレッドを指定するための情報を共有しないといけないような図となっています。
f:id:hatsune_a:20200929083246p:plain
もしかしたら、クラウド側をAzure.Communication.Servicesだけで実現するのは難しいかもしれないのですが、もう少し、調べてみようと思います。

ずっとこれを待っていた!Azure Communication Servicesプレビュー版登場!

azure.microsoft.com

I've been waiting for this for a long time, and now the Azure Communication Services preview is available!

[EN]

It's an Azure service for adding video, voice, chat and text messaging capabilities to your app.

If you used to do things like putting a WebRTC server in AppService or VM, you can leave it to Azure.

The good thing about this is that Azure takes care of security and everything else, so you don't have to worry about server operations and security audits on the app development side.

This seems to be the same grade of service that is used behind Microsoft Teams.

It's one of the big new features in Azure in conjunction with Ignite, and we'll be covering it here on the blog as we go through the material.

[JP]

ビデオ、音声、チャット、テキスト メッセージングの機能をアプリに追加するためのAzureのサービスです。

いままでだったら、AppServiceやVMにWebRTCサーバーを入れてみたいなことをやっていたのがAzureにお任せできます。

これのいいところはセキュリティなどもろもろをAzure側が担保してくれるので、アプリ開発側でのサーバー運用やセキュリティ監査が大幅に軽減できる点です。

これ、Microsoft Teamsの裏側で使われているのと同じグレードのサービスといえるようです。

IgniteにあわせたAzureの新機能の中でも大注目の1つなので、資料をを見ながら、このブログでもご紹介していく予定です。

 

{Kinect]Azure Kinect DK

<p>ついにAzure Kinectが!</p><p><a title="https://azure.microsoft.com/ja-jp/services/kinect-dk/" href="https://azure.microsoft.com/ja-jp/services/kinect-dk/">https://azure.microsoft.com/ja-jp/services/kinect-dk/

プレオーダーもはじまってますね!</p><p><br></p><p>複数台連携がAzure Kinect側でできるみたいなので連携したときにアプリからどう見えるか知りたい。</p>

2018/09/25のAzureの注目アップデート

AzureのUpdateがすごい量でてきました。

ぱっと見て、自分が注目している部分のアップデートをピックアップしてみました。

 

BLOB使いやすくて好きなのです。で、高スループットのものがでてきましたね。

BLOBいいけど速度どうなの?という方にも安心ですね。

https://azure.microsoft.com/ja-jp/blog/introducing-azure-premium-blob-storage-limited-public-preview/?irgwc=1&OCID=AID681541_aff_7593_1243925&tduid=(ir_d29e067eNbedaf2b2710a463509a078b8)(7593)(1243925)(TnL5HPStwNw-gt.c5nteSLzUDkvPulOjyA)()&irclickid=d29e067eNbedaf2b2710a463509a078b8

 

そして、Azure Signal R ServiceがGA(generally available)です。東日本リージョンでも使えるようになりました。

SignalR使ているところは、裏側をこれに置き換える検討しないとなー。

https://azure.microsoft.com/en-us/blog/azure-signalr-service-now-generally-available/?irgwc=1&OCID=AID681541_aff_7593_1243925&tduid=(ir_d29e067eNbedaf2b2710a463509a078b8)(7593)(1243925)(TnL5HPStwNw-LGYhziMgBF0y9tTqG7eUpQ)()&irclickid=d29e067eNbedaf2b2710a463509a078b8

Quick Startを後で見てみましょう。

https://github.com/aspnet/AzureSignalR-samples

 

クラウド使っているときのDDoS対策は?なんて聞かれることもありますよね?

Azure DDos Protectionを使って攻撃緩和レポートなどがみれるようになるようです。

https://azure.microsoft.com/en-us/blog/ddos-protection-attack-analytics-rapid-response/?irgwc=1&OCID=AID681541_aff_7593_1243925&tduid=(ir_d29e067eNbedaf2b2710a463509a078b8)(7593)(1243925)(TnL5HPStwNw-qsBdAjswrbw0UR2YfoNHfw)()&irclickid=d29e067eNbedaf2b2710a463509a078b8

ついでに、Azure FirewallもGAですね。

 

そして、Cognitive ServiceのSpeech Serviceがグローバル提供(特定のデータセンター選ばなくてよい)になって、サポート言語も17言語(と地域)が増えて30言語になりましたね。

https://azure.microsoft.com/en-us/blog/global-scale-ai-with-azure-cognitive-services/?irgwc=1&OCID=AID681541_aff_7593_1243925&tduid=(ir_d29e067eNbedaf2b2710a463509a078b8)(7593)(1243925)(TnL5HPStwNw-4vE0gsjztG1AzuVHLNuw_Q)()&irclickid=d29e067eNbedaf2b2710a463509a078b8

 

Ignite合わせで色々出てきましたね。

来年はIgniteもいきたいですね。

Azrue Cognitive Serviceのセキュリティ

Cognitive Serviceのセキュリティを調べるために検索すると下記の様な記事がヒットします。

ascii.jp

ここの記事の中で

「顧客データを広告やマーケティング目的でマイニングしない」、「マイクロソフト社員であっても顧客データへのアクセスは制限される」、「サービス利用終了時には顧客データを削除する」

というAzureにおける方針に対して、Coginitive Serviceは除外されるとあります。

この記事は、2017年8月の記事ですが、確かにその当時は、Translator Text APIなどはは有料プランでno traceを指定しないとサービスの向上のためにデータの再利用(もちろん利用終了後も残る)していました。

 

しかしながら、最近は、無料プランであってもno traceがデフォルトに変わっています。最新の状況がどこかに記載されていないかと探してみると、以下のURLを発見しました。

Microsoft Trust Center |Microsoft Cognitive Services

上記のURLには次のような記載があります。

 

「Cognitive Services で一般提供されている多くのサービスは、Azure サービスに即しており、Computer Vision、Face、Content Moderator、Text Analytics、Bing Speech、Translator Speech、Translator Text API v3、Language Understanding の各サービスは、そのような移行を果たしています。これらのサービスについては、セキュリティ センターの Microsoft Azure のセクションをご確認ください。」

2018年8月現在では、Bing Search Services以外のほぼすべての

Cognitive ServiceがAzure自体のセキュリティに準拠ととなっています。

どのようなことかといえば、Bing Search Servicesが準拠していない部分をみるとわわかりやすいでしょう。同様に上記のURLにある説明を引用してみましょう。

マイクロソフトの製品とサービスを改善するために、Bing Search Services データを使用する場合があります。たとえば、基礎となるアルゴリズムとモデルを、時間をかけて改善するために、お客様が Bing Search Services に提供した検索クエリを使用する場合があります。

つまり、入力したデータはサービスの改善に再利用され、また、利用終了後も保持されるということになります。最初に紹介した記事の内容と一致しますね。つまり、検索クエリという特性上、Bing Search Serviceだけは新しい方針に移行できなかったということになります。

 

なお、マイクロソフトの翻訳アプリや音声認識アプリなどは、データ再利用すると記載されている場合があります。つまり、APIとして利用した場合はデータ再利用なし、アプリとしてマイクロソフト内部的にAPIを使うときはデータ再利用ありでサービス向上という2方針になっているようですね。