次の方法で共有


Blazor アプリのプロジェクト構造

ヒント

このコンテンツは電子ブック、Azure の「ASP.NET Web Forms 開発者向け Blazor」からの抜粋です。これは .NET Docs から閲覧するか、オフラインで読める無料ダウンロードの PDF としても入手できます。

Blazor-for-ASP-NET-Web-Forms-Developers 電子ブックのカバー サムネイル。

プロジェクト構造が大きく異なるにもかかわらず、ASP.NET Web Forms と Blazor には共通するさまざまな概念があります。 ここでは、Blazor プロジェクトの構造を観察し、それを ASP.NET Web Forms プロジェクトと比較します。

最初の Blazor アプリを作成するには、Blazor の開始手順に従ってください。 指示に従って、ASP.NET Core でホストされている Blazor サーバー アプリまたは BlazorWebAssembly アプリのいずれかを作成できます。 ホスティングモデル固有のロジックを除き、両方のプロジェクトのコードはほぼ同じです。

プロジェクト ファイル

Blazor サーバー アプリは .NET プロジェクトです。 Blazor サーバー アプリのプロジェクト ファイルは、概ね次のような簡単なものです。

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>

</Project>

BlazorWebAssembly アプリのプロジェクト ファイルは、少し複雑になります (正確なバージョン番号は異なる場合があります)。

<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.0" PrivateAssets="all" />
  </ItemGroup>

</Project>

BlazorWebAssembly プロジェクトは、WebAssembly ベースの .NET ランタイム上のブラウザーで実行されるため、Microsoft.NET.Sdk.Web SDK ではなく Microsoft.NET.Sdk.BlazorWebAssembly をターゲットとします。 サーバーや開発者コンピューター上で行うように、.NET を Web ブラウザーにインストールすることはできません。 その結果、プロジェクトでは個別のパッケージ参照を使用して、Blazor フレームワークが参照されます。

これに対し、既定の ASP.NET Web Forms プロジェクトでは、 .csproj ファイルに約 300 行の XML が含まれており、そのほとんどはプロジェクト内のさまざまなコードおよびコンテンツ ファイルを明示的に示すものです。 .NET 5 のリリース以降、Blazor Server アプリと BlazorWebAssembly アプリは、統合された 1 つのランタイムを簡単に共有することができます。

これらはサポートされていますが、個々のアセンブリ参照は .NET プロジェクトではあまり一般的ではありません。 ほとんどのプロジェクトの依存関係は、NuGet パッケージ参照として処理されます。 .NET プロジェクトの最上位レベルのパッケージの依存関係のみ参照する必要があります。 推移的な依存関係は自動的に追加されます。 ASP.NET Web Forms プロジェクトでよく見られる packages.config ファイルを使用してパッケージを参照するのではなく、<PackageReference> 要素を使用してパッケージ参照をプロジェクトファイルに追加します。

<ItemGroup>
  <PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup>

エントリ ポイント

Blazor サーバー アプリのエントリ ポイントは、コンソール アプリで見られるように Program.cs ファイルで定義されます。 アプリを実行すると、Web アプリに固有の既定値を使用して Web ホスト インスタンスが作成されて実行されます。 Web ホストは Blazor サーバー アプリのライフサイクルを管理し、ホストレベルのサービスを設定します。 このようなサービスの例としては、構成、ログ記録、依存関係の注入、HTTP サーバーなどがあります。 このコードはほとんどが定型であり、変更されることはほとんどありません。

using BlazorApp3.Areas.Identity;
using BlazorApp3.Data;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
builder.Services.AddSingleton<WeatherForecastService>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
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.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

BlazorWebAssembly アプリでは、Program.cs でエントリ ポイントが定義されます。 コードは少し異なります。 コードは、同じホストレベルのサービスをアプリに提供するようにアプリ ホストを設定するという点で似ています。 ただし、WebAssembly アプリ ホストはブラウザーで直接実行されるため、HTTP サーバーを設定しません。

Blazor アプリでは、Global.asax ファイルを使用してアプリのスタートアップ ロジックを定義することはありません。 代わりに、このロジックは、プログラム Program.cs または Program.cs から参照される関連する Startup クラスに含まれています。 いずれにしても、このコードはアプリとアプリ固有のサービスを構成するために使用されます。

Blazor サーバー アプリでは、表示されている Program.cs ファイルを使用して、クライアント ブラウザーとサーバーの間で Blazor によって使用されるリアルタイム接続のエンドポイントを設定します。

BlazorWebAssembly アプリでは、Program.cs ファイルによって、アプリのルート コンポーネントと、それらをレンダリングする場所が定義されます。

using BlazorApp1;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

await builder.Build().RunAsync();

静的ファイル

ASP.NET Web Forms プロジェクトとは異なり、Blazor プロジェクト内のすべてのファイルを静的ファイルとして要求できるわけではありません。 wwwroot フォルダー内のファイルのみが Web アドレスを指定できます。 このフォルダーは、アプリの「Web ルート」と呼ばれます。 アプリの Web ルート以外のものは、web アドレスを指定 "できません"。 このセットアップでは、プロジェクト ファイルが Web 経由で誤って公開されないようにするための追加のセキュリティ レベルが提供されます。

構成

ASP.NET Web Forms アプリの構成は、通常 1 つ以上の web.config ファイルを使用して処理されます。 Blazor アプリには通常、web.config ファイルがありません。 ファイルがある場合、ファイルは IIS でホストされている場合に IIS 固有の設定を構成するためにのみ使用されます。 代わりに、Blazor Server アプリでは ASP.NET Core 構成の抽象化を使用します。 (BlazorWebAssembly 現在、アプリは同じ構成抽象化をサポートしていませんが、今後追加される機能である可能性があります)。たとえば、既定 Blazor のサーバー アプリでは、一部の設定が appsettings.json に格納されます。

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

ASP.NET Core プロジェクトの構成の詳細については、構成に関するセクションを参照してください。

Razor のコンポーネント

Blazor プロジェクト内のほとんどのファイルは .razor ファイルです。 Razor は、Web UI を動的に生成するために使用される HTML および C# に基づくテンプレート言語です。 この .razor ファイルは、アプリの UI を構成するコンポーネントを定義します。 コンポーネントの多くは、Blazor Server と BlazorWebAssembly アプリの両方で同一です。 Blazor のコンポーネントは、ASP.NET Web Forms のユーザー コントロールに似ています。

各 Razor コンポーネント ファイルは、プロジェクトのビルド時に .NET クラスにコンパイルされます。 生成されたクラスは、コンポーネントの状態、レンダリング ロジック、ライフサイクル メソッド、イベント ハンドラー、およびその他のロジックをキャプチャします。 コンポーネントの作成については、「Blazor を使用して再利用可能な UI コンポーネントを構築する」セクションで詳しく説明しています。

_Imports.razor ファイルは Razor コンポーネント ファイルではありません。 代わりに、これらは同じフォルダーおよびそのサブフォルダー内の他の .razor ファイルにインポートする Razor ディレクティブのセットを定義します。 たとえば、 _Imports.razor ファイルは、一般的に使用される名前空間の using ディレクティブを追加する従来の方法です。

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using BlazorApp1
@using BlazorApp1.Shared

ページ

Blazor アプリ内のページはどこにあるでしょうか。 Blazor では、ASP.NET Web Forms アプリの .aspx ファイルのように、アドレス指定可能なページに対して個別のファイル拡張子は定義されません。 代わりに、ページはコンポーネントにルートを割り当てることによって定義されます。 ルートは通常、@page Razor ディレクティブを使用して割り当てられます。 たとえば、Pages/Counter.razor ファイルで作成された Counter コンポーネントは、次のルートを定義します。

@page "/counter"

Blazor でのルーティングは、サーバー側ではなくクライアント側で処理されます。 ユーザーがブラウザーで移動すると、Blazor はナビゲーションをインターセプトし、一致するルートを使用してコンポーネントをレンダリングします。

現在、コンポーネントのルートは、 .aspx ページまたは ASP.NET Core Razor Pages のように、コンポーネントのファイルの場所によって推測されることはありません。 この機能は、今後追加される可能性があります。 各ルートはコンポーネント上で明示的に指定する必要があります。 ルーティング可能なコンポーネントを Pages フォルダーに格納することは、特別な意味を持たず、単なる慣例です。

Blazor でのルーティングの詳細については、「ページ、ルーティング、レイアウト」セクションを参照してください。

Layout

ASP.NET Web Forms アプリでは、共通ページ レイアウトはマスター ページ (Site.Master) を使用して処理されます。 Blazor アプリでは、ページ レイアウトはレイアウト コンポーネント (Shared/MainLayout.razor) を使用して処理されます。 レイアウト コンポーネントの詳細については、「ページ、ルーティング、レイアウト」セクションを参照してください。

Blazor をブートストラップする

Blazor をブートストラップするには、アプリは次のことを行う必要があります。

  • ページ上でルート コンポーネント (App.Razor) がレンダリングされる場所を指定します。
  • 対応する Blazor フレームワーク スクリプトを追加します。

Blazor サーバー アプリでは、ルート コンポーネントのホスト ページは _Host.cshtml ファイルに定義されています。 このファイルはコンポーネントではなく Razor ページを定義します。 Razor ページでは Razor 構文を使用して、サーバーアドレス指定可能なページを定義します。これは .aspx ページと非常によく似ています。

@page "/"
@namespace BlazorApp3.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
    Layout = "_Layout";
}

<component type="typeof(App)" render-mode="ServerPrerendered" />

render-mode 属性は、ルートレベルのコンポーネントをレンダリングする場所を定義するために使用されます。 RenderMode オプションは、コンポーネントをレンダリングする方法を示します。 次の表に、サポートされる RenderMode オプションについて説明します。

オプション 説明
RenderMode.Server ブラウザーとの接続が確立されると、対話形式でレンダリングされます
RenderMode.ServerPrerendered 最初に事前レンダリングされ、次に対話形式でレンダリングされます
RenderMode.Static 静的コンテンツとしてレンダリングされます

_Layout.cshtml ファイルには、アプリとそのコンポーネントの既定の HTML が含まれています。

@using Microsoft.AspNetCore.Components.Web
@namespace BlazorApp3.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="~/" />
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    <link href="css/site.css" rel="stylesheet" />
    <link href="BlazorApp3.styles.css" rel="stylesheet" />
    <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
    @RenderBody()

    <div id="blazor-error-ui">
        <environment include="Staging,Production">
            An error has occurred. This application may no longer respond until reloaded.
        </environment>
        <environment include="Development">
            An unhandled exception has occurred. See browser dev tools for details.
        </environment>
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>

    <script src="_framework/blazor.server.js"></script>
</body>
</html>

_framework/blazor.server.js へのスクリプト参照は、サーバーとのリアルタイム接続を確立し、次にすべてのユーザー操作と UI 更新を処理します。

BlazorWebAssembly アプリでは、ホスト ページは、wwwroot/index.html の下のシンプルな静的 HTML ファイルです。 <div> という id を持つ要素 app は、ルート コンポーネントのレンダリング先を示すために使用されます。

<!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>BlazorApp1</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
    <link href="BlazorApp1.styles.css" rel="stylesheet" />
</head>

<body>
    <div id="app">Loading...</div>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>
</body>

</html>

レンダリングするルート コンポーネントは、アプリの Program.cs ファイルで指定され、依存関係の挿入によってサービスを柔軟に登録できます。 詳細については、「ASP.NET Core Blazor の依存関係の挿入」を参照してください。

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

ビルド出力

Blazor プロジェクトをビルドされたら、すべての Razor コンポーネントとコード ファイルが 1 つのアセンブリにコンパイルされます。 ASP.NET Web Forms プロジェクトとは異なり、Blazor は UI ロジックのランタイム コンパイルをサポートしていません。

ホット リロードを使用したアプリの実行

Blazor サーバー アプリを実行するには、Visual Studio で F5 キーを押してデバッガーをアタッチして実行するか、Ctrl + F5 キーを押してデバッガーをアタッチせずに実行します。

BlazorWebAssembly アプリを実行するには、次のいずれかの方法を選択します。

  • 開発サーバーを使用して、クライアント プロジェクトを直接実行する。
  • ASP.NET Core を使用してアプリをホストするときに、サーバー プロジェクトを実行する。

BlazorWebAssembly アプリは、ブラウザーと Visual Studio の両方でデバッグできます。 詳細については、「ASP.NET Core BlazorWebAssembly をデバッグする」を参照してください。

Blazor Server と BlazorWebAssembly アプリの両方が、Visual Studio でホット リロードをサポートします。 ホット リロードは、Blazor アプリに対して行われた変更をブラウザーで自動的に更新する機能です。 ツール バーのアイコンからホット リロードを有効にするかどうかを切り替えることができます。

Visual Studio 2022: ホット リロード メニュー項目とアイコン。

アイコンの横にあるキャレットを選択すると、追加のオプションが表示されます。 ホット リロードのオンまたはオフ、アプリケーションの再起動、ファイルが保存されるたびにホット リロードを実行するかどうかを切り替えることができます。

Visual Studio 2022: オプションが展開されたホット リロード メニュー項目。

追加の構成オプションにもアクセスできます。 構成ダイアログでは、デバッグ時 (エディット コンティニュと共に)、デバッグなしで開始する場合、またはファイルを保存するときに、ホット リロードを有効にするかどうかを指定できます。

Visual Studio 2022: [ツール] > [オプション] > [デバッグ] > [.NET/C++ ホット リロード] ダイアログのホット リロード構成オプション。

「開発者の内部ループ」は、ホット リロードを使用して大幅に効率化されました。 ホット リロードを使用しない場合、Blazor 開発者は通常、変更が行われるたびにアプリを再起動して再実行し、必要に応じてアプリの適切な部分に移動する必要があります。 ホット リロードでは、ほとんどの場合、再起動することなく、実行中のアプリに変更を加えることができます。 ホット リロードではページの状態も保持されるため、フォームの値を再入力したり、アプリを必要な場所に戻したりする必要はありません。