Blazor - サンプルを確認する②
初めに
Blazor WebAssembly アプリのサンプルを見て、プロジェクトの構成を学びます。本記事は Server プロジェクトと Shared プロジェクトについてまとめます。
Index
Server プロジェクト
サーバー側で動作するプログラムを書くプロジェクトです。
Properties フォルダ
launchSettings.json が含まれています。Client プロジェクトにあるものと同じ情報が書かれており、デバッガーからプログラムを起動する際の各種設定をプロファイル単位で定義できます。
Controllers フォルダ
Controllers フォルダには、クライアント側から API として呼び出す処理を書くクラスをまとめておきます。
サンプルでは、WeatherForecastController.cs が入っており、
using BlazorTodoTest.Shared; using Microsoft.AspNetCore.Mvc; namespace BlazorTodoTest.Server.Controllers { [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; } [HttpGet] public IEnumerable<WeatherForecast> Get() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); } } }
[ApiController] 属性は、ASP.NET Core Web API コントローラークラスに付けられる属性です。この属性を使用すると、コントローラー内のアクションメソッドに対して自動的なモデルバインディング、バリデーションエラー処理、および一般的な Web API の機能が有効になります。
[ApiController] 属性の細かい説明はこちら。
[Route] 属性はコントローラーまたはアクションの URL パターンを指定します。[Route("[controller]")] は、コントローラーの名前をベースに URL パスが作成されることを意味します。
例えば、このコードの場合、コントローラーの名前が "WeatherForecastController" なので、[Route("[controller]")] は "[controller]" の部分を "WeatherForecast" に置き換えて、"/WeatherForecast" という URL パスにマッピングされます。クライアントが "/WeatherForecast" に対して GET リクエストを行うと、このコントローラーの Get() メソッドが呼び出されます。
※このサンプルでは Client プロジェクトの FetchData.razor から呼び出されています。
Pages フォルダ
Error.cshtml が含まれています。エラーが発生したときに表示されるページを定義しています。
@page @model BlazorTodoTest.Server.Pages.ErrorModel <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <title>Error</title> <link href="~/css/bootstrap/bootstrap.min.css" rel="stylesheet" /> <link href="~/css/app.css" rel="stylesheet" asp-append-version="true" /> </head> <body> <div class="main"> <div class="content px-4"> <h1 class="text-danger">Error.</h1> <h2 class="text-danger">An error occurred while processing your request.</h2> @if (Model.ShowRequestId) { <p> <strong>Request ID:</strong> <code>@Model.RequestId</code> </p> } <h3>Development Mode</h3> <p> Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred. </p> <p> <strong>The Development environment shouldn't be enabled for deployed applications.</strong> It can result in displaying sensitive information from exceptions to end users. For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong> and restarting the app. </p> </div> </div> </body> </html>
appsettings.json
アプリの構成設定のファイルです。開発環境、テスト環境、本番環境などで参照するサーバーやサービスを変更したいときに使います。
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
Program.cs
サーバー側の開始プログラムになります。
using Microsoft.AspNetCore.ResponseCompression; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(); builder.Services.AddRazorPages(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseWebAssemblyDebugging(); } else { app.UseExceptionHandler("/Error"); // 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.UseBlazorFrameworkFiles(); app.UseStaticFiles(); app.UseRouting(); app.MapRazorPages(); app.MapControllers(); app.MapFallbackToFile("index.html"); app.Run();
初めの部分では WebAppilication にサービスを追加し、ビルドしています。
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(); builder.Services.AddRazorPages(); var app = builder.Build();
var builder = WebApplication.CreateBuilder(args); で WebApplication ビルダーを作成します。
builder.Services.AddControllersWithViews(); で コントローラーとビューを使用した MVC(Model-View-Controller)を利用した開発が可能になります。
builder.Services.AddRazorPages(); でRazorPages を利用した開発が可能になります。
var app = builder.Build(); でビルドしています。
ここまでは、呪文のように書いておいてよいかと思われます。
// Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) //開発環境かどうかを判定 { app.UseWebAssemblyDebugging(); } else //開発環境ではない場合 { app.UseExceptionHandler("/Error"); //エラーハンドリング // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); //HSTSを有効にする }
HSTS(HTTP Strict Transport Security)は、ウェブサイトがブラウザに HTTP の代わりに HTTPS を用いて通信を行うよう指示するためのものです。http は暗号化されておらず、https は暗号化されているので https で通信を行うように変更します。
app.UseHttpsRedirection(); //httpからhttpsへのリダイレクト app.UseBlazorFrameworkFiles(); //Blazor ファイルの提供 app.UseStaticFiles(); //静的ファイルの提供 app.UseRouting(); //ルーティングの設定を有効にする app.MapRazorPages(); //Razor Pagesのエンドポイントをマップ app.MapControllers(); //コントローラーのエンドポイントをマップ app.MapFallbackToFile("index.html"); //すべてのエンドポイントにマッチしないリクエストが "index.html" ファイルにマップされる app.Run(); //実行
ルーティングについての説明はこちら。
エンドポイントは、クライアントからのリクエストを処理するための特定のリソースやアクションを指します。つまり、クライアントが要求するリソースやアクションがどのハンドラーに関連付けられるかを定義します。
例えば、/counter の URL に対して、Counter の Razor ページをマップするようにするなど、特定のリクエストに対し、RazorPage や Controller を関連付けています。
Shared プロジェクト
Shared はクライアント側とサーバー側で共通して使用したいプログラムを入れておくプロジェクトです。
サンプルでは、WeatherForecast.cs が入っています。
namespace BlazorTodoTest.Shared { public class WeatherForecast { public DateOnly Date { get; set; } public int TemperatureC { get; set; } public string? Summary { get; set; } public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); } }
補足
ApiController 属性
[ApiController] 属性は、ASP.NET Core Web API のコントローラークラスに付けられる特別なマークです。この属性を使用すると、コントローラー内のアクションメソッドに対していくつかの便利な機能が自動的に有効になります。
〇 モデルバインディング:
モデルバインディングとは、クライアントから送信されたデータを自動的にコントローラーのアクションメソッドの引数にバインドする機能です。
[ApiController] 属性を使用すると、リクエストのデータがアクションメソッドの引数に自動的にマッピングされます。そのため、データを受け取るためのコードを手動で書く必要がありません。
〇 バリデーションエラー処理:
バリデーションエラー処理は、クライアントからのリクエストが正しい形式であるかを検証し、問題がある場合に適切なエラーメッセージを生成する機能です。
[ApiController] 属性を使用すると、リクエストのバリデーションが自動的に行われ、エラーメッセージが生成されます。これにより、バリデーションエラーの処理を手動で書く必要がありません。
〇 Web API の一般的な機能:
[ApiController] 属性を使用すると、一般的な Web API の機能が有効になります。たとえば、アクションメソッドの戻り値が自動的に HTTP 応答としてシリアライズ(データを文字列に変換すること)されます。これにより、コントローラー内でデータを返すだけで、自動的に適切な応答が生成されます。つまり、[ApiController] 属性を使用すると、コントローラークラスにいくつかの便利な機能が追加され、開発者は手動でこれらの機能を実装する必要がありません。これにより、開発者はより迅速に、簡潔で効率的な Web API を作成することができます。
ルーティング
ルーティングは、クライアントからの HTTP リクエストを、適切なコントローラーとアクションメソッドにマッピングする仕組みです。つまり、どの URL パスがどのコントローラーとアクションメソッドに関連付けられるかを定義します。
例えば、以下のような URL パスがあったとします:
- /products
- /products/123
- /categories/5/products/123
ルーティングの設定によって、これらのパスが異なるコントローラーとアクションメソッドにマッピングされます。
ルーティングは、URL パターンとアクションメソッドの対応関係を定義することで機能します。例えば、以下のような設定があるとします:
app.UseRouting(); app.MapGet("/products", () => { ... }); app.MapGet("/products/{id}", (int id) => { ... }); app.MapGet("/categories/{categoryId}/products/{productId}", (int categoryId, int productId) => { ... });
上記の設定では、それぞれの URL パスに対して異なるアクションメソッドがマッピングされています:
- /products の場合、最初のアクションメソッドが実行されます。
- /products/123 の場合、2 番目のアクションメソッドが実行されます。123 のような値は、{id} のようなプレースホルダーとして扱われます。
- /categories/5/products/123 の場合、3 番目のアクションメソッドが実行されます。5 と 123 のような値は、それぞれ {categoryId} と {productId} のプレースホルダーとして扱われます。
ルーティングは、URL パスに基づいてリクエストを正しいコントローラーとアクションメソッドにディスパッチし、適切な処理を行うための重要な仕組みです。これにより、クライアントの要求に応じた適切な応答を返すことができます。