C#の実験的なBlazor（WebAssembly＋Razor）とSignalRでチャットを作ってみた１準備編

# この投稿は何？
とりあえず[Blazor](https://github.com/aspnet/blazor)と[SignalR](https://github.com/aspnet/SignalR)を使用してシンプルなとなりますがチャットを作るところまで持って行けましたので投稿してみました。
※この記事はBlazorの0.1.0preview頃の情報を元にしています。
正直2018年06月29日現在では0.5.0previewになっており、破壊的な変更も多く入っています。
また、[Blazorが凄かった件](https://qiita.com/jsakamoto/items/20d4893f6c8cdb0356f6)のjsakamoto氏の[Blazor アプリケーションプログラミング自習書](https://github.com/jsakamoto/self-learning-materials-for-blazor-jp)は非常に役に立ちますので一読することをお勧めします。
自分もこれを見てやっちまってるゎーと思って修正したところやこんなことができるのかと追加したところがあります。（追記：2018年06月29日）
[2020年01月28日のASP.NET Blog|Blazor WebAssembly 3.2.0 Preview 1 release now available](https://devblogs.microsoft.com/aspnet/blazor-webassembly-3-2-0-preview-1-release-now-available/)
BlazorもWebAssemblyだけでなくSignalRを使用してサーバーサイドでC#ロジックを処理する仕組みを利用してSignalRをWebAssembly版の方でも簡単に利用できるようになっていました。
当記事ではJavaScriptとC#を行き来してなんとかやりくりしてJS側でサーバーからの通知をC#のインスタンスのポインタ？ハンドル？っぽいものを目安にして返してやる処理を書いていましたが、全く必要なくなりました。
その為、JSファイルが不要になりました。（ゆーてもBlazorWebAssemblyで提供しているJSが頑張ってやりくりしているだけのはずなのでまだJS不要論とはなりません。JSに比べるとDOMや通信回りなどのAPIがWebAssemblyへ提供されていないので）
なお、内部的にもかなり変わってしまっていますので、ソリューションを作り直しており、GitHubへは未反映です。
取り急ぎ実装したいという人は上記ASP.NETブログの街頭記事を参照してください。英語が分かんねーって人はChromeで開いて日本語へ翻訳してください。
（追記：2020年03月01日）

##この投稿のシリーズ

* [１準備編](https://qiita.com/lensouko/items/3aff7311887470ad0905)
* [２実装編](https://qiita.com/lensouko/items/f28dbbaf4dc8cedeff26)
* [３実用っぽいの編](https://qiita.com/lensouko/items/f4716d90e4673b118c46)

##この記事のサンプル
[ソース(GitHub)](https://github.com/lensouko/SignalBlazorR/tree/sample01)
[動作サンプル]
毎月2万円弱の請求が来るようになったのでこちらの動作サンプルは廃止しました。

##経緯
昔、knockout.js＋SignalRでチャットを作ったことがあったのですが、knockoutはかなり古いものになるため次はどうしようかと探してVue.JSを触っていました。
ところが、先日何で検索したのか忘れてしまいましたが、[C# で Single Page Web Application が書ける Blazor が凄かった件](https://qiita.com/jsakamoto/items/20d4893f6c8cdb0356f6)この投稿が検索結果に出てきたので何となく見てみたら本当にすごかったので試してみました。
で、初ASP.NET Coreだったのもあってか、色々と手間取ってしまいましたので、とりあえず動くところまで持って行けたのだから他の人の参考になるかと思いました。
なお、Blazorって何なの？って方は上記の別の方の投稿をご覧ください。

# 準備
## インストールするもの
まずはBlazorが使えるようにするために以下のSDK／ソフトをインストールします。

+ Visual Studio 2017
（~~15.6以上で可能なら15.7の方が良いらしいけど自分は15.6のままでやりました~~
 アップデートで15.7にして.NET Core も2.1系にしないとBlazorの最新版が利用できなくなりました）
+ .NET Core SDK（なるべく新しいのを入れた方がよさげ）
+ Node.js（8.3以上とあるけどとりあえず最新を入れておけばよさげ）

## ＶＳからの設定など
インストールしたらVisual Studioに拡張機能をインストールします。
ＶＳを起動してからツールのオプションより左メニューの「環境 ＝＞ 拡張機能と更新プログラム」を開き、その他拡張機能ギャラリーにＵＲＬを「[https://dotnet.myget.org/f/blazor-dev/vsix](https://dotnet.myget.org/f/blazor-dev/vsix)」で追加します。
![拡張機能設定.png](https://qiita-image-store.s3.amazonaws.com/0/244471/b015683a-3a58-fe69-5daa-d6e67da657c6.png)

次に「NuGetパッケージマネージャー ＝＞ パッケージソース」の利用可能なパッケージソースにソースを「[https://dotnet.myget.org/f/blazor-dev/api/v3/index.json](https://dotnet.myget.org/f/blazor-dev/api/v3/index.json)」で追加します。
![NuGetパッケージマネージャー設定.png](https://qiita-image-store.s3.amazonaws.com/0/244471/7b798cb2-43f9-a2a5-c6dc-938337e50ab9.png)

どちらの設定も名前はわかりやすいように好きに設定してください。
設定後、再起動が必要かもしれませんが設定反映後は「ツール＝＞拡張機能と更新プログラム」を開き、左メニューから「オンライン ＝＞ （設定で登録したBlazorのMyGetの名前）」を選択すると表示されるBlazorとRazorのランゲージサービスをインストールしてください。
![インストールする拡張機能.png](https://qiita-image-store.s3.amazonaws.com/0/244471/7dd4ac66-ce4b-51d1-fb4c-68ebfe48824b.png)

なお、自分は[Blazor - 前置環境設定](https://blog.kevinyang.net/2018/03/11/blazor/)こちらのサイトを参考にしました（ただしNuGetのURLが間違っているため画像から読み取りました。）。

設定および拡張機能のインストール指示が完了したらVS終了後に拡張機能のインストーラーが起動しますのでインストールしてください。
インストール完了後にVSを起動し、プロジェクトの新規作成で「Visual C# ＝＞ .NET Core」から「ASP.NET Core Webアプリケーション」を選択し、好きな（ただし半角英数字のみで）プロジェクト名およびソリューション名を入力してOKをおしてください。
![プロジェクトテンプレート.png](https://qiita-image-store.s3.amazonaws.com/0/244471/791ed125-dea6-5e77-58c4-d480699e4adf.png)

すると次はASP.NET Coreのプロジェクトのタイプを選択する画面が出てきますが、こちらに二つBlazor用のものが増えているはずです。
![ASPNETCoreてんぷれ.png](https://qiita-image-store.s3.amazonaws.com/0/244471/307f4d0d-c335-1aaa-5188-d28b87f1c5fd.png)
単にBlazorとあるものはクライアント（ブラウザ）側でのみ動くサーバーとの通信が不要な画面のみのWebサイト向けになっており、SignalRでは使えません。とはいえまずは練習等方はこちらでも良いかもしれません。
もう一つのBlazor(ASP.NET Core hosted)はサーバーサイドにWebAPIを作り、クライアントサイドとの連携ができるWebアプリケーション用となります。
どちらも同じようなサンプル付きでファイル一式が作られますので、まずはソリューション作成後のサンプルをいじって試すといいでしょう。

##簡単な説明
作成したソリューションには以下のプロジェクトが用意されています。
～にはソリューション作成時に入力した名前が入ります。

* ～.Client
* ～.Server
* ～.Shared

![ソリューション作成直後.png](https://qiita-image-store.s3.amazonaws.com/0/244471/f096f100-4012-8f52-c013-efffcc9542b4.png)

Clientはブラウザ内で実行されるプロジェクトで画面周りの処理およびサーバーとの通信処理を実装します。
Serverにはサーバーサイドの処理を実装しますので、DBアクセスが必要な場合はこちらで行います。
また、SignalRによるHubもこちらへ実装します。
Sharedへはクライアントとサーバーの共通で使用するデータ格納クラスを登録します。これによりサーバーとの通信が必要なページにSharedのusingを追加するだけで共通のデータ型が使用できます。JavaScriptなどでは両方で定義する必要がありましたがこの仕組みのおかげで一つで済むようになり、定義の追加や修正時に漏れが起きにくくなってとっても便利です。

#設定
##プロジェクトの参照設定
SignalRを使用する準備はできていませんし、またBlazorは更新頻度が高いためソリューション内の各プロジェクトに必要なパッケージを追加する必要があります。
なお、ClientのSignalRはNuGetで取得する.Net用ではなくJSになります。
凄かったのページで指摘を受けましたが、よく考えたらBlazor用のものではありませんので、通信機能はブラウザのものを使用せずに自前でソケットを使用しているため、ブラウザ内からは無理だよーって理由のようです。
左ができたてのソリューション、右が実際に作った後のもので左は「wwwroot」開くの忘れてました。
また、ServerのプロジェクトはSDKのディレックトリガ消えてしまってNuGetも一式NG出ていますが、起動時に取得するなどの処理をしてなんかエラーが出ているみたいですが動くので今は気にしないでおきます。（が、何が起きたのか表示してくれてないのでわからない）
![参照など.png](https://qiita-image-store.s3.amazonaws.com/0/244471/c8058383-fb9c-213e-57f6-708e7de2fdb5.png)
なお、NuGetやMyGetの追加を行う際には「プレリリースを含める」にチェックを入れてください。そのうちチェックは不要になるはずですが、現段階ではAsp.Net CoreのSignalRもBlazorも開発中のものになるためチェックを外すと拾えなくなります。

###～.Clientの参照設定
先の画像で開き忘れた「wwwroot」には「index.html」などがあり、どうやらJavaScriptファイルはこちらに置かないとダメなようです。
また、JSへの参照もこの中の「index.html」で書いておかないといけないようで、後程作成する～.cshtmlに書いては正常に動作しませんでした。
推測ですが、cshtml内の記述はコンパイル対象となるため、実行環境がWebAssemblyになるためかもしれません。

####SignalR用のJavaScriptファイルを配置
Server側が.NetCoreで動くため、通信を行うSignalRのJavaScriptファイルも.NetCore用のものが必要となります。.NET 4.X系のものと違ってJQueryを必要としないのが良いですね。
取得方法はnmp（Node.jsのパッケージマネージャーになりますのでぶっちゃけこれのためにNodeをインストールしたんじゃ？という気がします）になります。Node.jsのコンソールを起動（VSからではなくスタートメニューから）し、プロジェクトのディレクトリへ移動してください。移動法はコマンドプロンプトと同じなのでCDコマンドでおｋです。移動したら「npm install @aspnet/signalr」と入力すれば自動でコンソールのカレントディレクトリに「node_modules」ディレクトリを作成して取得してくれます。「@aspnet\signalr\dist\browser」の中にほしいファイル一式がありますのでプロジェクトの「wwwroot」ディレクトリ配下に「js」なりそれっぽい名前のディレクトリを作成してコピーしてください。minとかmapとかの説明は省きますが全部持って行ってください。

####SignalR用の参照追加
次にSignalRの受信イベントハンドラがJavaScriptでの記述となり、BlazorのC#とやり取りするメソッドの引数では最大４つまでのstringと決まっているようなので、JSON文字列へ変換してからC#側で復元する必要があります。~~そのために必要なJSONからのデシリアライザーを用意します。早いと有名なUTF8Jsonは使ったことがなかったため、試してみたものの動きませんでした。そのため自分は「Newtonsoft.Json」を参照へ追加しています。これは使い慣れたものを試してみて無理だったら他のにするという形で使いやすく動作可能なものを選択してください。~~
Blazorの0.1.0までには（いつそうなったのかは把握していません）「Newtonsoft.Json」が動かなくなっておりますので、「Microsoft.AspNetCore.Blazor.JsonUtil」を使用してください。

###～.Serverの参照設定
サーバープロジェクトはSignalR用のパッケージ「Microsoft.AspNetCore.SignalR」を一つ追加するだけで構いませんので楽です。
Coreのついていないものは.Net4.X用のものになりますので今回は使用しません。

###～.Sharedの参照設定
特にありません。そもそもServerとClientと共通で使用するデータクラスの定義を行う為だけにあるようなものですので処理がありません。何かClient側でも処理をガンガン行ってかつ、Server側でも同じことを行うといった場合は必要になるかもしれません。

#準備完了
以上でソリューションの作成及び参照などの設定が完了となります。
まだSignalRを使用するためにソースへ追記する内容などもありますが、そちらは~~忘れなければ近いうちに~~[２：実装編](https://qiita.com/lensouko/items/f28dbbaf4dc8cedeff26)で記述いたしま~~す~~した。