第一印象は「敷居が高そうなフレームワーク」だったが、むしろ従来のWebフレームワークよりも様々な種類のアプリをすばやく簡単に作れるようにと、Web開発の敷居を下げようとしてくれているフレームワークだった。
1つ1つの技術もすごいけど、これらが集結して相乗効果を生んでいる点がさらに魅力的。Webアプリなのにクライアントとサーバー間の壁を感じず、ネイティブアプリを作る感覚でシームレスに開発できる。
View開発
Web開発で避けて通れない画面の開発において、Blazorでは再利用性の高い開発方法を使えるので、開発・保守コストを下げられる。
✔️ コンポーネント指向
UI(画面の)要素の全ては「コンポーネント」で構成されているという考え方。
- ボタン、入力欄、テキストブロックなど1つ1つの部品はコンポーネント。
- それらを組み合わせて1セットにまとめたものもコンポーネント。
- 1つのページもたくさんのコンポーネントから成るコンポーネント。
コンポーネント指向はBlazorに限った話ではない
例えばReact.jsもコンポーネント指向。
コンポーネントを再利用するメリット
コンポーネント指向のメリットは、コンポーネントを再利用できること。
同じコンポーネントを複数個所に使いたい場合、再利用することでコード記述量が少なくて済み、開発スピードや保守性が向上する。
例えば、カウンターを1つのWebアプリの中に5個設置したいとすると、Counterというコンポーネントを1つ定義するだけで、5か所にカウンターを表示できる。純粋なHTMLだと、Counterコンポーネントの定義を5箇所にコピペしないといけない。
✔️ Razor
HTMLにC#コードを埋め込んで書ける技術および記法。
Webブラウザが解釈できるのは純粋なHTMLなので、RazorビューエンジンがC#で書かれた部分から動的にHTMLを生成し、HTMLデータを完成させてブラウザに渡す。
HTMLを動的にレンダリングするメリット
HTMLファイルの数を削減できる。
例えば、平社員ユーザーと部長ユーザーがいて、同じページでも部長だけに表示したい特別なボタンがあるとする。
単純なHTMLなら、部長専用のページと平社員専用のページ、というように2つのほぼ同じHTMLファイルを作成しないといけないが、RasorならC#でif文を使って「部長なら表示する、平社員なら表示しない」と、1つのファイルに書けば済む。
他言語にも同じような仕組みがある
例えば、JavaのJSP(JavaServerPage)はHTMLの中にJavaコードを埋め込むことができる仕組み。
BlazorとRazorの違い
BlazorとRazorは名称が似ているので混同しやすいが異なるもの。
- Blazor…フレームワークの種類
-
Rasor…HTMLにC#コードを埋め込む技術
Blazor以前のASP.NET系フレームワークでも使われている。
BlazorとRazorの関係性
BlazorではコンポーネントをRazor記法で表現する。
ちなみに、Blazor = Browser + Razor だそう。(Lはどこから来た?)
Rasor記法で書けるファイルの種類
-
.cshtmlファイル
Razor記法で書かれたファイルであると認識される。
Blazor以前からのASP.NET系フレームワークではViewの記述にこれを使う。 -
.razorファイル
Blazorにおいて、1つの「Razorコンポーネント」であると認識される。
Web技術
Blazorには便利で比較的新しいWeb技術が簡単に使えるよう組み込まれているので、従来のWebアプリにとって敷居が高いと思われたゲームアプリやチャットアプリなんかも作りやすくなることが期待できる。
✔️ WebAssembly(Wasm)
従来のWebアプリではサーバーサイドに配置するしかなかったバックエンド言語プログラムをブラウザ上で動作させる仕組み。
様々な言語で書かれたコードを、「wasmコード」というブラウザで動作する仕様のコードに変換すると、ブラウザ内の仮想マシンで実行することができる。
ブラウザで動くプログラミング言語はJavaScriptだけではなくなっている。
とはいえブラウザが解釈できるのは変換後のwasmコードであり各言語そのものではないので、変換はサーバーサイドで行う。
様々なプログラミング言語がWasmに対応している中で、C#もWasmに対応している。活用シーン例としては、通信状態に関係なく動き続けてほしいタイプのゲームなど。
✔️ SignalR
リアルタイム通信を行う技術。Microsoftが開発した技術で、ASP.NET系フレームワークで使えるライブラリ。
従来のWebアプリにおけるサーバーは、クライアントからリクエストが届いたときに応答するだけの受け身な立場だが、リアルタイム通信ではサーバーが自ら情報をプッシュすることもできるので、例えばチャットアプリが作れる。
SignalRは既存の双方向通信技術を複数使えるが、WebSocketが使える場面ではWebSocketを優先的に使うので、内部的な技術は主にWebSocketといえる。
✔️ 「JavaScriptの代わりにC#で書ける」のはなぜ?
例えば次のカウンターの値を更新する処理は、従来のWebアプリではJavaScriptで書くだろうが、Blazorでは先述したRazor記法でC#で書かれている。
当時何も知らなかった私は「C#がJavaScriptに変換されるのかな~?!」などと思っていたが、実際はそうでなく、WebAssemblyまたはSignalRの技術でこの仕組みを実現している。
-
WebAssemblyを使う場合
初めにクライアントサイドにモジュールをダウンロードする。ダウンロードが完了したらカウンターを使えるようになる。しかしこのダウンロードが思ったより長くかかるようで、ページにアクセスしてすぐにカウンターの連打を開始してみると、初めの約1秒間ほどは値が更新されなかった。 -
SignalRを使う場合
カウンターの値を更新するために通信を行い、サーバーサイドで処理を行う。
この程度の軽い処理だと全く通信してる気がしないレスポンスの速さに感動するが、試しにサーバーを停止してみると、通信が途切れた瞬間に再接続を試行する画面に変わる。(これがSignalRのリアルタイム通信)
✔️ レンダーモード
SignalRは通信する技術で、WebAssemblyは通信しない技術。
これらは相反する技術だが、な・ん・と!
.NET8から、1つのBlazorプロジェクト内でSignalRとWebAssemblyを局所的に使い分けることができる。Razorコンポーネントのレンダリング方法を次の①~④から指定できる。最小でコンポーネント単位で指定できる。なんて柔軟なんだ!
# | モード名 | 説明 | レンダリング場所 | 方向 |
---|---|---|---|---|
① | Static Server |
静的SSR (従来のHTTP) |
サーバー | 一方向 |
② | Interactive Server |
対話的SSR (SignalR利用) |
サーバー | 双方向 |
③ | Interactive WebAssembly |
CSR (Wasm利用) |
クライアント | 双方向 |
④ | Interactive Auto |
アクセスの都度、 モードを自動で決定 (②か③のどちらか) |
サーバー または クライアント |
双方向 |
補足:アプリケーション・クラス設計
以下、公式がよく紹介している2つの設計方法例。
方法1. RazorコンポーネントからServiceクラスを呼び出す。
- 例えば、ボタンのクリックイベントにC#のメソッドを紐づけることができるようになっている。
- 中身的なロジックを「サービス」単位でC#クラスに切り出しておく。
- MVCでいうControllerが必要なく、直接Modelを呼ぶような気持ち。
方法2. razorコンポーネントからWeb APIを呼び出す
- C#ライブラリのHttpCilentサービスを使ってWeb APIを呼び出す。
- 外部サービスと連携したい時に使う方法。
- 特にクライアント完結型アプリケーション(Blazor WebAssemblyプロジェクト)でも、この方法でなら外部と通信できる。(って多分.NET8以前に苦肉の策で言ってたんやと思う)
いずれの方法でも結局は「サービス」を呼び出すことになる。
このときDIというデザインパターンが推奨される。
✔️ DI(Dependency Injection, 依存性注入)
オブジェクト指向開発において疎結合を実現するデザインパターンの一つ。
Blazor以前のASP.NET系フレームワークでも、他言語のWebフレームワークでもよく推奨されている。
DI理解の前提・背景
- クラスAがクラスBのインスタンスを生成する(呼び出す)とき、呼び出す側のクラスAを「クライアント」、呼び出される側のクラスBを「サービス」という。
- このとき、「クラスAはクラスBに依存している」と言う。
- 依存関係を少なくする「疎結合」な設計ができると、開発品質が向上する。
DIの詳しい説明
-
Javaで説明されているが、説明がとても分かりやすい。
https://docs.sakai-sc.co.jp/article/software-engineering/dependency-injection.html -
C#での説明。Webフレームワークで実際に使うやり方とは少し違うが、説明が詳細。
https://qiita.com/saeki4n/items/22a276dcac9ef537ee25
BlazorでDIする方法
ASP.NET Coreと同じ簡単3ステップ。
- あるサービスの、インタフェースと具象クラスを作成する。
- Program.cs 内で、サービスコンテナに、そのサービスのインタフェースと具象クラスを対にして登録する。
- クライアントが、自身のコンストラクタに受け取りたいサービスのインタフェース型引数を指定する。(コンストラクタインジェクションの場合)
✔️ インスタンスのライフサイクル(スコープ)
DIに使うサービスコンテナは、登録するサービスのインスタンスのライフサイクル(スコープ)を指定できる機能も備えている。ライフサイクル(スコープ)とは、あるインスタンスを生成・破棄するタイミングのこと。Webアプリの性質を考えると結構重要。
注意1
BlazorはSignalRやWebAssemblyの技術が組み込まれていて従来型のWebアプリとは異なる性質を持つため、指定できるスコープのラインナップはASP.NET.Coreと同じだが、実際のスコープが異なる。
https://zenn.dev/yoshi1220/articles/22b99b1e3717e3
注意2
DB操作にEntityFrameworkCoreを使う場合。DbContextを登録するとき、ASP.NET CoreではAddDbContext()やAddDbContextPool()を使っていたが、BlazorではAddDbContextFactory()が推奨されている。
https://www.appsloveworld.com/entity-framework-core/100/7/difference-between-adddbcontext-and-adddbcontextfactory#google_vignette
C#っていう言語だけでも魅力的なのに、さらにBlazorとかいうフレームワークまで魅力がありすぎる!まだまだマイナーな気しかしないけど、ぜひ広まってほしい!(おわり)