読者です 読者をやめる 読者になる 読者になる

眠いしお腹すいたし(´・ω・`)

C#関連を主に書きます。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

ASP.NET CoreでWebSocketを使用するサンプルを作ってみたよ( `ー´)ノ

ごあいさつ

新年あけましておめでとうございます。

2017年もよろしくお願いします。

正月太り(´ ・ ω ・ `)

本題

SignalRではなくASP.NET CoreでWebSocketを使ったサンプルアプリを書いてみました。

今回作ったコードはこちらにあります。

github.com

ASP.NET CoreでWebSocketサーバを作るには

www.nuget.org

を使用すれば簡単に作成することができます。

今回のサンプリアプリはクライアントサイドにはVue.jsを使用しています。

解説

完成品の動き

f:id:tamafuyou:20170104140324p:plain

アクセスしたらユーザ名の入力を行って接続を行います。

f:id:tamafuyou:20170104140636p:plain

接続後にチャットで発言を行うと他のクライアントにも表示されてチャットができます。

接続、切断したユーザがいる場合にはその都度メッセージが送信されます。

参考にしたサイト

zbrad.github.io

基本的にここに書かれている通りに作っていけばよい感じです。

qiita.com

ASP.NET CoreでVue使う場合にどうすればよいか考えるのに参考にしました。

使用したnugetパッケージ

サーバサイド

基本的に前述の参考サイトの通りに作成します。

今回はChatClientクラス ChatServerクラスの2クラスで構成しました。

ChatClientクラス

aspnetcore_webspcket_sample/ChatClient.cs at master · yuka1984/aspnetcore_webspcket_sample · GitHub

System.Net.WebSockets.WebSocketクラスを内包してクライアントとの通信を行うクラスです。

RecieveJoinAsyncでチャット参加メッセージを受け取って、RecieveAsyncでチャットメッセージを継続して受け取ります。

WebSocketのRecieveAsyncメソッドの引数にArraySegmentが使用されています。

WebSocketってプロトコルの仕様上メッセージが分割されることがあるのですが、連続してデータを取得しやすくするためにArraySegmentを使用してバッファ内でセグメント毎に受信します。

単純なテキストメッセージで分割するようなパターンってないと思いますが。

今回はObserver/Observableパターンで送信と受信を実装を行ってみました。

RecieveAsync中に受信したメッセージはIObservable.Subscribeにて購読を行っている人に配信されて、WebSocketがクローズされた場合にはOnCompleteが流れるて購読が解除される形になります。

OnNextが呼ばれるとメッセージをクライアントに送信します。

次にIObserver/IObservableをどのように利用しているかを見てみます。

ChatServerクラス

aspnetcore_webspcket_sample/ChatServer.cs at master · yuka1984/aspnetcore_webspcket_sample · GitHub

public void Map(IApplicationBuilder app)
{
    app.UseWebSockets();
    app.Use(Acceptor);
}

マップ関数にてIApplicationBuilderへの登録を行っていてリクエストが来た時にAcceptor関数が実行されます。

Accepter関数はTask型になっていますが、この関数が終了するとHttpリクエストが返答されて終了します。

WebSocket接続だった場合にはクローズされます。

ですのでWebSocketを繋ぎっぱなしにしておくにはawaitで留まっている必要があります。

gist.github.com

Accepter関数はこのようになっているのですが

まず最初にWebSocketリクエストなのかを判定しています。

そうでなかった場合はMiddlewareチェインの次を実行して関数を終了しています。

これは別にチェインの次を実行する必要はなくてhttpcontextのResponseにステータスコード400を指定してBadReqestにして終了してしまったりしてもOKです。

WebSocketリクエストであった場合には AcceptWebSocketAsyncを実行してWebSocketクラスを取得します。

このWebSocketクラスを使用して、先ほど説明したChatClientクラスを作成します。

ChatClient.RecieveJoinAsyncを実行してチャット参加メッセージを受信します。

参加がOKだった場合には接続中のクライアントに新規参加メッセージを送信し、クライアント間での接続を行っています。

// ほかのクライアントと相互接続
x.Subscribe(client);
client.Subscribe(x);

この部分でIObserver/IObservableパターンが活きています。

クライアント間でお互いに購読登録を行うことで、メッセージストリームが流れた時にそのまま送信が行われます。

今回はそのままお互いにSubscribeしていますが、例えばWhereをいれて流れるメッセージを制御したりSelectでメッセージを調整したり色々な事が出来たりします。

Reactiveプログラミング面白い(^^)/

相互接続が完了したら受信待機します。

これだけでサーバ側でチャットが成り立ってしまいます(^◇^)

aspnetcore_webspcket_sample/Startup.cs at master · yuka1984/aspnetcore_webspcket_sample · GitHub

あとはStartupクラスでmiddlewareの登録を行ってあげればOKです。

クライアントサイド

aspnetcore_webspcket_sample/index.html at master · yuka1984/aspnetcore_webspcket_sample · GitHub

このファイル一つです。さぼってhtmlファイルの中にコードも書いちゃいました。

Vue.jsとかbootstrapとか取り込んでいる部分は前述の参考サイトを見てください。

gist.github.com

実際のスクリプトはこんな感じです。

あんまり工夫もなくoldなJavaScriptな感じで大変申し訳ないです。

新しめのJavaScriptは今勉強中です。

gist.github.com

Htmlはこんな感じ。

結構良い感じで書けます。

Vue.jsって凄くよくできてて感心してます。

今回はあまり使っていませんがC#のMVVMでReactivePropertyを使用したパターンをVue.jsだけで実現できる感じなんですよね。

今回は以上です。 ではでは(^^)/