プロジェクトのファイル構成
プロジェクトのファイル構成は、通常のデスクトップアプリとはかなり異なっています。
今回のプロジェクトでポイントとなるファイルは、以下の3つのフォルダのファイルです。
フォルダ名 | 含まれるファイルの概要 |
---|---|
wwwroot | HTML、CSSファイルなどの、静的なWebコンテンツファイル |
Pages | ページのベースとなるRazorファイル |
Shared | 各ページで利用する機能毎のRazorファイル |
wwwrootフォルダ
wwwrootフォルダ以下のファイルは、Webシステムの技術者にはおなじみなものでしょう。HTML、CSSファイルや、Webフォントが含まれています。
通常のWebアプリケーションと同様、この中のindex.htmlファイルが最初に読み込まれるファイルとなります。
~略~ <body> ~略~ <script src="_framework/blazor.webassembly.js"></script> </body> </html>
index.htmlでは、scriptタグで、blazor.webassembly.jsを呼び出しています。このJavaScriptファイルで、.NETアセンブリをロードし、ランタイムを初期化して、プロジェクトのコードを実行します。
index.htmlの次に読みこまれるのは、プロジェクトフォルダ直下にあるApp.razorというファイルです。このファイルでは、同じくプロジェクトフォルダ直下にある、プロジェクトのメインプログラム(Program.cs)のアセンブリの指定と、プロジェクトのDefaultLayoutとして、MainLayoutコンポーネント(MainLayout.razor)を指定しています。
今回のテンプレートプロジェクトでは、MainLayoutコンポーネントと呼ばれる、レイアウトを構築するパーツ(コンポーネント)が使われています。このコンポーネントのような、プロジェクト全体で使われるコンテンツは、Sharedフォルダ内の各ファイルで定義されています。
なお、拡張子razorのファイルは、Razorファイルと呼ばれ、Razor構文というHTMLを拡張した構文で記述します。Razor構文のいちばんの特徴は、HTML内に直接C#のコードを記述できることです。じつは、このRazorファイル、Razor Pagesでのcshtmlファイルと同じです。Blazorフレームワークでは、拡張子がrazorに変更されました。
Sharedフォルダ
Sharedフォルダには、各ページのメニューを実現するコンポーネント(MainLayout.razor、NavMenu.razor)や、子コンテンツのコンポーネント(SurveyPrompt.razor)が含まれています。
MainLayout.razorは、各ページ共通のレイアウトを定義しているテンプレートとなっています。
@inherits LayoutComponentBase ① <div class="sidebar"> <NavMenu /> ② </div> <div class="main"> <div class="top-row px-4"> <a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a> </div> <div class="content px-4"> @Body ③ </div> </div>
Razor構文では、@マークを使って通常のHTMLコードと区別します。1行目の@inheritsは、Razorディレクティブと呼ばれるもので、@マークの後に予約済みのキーワードで識別される構文です。
1行目の@inheritsディレクティブ(①)では、継承元として、Blazorで提供されるLayoutComponentBaseクラスを指定しています。レイアウトとしてテンプレートを定義する場合は、このLayoutComponentBaseクラスを継承する必要があります。
<NavMenu />(②)は、左サイドバーのコンテンツ(NavMenu.razor)です。
③のBodyプロパティには、Pagesフォルダで定義した各コンテンツが格納されて、表示されます。
Pagesフォルダ
Pagesフォルダにあるindex.razorファイルが、Webアプリのトップページに表示されるコンテンツを定義したものです。
@page "/" <h1>Hello, world!</h1> Welcome to your new app. <SurveyPrompt Title="How is Blazor working for you?" />
1行目の@pageディレクティブでは、ページのURLを指定します。ここでは"/"、つまりWebサイトのルートのページ(で表示されるメインコンテンツ)ということになります。
最後の<SurveyPrompt>タグは、子コンテンツ(コンポーネント)を挿入することを示しています。この例では、SurveyPrompt.razorファイルで定義されているコンテンツ(アンケートページへのリンク)が、このタグの位置に挿入されます。
前述したように、Razor構文ではC#のコードを含めることができます。たとえば、@マークの後に、次のようなコードを追加すると、現在時刻が表示されます。DateTimeオブジェクトが返す文字列を、直接ページに埋め込むことになります。
<p>@DateTime.Now.ToString("yyyy年MM月dd日 HH時mm分ss秒")</p>
Counter.razor
今回のWebアプリのメニューからCounterを選ぶと、Counter.razorで定義されたページが表示されます。このページでは、ボタンをクリックすると、値が1加算されて表示されます。
@page "/counter" <h1>Counter</h1> <p>Current count: @currentCount</p> ① <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> ② @code { ③ private int currentCount = 0; private void IncrementCount() ④ { currentCount++; } }
Counter.razorでは、ボタンクリック時に呼び出されるイベントハンドラとして、IncrementCountメソッドが定義されています(④)。Razor構文では、@onclickディレクティブで、クリックのイベントハンドラを指定します(②)。
@codeディレクティブ以降のブロックでは(③)、変数とメソッドを定義しています。ここでは、praivateというアクセス修飾子が使われています。Razorファイルでは、そのファイル名と同じ名前で、C#のクラスが生成されます。つまり、この変数とメソッドのコードは、Counterクラスのメンバの定義となっているのです。
IncrementCountメソッドで呼び出されると、変数のcurrentCountがインクリメントされます。また同時に、currentCountの値の表示も自動的に変更されます(①)。
FetchData.razor
FetchData.razorでは、少し長めのコードになっていますが、動作的にはシンプルです。
~略~ @code { private WeatherForecast[] forecasts; protected override async Task OnInitializedAsync() { forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json"); } ~略~
このRazorファイルでは、weather.jsonというJSON形式のデータファイルを読み込み、その内容を表示しているだけです。ただこのコードで重要なことは、weather.jsonを直接読み込んでいない点です。通常のC#であれば、StreamReaderクラスなどを使って、ファイルを読み込むことができます。ところが、WebAssemblyでは、セキュリティの制限により、ローカルにあるファイルを直接読み込むことはできません。このコードでは、System.Net.Httpクラスを利用して、Http通信でファイルを非同期に参照しています。
最後に
今回は、Blazorの最初のステップとして、Blazorのプロジェクトテンプレートを使ったアプリケーションを作成しました。
今回のプロジェクトには、見慣れないファイルが多くあったかと思います。ただ今の段階では、すべてを理解する必要はありません。次回からは、このプロジェクトテンプレートを元にして、アプリケーションを作成して行く予定です。