📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

 
(同じ利用者による、間の3版が非表示)
60行目: 60行目:
<br>
<br>
なお、<code>@page</code>ディレクティブで明示的にルートを指定した場合は、この規約が上書きされる。<br>
なお、<code>@page</code>ディレクティブで明示的にルートを指定した場合は、この規約が上書きされる。<br>
<br><br>
== レンダーフラグメント ==
レンダーフラグメントは、UIの一部を表すデリゲート型であり、コンポーネント間でコンテンツを受け渡すための仕組みである。<br>
これは、JSXのchildren propやReactのprops.childrenに相当する概念である。<br>
<br>
また、<code>@Body</code>は、このレンダーフラグメントの特別な実装である。<br>
<br>
<syntaxhighlight lang="c#">
[Parameter]
public RenderFragment CustomContent { get; set; }
// 使用例
<div>
    @CustomContent
</div>
</syntaxhighlight>
<br>
レンダーフラグメントは、Blazorにおける重要な型であり、以下に示す用途で使用される。<br>
<syntaxhighlight lang="c#">
// LayoutComponentBaseクラスでの定義
public RenderFragment Body { get; set; }
// カスタムコンポーネントでの使用例
[Parameter]
public RenderFragment ChildContent { get; set; }
// テンプレート用途での使用例
[Parameter]
public RenderFragment<TItem> ItemTemplate { get; set; }
</syntaxhighlight>
<br>
==== @Body ====
<code>@Body</code>は、レイアウトコンポーネント内でページコンテンツを表示する場所を指定するプレースホルダーである。<br>
<br>
@Bodyは、レイアウトを使用する各ページのコンテンツが配置される場所を示す。<br>
<br>
例えば、以下に示すようなページコンポーネントが存在する場合<br>
<syntaxhighlight lang="c#">
// MainLayout.razorファイル
<div class="page">
    <div class="sidebar">
      <NavMenu />
    </div>
    <main>
      <div class="content">
          @Body
      </div>
    </main>
</div>
</syntaxhighlight>
<br>
<syntaxhighlight lang="c#">
// Pages/Counter.razorファイル
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button @onclick="IncrementCount">Click me</button>
@code {
    private int currentCount = 0;
    private void IncrementCount() => currentCount++;
}
</syntaxhighlight>
<br>
上記のCounter.razorファイルの内容が、MainLayout.razorファイルの@Body部分に展開されて表示される。<br>
<syntaxhighlight lang="c#">
// MainLayout.razorファイル
<div class="page">
    <div class="sidebar">
      <NavMenu />
    </div>
    <main>
      <div class="content">
          // ここに、Counter.razorファイルの内容が展開される
          <h1>Counter</h1>
          <p>Current count: 0</p>
          <button>Click me</button>
      </div>
    </main>
</div>
</syntaxhighlight>
<br><br>
<br><br>


291行目: 377行目:


== レイアウトの適用 ==
== レイアウトの適用 ==
Blazorのルーティングでは、レイアウトの適用も重要である。<br>
Blazorのルーティングでは、レイアウト機能も重要である。<br>
レイアウト機能により、共通のUIパーツを効率的に管理でき、ページごとに異なるレイアウトを適用することができる。<br>
<br>
_Imports.razorファイルにおいて、デフォルトレイアウトを指定して、必要に応じて個別のコンポーネントで<code>@layout</code>指示子を使用して上書きすることができる。<br>
_Imports.razorファイルにおいて、デフォルトレイアウトを指定して、必要に応じて個別のコンポーネントで<code>@layout</code>指示子を使用して上書きすることができる。<br>
<br>
==== 基本的なレイアウトファイルの構造 ====
<syntaxhighlight lang="c#">
// MainLayout.razorファイル
@inherits LayoutComponentBase
<div class="page">
    <div class="sidebar">
      <NavMenu />
    </div>
    <main>
      <div class="content">
          @Body
      </div>
    </main>
</div>
</syntaxhighlight>
<br>
==== _Imports.razorでのデフォルトレイアウト指定 ====
<syntaxhighlight lang="c#">
@using System.Net.Http
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@layout MainLayout    // デフォルトレイアウトの指定
</syntaxhighlight>
<br>
==== 個別コンポーネントでのレイアウト上書き ====
<syntaxhighlight lang="c#">
// Pages/AdminPage.razorファイル
@layout AdminLayout  // このコンポーネントのみ異なるレイアウトを使用
@page "/admin"
<h1>管理画面</h1>
</syntaxhighlight>
<br>
==== 入れ子レイアウトの例 ====
<syntaxhighlight lang="c#">
// AdminLayout.razorファイル
@inherits LayoutComponentBase
<div class="admin-layout">
    <nav class="admin-nav">
      <AdminMenu />
    </nav>
    <div class="admin-content">
      @Body
    </div>
</div>
</syntaxhighlight>
<br><br>
<br><br>


298行目: 441行目:
404エラー等のルーティングエラーは、App.razorで設定したNotFoundテンプレートによって処理される。<br>
404エラー等のルーティングエラーは、App.razorで設定したNotFoundテンプレートによって処理される。<br>
これにより、ユーザフレンドリーなエラー画面を表示することが可能である。<br>
これにより、ユーザフレンドリーなエラー画面を表示することが可能である。<br>
<br>
例えば、NotFoundセクションをカスタマイズすることにより、より使用しやすいエラー画面を提供することができる。<br>
<br>
<syntaxhighlight lang="c#">
// App.razorファイル
<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
      <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
      <PageTitle>Not found</PageTitle>
      <LayoutView Layout="@typeof(MainLayout)">
          <div class="alert alert-danger">
            <h3>ページが見つかりません</h3>
            <p>申し訳ありません。要求されたページは存在しません。</p>
            <a href="/" class="btn btn-primary">ホームに戻る</a>
          </div>
      </LayoutView>
    </NotFound>
</Router>
</syntaxhighlight>
<br>
==== カスタム404ページ ====
<syntaxhighlight lang="c#">
// Pages/CustomNotFound.razorファイル
@inject NavigationManager NavigationManager
<div class="error-container">
    <h2>404 - ページが見つかりません</h2>
    <p>リクエストされたURL: @NavigationManager.Uri</p>
    <div class="error-actions">
      <button @onclick="GoBack">前のページに戻る</button>
      <a href="/" class="btn">ホームページへ</a>
    </div>
</div>
@code {
    private void GoBack()
    {
      NavigationManager.NavigateTo(NavigationManager.Uri);
    }
}
</syntaxhighlight>
<br>
上記のファイルをApp.razorファイルで使用する。<br>
<syntaxhighlight lang="c#">
// App.razorファイル
<NotFound>
    <LayoutView Layout="@typeof(MainLayout)">
      <CustomNotFound />
    </LayoutView>
</NotFound>
</syntaxhighlight>
<br><br>
<br><br>


== 認証 / 認可 ==
== 認証 / 認可 ==
<code>[Authorize]</code>属性を使用することにより、特定のルートへのアクセスを制限することができる。<br>
<code>[Authorize]</code>属性を使用することにより、特定のルートへのアクセスを制限することができる。<br>
<br>
==== 基本的な認証要求 ====
<syntaxhighlight lang="c#">
@page "/secured-page"
[Authorize]
public class SecuredPageBase : ComponentBase
{
    // このページは認証済みユーザーのみアクセス可能
}
</syntaxhighlight>
<br>
==== 特定のロールに基づく認証 ====
<syntaxhighlight lang="c#">
@page "/admin-page"
[Authorize(Roles = "Admin")]
public class AdminPageBase : ComponentBase
{
    // 管理者ロールを持つユーザーのみアクセス可能
}
</syntaxhighlight>
<br>
==== 複数のロールの指定 ====
<syntaxhighlight lang="c#">
[Authorize(Roles = "Admin,Manager")]
// ポリシーベースの認証
[Authorize(Policy = "RequireAdminRole")]
// カスタム認証要件
[Authorize(Policy = "MinimumAgeRequirement")]
</syntaxhighlight>
<br>
==== Program.csでの認証サービスの設定 ====
<syntaxhighlight lang="c#">
builder.Services.AddAuthentication().AddCookie();
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("RequireAdminRole", policy => policy.RequireRole("Admin"));
    options.AddPolicy("MinimumAgeRequirement", policy => policy.Requirements.Add(new MinimumAgeRequirement(18)));
});
</syntaxhighlight>
<br>
==== 認証状態の確認と処理 ====
<syntaxhighlight lang="c#">
@inject AuthenticationStateProvider AuthenticationStateProvider
@code {
    private async Task<bool> IsUserAuthenticated()
    {
        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        return authState.User.Identity.IsAuthenticated;
    }
}
</syntaxhighlight>
<br><br>
<br><br>