やりたいこと
- .NET 8 で、.NET 7 以前はできた ASP.NET Core でホストされた Blazor WebAssembly アプリを作成する
環境
- Windows 11 23H2
- Visual Studio Community 2022 Version 17.9.5
手順
準備
- 空のソリューションを追加
{ソリューション名}
-
Blazor WebAssembly アプリ プロジェクトを追加
-
ASP.NET Core Web API プロジェクトを追加
- クラスライブラリ プロジェクトを追加
作成したプロジェクト構成
-
{ソリューション名}
-
{ソリューション名}.UI.Client
- クライアントアプリ
-
{ソリューション名}.UI.Server
- API
-
{ソリューション名}.UI.Share
- クライアントアプリとAPIの間でやり取りするオブジェクト等
-
Server の変更
NuGet パッケージを追加
Microsoft.AspNetCore.Components.WebAssembly.Server
依存関係追加
- Client
- Share
Program.cs
の変更
Program.cs
- builder.Services.AddControllers();
+ builder.Services.AddControllersWithViews();
+ builder.Services.AddRazorPages();
Program.cs
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
+ app.UseWebAssemblyDebugging();
}
Program.cs
app.UseHttpsRedirection();
+ app.UseBlazorFrameworkFiles();
+ app.UseStaticFiles();
Program.cs
+ app.MapRazorPages();
app.MapControllers();
+ app.MapFallbackToFile("index.html");
Program.cs(完成)
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
app.UseWebAssemblyDebugging();
}
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");
app.Run();
動作確認
Swagger が開かないようにする
-
launchSettings.json
を開く - 書く環境に設定されている
"launchUrl": "swagger",
を"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
に置換
動作確認
Client の変更
依存関係追加
- Share
Weather.razor から Server の API を叩く
Weather.razor
protected override async Task OnInitializedAsync()
{
- forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json");
+ forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("weatherforecast");
}
Share を使うように変更
Share に WeatherForecast クラスを追加
このクラスを Client/Server 両方から使います。
WeatherForecast.cs
+ namespace SolutionName.UI.Share.WeatherForecastModels;
+
+ 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);
+ }
Client の WeatherForecast クラスを削除
Weather.razor
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("weatherforecast");
}
- 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);
- }
}
Client に using 追加
Weather.razor
@page "/weather"
+ @using SolutionName.UI.Share.WeatherForecastModels
@inject HttpClient Http
Server の WeatherForecast クラスを削除
WeatherForecast.cs
- namespace HigeDaruma.DemoNet8BlazorWasm.UI.Server;
-
- public class WeatherForecast
- {
- public DateOnly Date { get; set; }
-
- public int TemperatureC { get; set; }
-
- public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
-
- public string? Summary { get; set; }
- }
Server に using 追加
WeatherForecast.cs
+ using SolutionName.UI.Share.WeatherForecastModels;
using Microsoft.AspNetCore.Mvc;
動作確認
ついでに C# 12 の新機能を使う
コレクションの初期化を簡素化する
WeatherForecastController.cs
- private static readonly string[] Summaries = new[]
- {
- "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", - "Sweltering", "Scorching"
- };
+ private static readonly string[] Summaries =
+ [
+ "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
+ ];
プライマリーコンストラクターを使う(そしてフィールドを削除する)
WeatherForecastController.cs
- public class WeatherForecastController : ControllerBase
+ public class WeatherForecastController(ILogger<WeatherForecastController> logger) : ControllerBase
{
private static readonly string[] Summaries =
[
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
];
- private readonly ILogger<WeatherForecastController> _logger;
-
- public WeatherForecastController(ILogger<WeatherForecastController> logger)
- {
- _logger = logger;
- }
おわりに
.NET 8 に ASP.NET Core でホストされた Blazor WebAssembly アプリは追加されないんですかね。Blazor でクライアントを作る単一ソリューションのアプリだと API 層があった方がレイヤードアーキテクチャーを構成しやすいんですけど。
次回この続きでレイヤードアーキテクチャーを実現していこうと思います。
参考