Blazor WebAssembly を試してみようかなと思い立ったので以下のドキュメントを写経してみました。
プロジェクトテンプレートのインストール
今のところプレビューなので自前で入れます。.NET Core SDk 自体も 3.1.102 以降である必要があります。私は、現時点での最新版の 3.1.201が入っていました。以下のコマンドでプロジェクトテンプレートをいれます。
dotnet new -i Microsoft.AspNetCore.Components.WebAssembly.Templates::3.2.0-preview2.20160.5
入れると、Visual Studio のプロジェクトテンプレートの Blazor アプリの中に Blazor WebAssembly App が生えます。
右下の ASP.NET Core hosted にチェックを入れると、ASP.NET Core のプロジェクトも作れて、そこに WebAssembly も入れてデプロイ出来るので Azure WebApps とかにデプロイするのが楽そうなので、それのチェックを入れて作ります。
新規作成すると、以下のようなテンプレートが生成されます。
この段階で ASP.NET Core 側の API を叩いて画面に表示する例のコードまで入ってい
るのはありがたいですね。Server 側プロジェクトにある WetherForecastController が WebAPI です。
Client 側プロジェクトの Pages/FetchData.razor を見ると以下のように WetherForecast の URL 叩いています。いいね。
ローカル実行
何も考えずにローカル実行をするとブラウザーが立ち上がって WebAssembly の Blazor が動きますね。完璧。
Azure にデプロイ
Azure WebApps にデプロイしてみましょう。デプロイするのは Server 側のプロジェクトです。右クリックから発行を選びます。
適当に発行先を選んで(もしくは新規作成)デプロイをすると、本当にすんなりと動きます。
WebApp とかだと https://サイト名.azurewebistes.net/直下に作られるので気にしなくていいのですが、そうではなくて https://example.com/YourAppName/のようなパスの下に展開されるときはアプリのベースパスの設定が必要なので、デプロイするときは、そこに気を付けましょう。
起動シーケンスを少し見てみる
プレビューなのでデプロイまで、もう少しハマると思ったら、何もハマらなかったのでちょっと拍子抜けしました。少し WebAssembly 上での起動時のシーケンスでも追ってみようと思います。
Client 側プロジェクトには Program.cs があります。ここにある Main メソッドがクライアントサイドの C# としてのエントリーポイントになるでしょう。
見てみると以下のような感じで WebAssmeblyHostBuilder を作ってルートのコンポーネントの登録をしたり、Http 呼び出しに使う HttpClient クラスの登録をしてから実行してるように見えます。
usingSystem;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;usingSystem.Text;usingMicrosoft.AspNetCore.Components.WebAssembly.Hosting;usingMicrosoft.Extensions.DependencyInjection;namespaceHelloBlazor.Client{publicclassProgram{publicstaticasyncTaskMain(string[]args){varbuilder=WebAssemblyHostBuilder.CreateDefault(args);builder.RootComponents.Add<App>("app");builder.Services.AddBaseAddressHttpClient();awaitbuilder.Build().RunAsync();}}}App クラスはどうなっているかというと、ただの App.razor ファイルです。
<RouterAppAssembly="@typeof(Program).Assembly"><FoundContext="routeData"><RouteViewRouteData="@routeData"DefaultLayout="@typeof(MainLayout)"/></Found><NotFound><LayoutViewLayout="@typeof(MainLayout)"><p>Sorry, there's nothing at this address.</p></LayoutView></NotFound></Router><Found Context="routeData">の部分と <RouteView RouteData="@routeData"の routeData は、名前が一致していないといけないようですね。DefaultLayout は typeof(MainLayout)となっているので、Shared/MainLayout.razorがレイアウト定義に使われています。
@inherits LayoutComponentBase
<divclass="sidebar"><NavMenu/></div><divclass="main"><divclass="top-row px-4"><ahref="http://blazor.net"target="_blank"class="ml-md-auto">About</a></div><divclass="content px-4">
@Body
</div></div>@Bodyでレイアウトファイルを適用したファイルの中身が展開される場所なんでしょうね。
App.razor の Router タグは自動的に RouteAttributeが適用されているもの(.razor ファイル内で @pageが指定されているもの)を探してくれます。
例えば Pages/Index.razorを見ると @page "/"と書かれています。
@page "/"
<h1>Hello, world!</h1>
Welcome to your new app.
<SurveyPromptTitle="How is Blazor working for you?"/>これで、デフォルトの https://example.com/などのような URL にアクセスされたときに自動的に Index.razorに行きつくようになっています。
Program.cs の builder の Services に自前クラスを追加することで DI も動きますね。
例えばこんな感じ MyClass を追加して…
usingSystem;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;usingSystem.Text;usingMicrosoft.AspNetCore.Components.WebAssembly.Hosting;usingMicrosoft.Extensions.DependencyInjection;namespaceHelloBlazor.Client{publicclassProgram{publicstaticasyncTaskMain(string[]args){varbuilder=WebAssemblyHostBuilder.CreateDefault(args);builder.RootComponents.Add<App>("app");builder.Services.AddBaseAddressHttpClient();builder.Services.AddSingleton<MyClass>();awaitbuilder.Build().RunAsync();}}publicclassMyClass{publicstringMessage=>"Hello world";}}Index.razor などで使うには @inject クラス名 変数名のような行を追加したらインジェクション出来ます。
@page "/"
@inject MyClass myClass
<h1>Hello, world!</h1><p>@myClass.Message</p>
Welcome to your new app.
<SurveyPromptTitle="How is Blazor working for you?"/>FetchData.razor のように C# のコードを .razor の中に直接うめることは出来ますが、partial class を使って .cs ファイルに分離を出来ます。
まとめ
結構いい感じに出来そうですね。HTML/CSS は好きだけど JavaScript が苦手な人にはいいかもしれない。WebAssembly 系の弱点の起動処理が重い点を除けば…。






