Blazor 気になってます。最初出てきた時に、これはいいものなのでは?と思ったけど実験的プロジェクトだったので触らなかったのですが、.NET Core 3.0 で入るので触ろうと思います。
実験的な段階の初期からあったブラウザーの WebAssembly で動くモード以外にもサーバーサイド Blazor というのがあって、こっちがどうも今のところ推奨っぽいです。サーバーサイド Blazor はサーバー側で処理やってクライアントサイドには SignalR を使って更新内容とかを伝えてるみたい。
なるほど、これなら初回起動時に各種 dll のダウンロードが走って起動が重いという問題も起きませんね。
準備
VS2019 と .NET Core 3.0 preview と Blazor 拡張機能を入れましょう。
Blazor の拡張機能を入れると ASP.NET Core Web application を作成するウィザードで ASP.NET Core 3.0 を選ぶと Blazor 関係のテンプレートが追加されます。
作ってみよう
Blazor (server-side) を選択して作成しました。Startup.cs を見てみると AddServerSideBlazor とか MapBlazorHub とか、それっぽいのが追加されています。
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using HelloBlazor.Data; namespace HelloBlazor { public class Startup { // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddServerSideBlazor(); services.AddSingleton<WeatherForecastService>(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); }); } } }
何も変更せず実行してみると動きます。
Startup.cs を見てみるに、初期ページは Pages/_Host.cshtml
で _Host.cshtml
は普通の Razor 構文で書かれたページで App をレンダリングしているようです。
App は恐らく App.razor
で開いてみると、なんじゃこりゃってなりました。
@* The Router component displays whichever component has a @page directive matching the current URI. *@ <Router AppAssembly="typeof(Startup).Assembly" />
雰囲気を察するに、Pages フォルダー以下の @page
のついてるものを、その URL で出してくれるものと見受けられる。ルーティングの仕組み持ちってことで SPA 作成が捗りそう。
ハローワールド
じゃぁハローワールドします。心機一転で ASP.NET Core 3.0 で空のプロジェクトを作ります。 Startup.cs を開いて ConfigureServices メソッドを以下のようにします。
public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddServerSideBlazor(); }
見ての通り RazorPages と ServerSideBlazor の有効化です。 続けて Configure メソッドの UseEndpoints の部分にも Blazor を追加しておきます。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); }); }
Pages フォルダーを作って、そこに _Host.cshtml
を作ります。とりあえず余計なものはつかないようにチェック全部外しました。
なんか、EntityFramework とか追加されてしまった…とりあえず気を取り直して以下のように編集しました。
@page "/" @namespace HelloWorldBlazor.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>_Host</title> </head> <body> <app>@(await Html.RenderComponentAsync<App>())</app> <script src="_framework/blazor.server.js"></script> </body> </html>
この RenderComponentAsync の App から Blazor の世界なのかな?あと、_framework/blazor.server.js
を参照するために UseStaticFiles が Startup.cs に必要だったみたいです。
次は App を作っていきます。プロジェクト直下に App.razor
というファイルを作ります。特にテンプレートは無いっぽいのでテキストファイルとして作りました。
何も考えずにハローワールドって書きます。
<h1>Hello world</h1>
実行すると出ました。
ちゃんと Blazor なのかこれだとわかりにくいので @functions
を足してみました。
<h1>Hello world</h1> <p>@Count</p> <button onclick="@Increment">Increment</button> @functions { int Count { get; set; } void Increment() => Count++; }
動いた。
ルーティング
せっかくなんてルーティングしてみます。App.razor
を以下のように変更します。
<Microsoft.AspNetCore.Components.Routing.Router AppAssembly="typeof(App).Assembly" />
プロジェクトテンプレートで生成したやつは単に Router タグでしたが、これは _Imports.razor
にあらかじめ using が書かれてるから省略できてるって類のものっぽいですね。
そして Pages に Index.razor と Next.razor を作ります。以下のように編集しました。
Index.razor
@page "/" <h1>Index</h1> <a href="/Next">Next</a>
Next.razor
@page "/Next" <h1>Next</h1>
実行してみると…思った通りに動きました。
まとめ
大してドキュメントを読まなくても ASP.NET Core MVC とかで Razor を軽く触ったことがあれば、@functions { ... }
の下に C# のクラスの中身を書いていくという雰囲気くらいの理解で上記くらいのことは簡単に出来ました。
雰囲気つかめたので、今度は色々ドキュメントを読み漁ってみよう。