次の方法で共有


ASP.NET Core Blazor フォームの概要

Note

これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 9 バージョンを参照してください。

警告

このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、「.NET および .NET Core サポート ポリシー」を参照してください。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

重要

この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

現在のリリースについては、この記事の .NET 9 バージョンを参照してください。

この記事では、Blazor でフォームを使用する方法を説明します。

入力コンポーネントとフォーム

Blazor フレームワークはフォームをサポートし、組み込みの入力コンポーネントが用意されています。

Note

サポートされていない ASP.NET Core 検証機能については、「サポートされていない検証機能」セクションで説明しています。

Microsoft.AspNetCore.Components.Forms 名前空間では以下が提供されます。

  • フォームの要素、状態、検証を管理するためのクラス。
  • 組み込み Input* コンポーネントへのアクセス。

Blazor プロジェクト テンプレートから作成されたプロジェクトには、この名前空間がアプリの _Imports.razor ファイルに含まれています。これにより、アプリの Razor コンポーネントでこの名前空間を使用できます。

標準の HTML フォームがサポートされています。 通常の HTML <form> タグを使用してフォームを作成し、送信されたフォーム要求を処理するための @onsubmit ハンドラーを指定します。

StarshipPlainForm.razor:

@page "/starship-plain-form"
@inject ILogger<StarshipPlainForm> Logger

<form method="post" @onsubmit="Submit" @formname="starship-plain-form">
    <AntiforgeryToken />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</form>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => Logger.LogInformation("Id = {Id}", Model?.Id);

    public class Starship
    {
        public string? Id { get; set; }
    }
}
@page "/starship-plain-form"
@inject ILogger<StarshipPlainForm> Logger

<form method="post" @onsubmit="Submit" @formname="starship-plain-form">
    <AntiforgeryToken />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</form>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => Logger.LogInformation("Id = {Id}", Model?.Id);

    public class Starship
    {
        public string? Id { get; set; }
    }
}

前の StarshipPlainForm コンポーネントは次のようなものです。

  • フォームは <form> 要素が出現する場所にレンダリングされます。 フォームには、Blazor フレームワークに対してフォームを一意に識別する @formname ディレクティブ属性を使用して名前が付けられます。
  • モデルはコンポーネントの @code ブロック内に作成され、パブリック プロパティ (Model) に保持されます。 [SupplyParameterFromForm] 属性は、関連付けられているプロパティの値をフォーム データから指定する必要があることを示します。 プロパティの名前と一致する要求内のデータは、プロパティにバインドされます。
  • InputText コンポーネントは文字列値を編集するための入力コンポーネントです。 @bind-Value ディレクティブ属性により、Model.Id モデル プロパティは、InputTextコンポーネントの Value プロパティにバインドされます。
  • Submit メソッドは、 @onsubmit コールバックのハンドラーとして登録されます。 このハンドラーは、ユーザーがフォームを送信すると呼び出されます。

重要

一意のフォーム名を持つ @formname ディレクティブ属性を常に使用してください。

Blazor は、既存の DOM に応答を適用する目的で要求をインターセプトすることでページ ナビゲーションとフォーム処理を強化します。レンダリングされたフォームはできるだけ多く保持されます。 この拡張機能により、ページを完全に読み込む必要がなくなります。また、コンポーネントがサーバーにレンダリングされますが、シングルページ アプリ (SPA) と同様に、はるかにスムーズな使用感が与えられます。 詳細については、「ASP.NET Core の Blazor ルーティングとナビゲーション」を参照してください。

ストリーミング レンダリングは HTML フォームでサポートされています。

Note

通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。

前の例には、フォームに AntiforgeryToken コンポーネントを含めることで、偽造防止のサポートが含まれています。 偽造防止のサポートについては、この記事の「偽造防止のサポート」セクションで詳しく説明します。

別の要素の DOM イベント (oninputonblur など) に基づいてフォームを送信するには、JavaScript を使ってフォームを送信します (submit (MDN ドキュメント))。

通常、Blazor アプリでプレーンフォームを使用する代わりに、フォームはフレームワークの EditForm コンポーネントを使用する Blazor の組み込みフォーム サポートで定義されます。 次の Razor コンポーネントでは、EditForm コンポーネントを使用して Web フォームをレンダリングするための一般的な要素、コンポーネント、Razor コードが示されています。

フォームは、Blazor フレームワークの EditForm コンポーネントを使用して定義されます。 次の Razor コンポーネントでは、EditForm コンポーネントを使用して Web フォームをレンダリングするための一般的な要素、コンポーネント、Razor コードが示されています。

Starship1.razor:

@page "/starship-1"
@inject ILogger<Starship1> Logger

<EditForm Model="Model" OnSubmit="Submit" FormName="Starship1">
    <div>
        <label>
            Identifier:
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => Logger.LogInformation("Id = {Id}", Model?.Id);

    public class Starship
    {
        public string? Id { get; set; }
    }
}
@page "/starship-1"
@inject ILogger<Starship1> Logger

<EditForm Model="Model" OnSubmit="Submit" FormName="Starship1">
    <div>
        <label>
            Identifier:
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => Logger.LogInformation("Id = {Id}", Model?.Id);

    public class Starship
    {
        public string? Id { get; set; }
    }
}

前の Starship1 コンポーネントは次のようなものです。

  • EditForm コンポーネントは、<EditForm> 要素が出現する場所にレンダリングされます。 フォームには、Blazor フレームワークに対してフォームを一意に識別する @formname ディレクティブ属性を使用して名前が付けられます。
  • モデルはコンポーネントの @code ブロック内に作成され、パブリック プロパティ (Model) に保持されます。 プロパティは EditForm.Model パラメーターに割り当てられます。 [SupplyParameterFromForm] 属性は、関連付けられているプロパティの値をフォーム データから指定する必要があることを示します。 プロパティの名前と一致する要求内のデータは、プロパティにバインドされます。
  • InputText コンポーネントは、文字列値を編集するための入力コンポーネントです。 @bind-Value ディレクティブ属性により、Model.Id モデル プロパティは、InputTextコンポーネントの Value プロパティにバインドされます。
  • Submit メソッドは、OnSubmit コールバックのハンドラーとして登録されます。 このハンドラーは、ユーザーがフォームを送信すると呼び出されます。

重要

一意のフォーム名を持つ @formname ディレクティブ属性を常に使用してください。

Blazor は、EditForm コンポーネントのページ ナビゲーションとフォーム処理を強化します。 詳細については、「ASP.NET Core の Blazor ルーティングとナビゲーション」を参照してください。

ストリーミング レンダリングEditForm でサポートされています。

Note

通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。

@page "/starship-1"
@inject ILogger<Starship1> Logger

<EditForm Model="Model" OnSubmit="Submit">
    <InputText @bind-Value="Model!.Id" />
    <button type="submit">Submit</button>
</EditForm>

@code {
    public Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit()
    {
        Logger.LogInformation("Model.Id = {Id}", Model?.Id);
    }

    public class Starship
    {
        public string? Id { get; set; }
    }
}

前の Starship1 コンポーネントは次のようなものです。

  • EditForm コンポーネントは、<EditForm> 要素が出現する場所にレンダリングされます。
  • モデルはコンポーネントの @code ブロック内に作成され、プライベート フィールド (model) に保持されます。 フィールドは EditForm.Model パラメーターに割り当てられます。
  • InputText コンポーネントは文字列値を編集するための入力コンポーネントです。 @bind-Value ディレクティブ属性により、Model.Id モデル プロパティは、InputTextコンポーネントの Value プロパティにバインドされます†。
  • Submit メソッドは、OnSubmit コールバックのハンドラーとして登録されます。 このハンドラーは、ユーザーがフォームを送信すると呼び出されます。

†プロパティのバインドについて詳しくは、「ASP.NET Core Blazor のデータ バインディング」をご覧ください。

次の例では、Starship2 コンポーネントにフォームが作成されるよう、上記のコンポーネントが変更されています。

  • OnSubmitOnValidSubmit に置き換えられています。これは、ユーザーが送信したときにフォームが有効である場合に、割り当てられたイベント ハンドラーを処理します。
  • ValidationSummary コンポーネントが追加されており、フォームの送信時にフォームが無効な場合に検証メッセージが表示されます。
  • データ注釈検証コントロール (DataAnnotationsValidator コンポーネント†) は、データ注釈を使用して検証サポートをアタッチします。
    • Submit ボタンが選択されたときに <input> フォーム フィールドが空白のままになっている場合、検証の概要 (ValidationSummary コンポーネント‡) にエラーが表示され ("The Id field is required.")、Submit呼び出されません
    • Submit ボタンが選択されたときに <input> フォーム フィールドに 10 文字より多く含まれている場合、検証の概要にエラーが表示されます ("Id is too long.")。 Submit呼び出されません
    • Submit ボタンが選択されたときに <input> フォーム フィールドに有効な値が含まれている場合、Submit が呼び出されます。

DataAnnotationsValidator コンポーネントについては、「検証コンポーネント」セクションを参照してください。 ‡ValidationSummary コンポーネントについては、「検証概要コンポーネントと検証メッセージ コンポーネント」セクションを参照してください。

Starship2.razor:

@page "/starship-2"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship2> Logger

<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship2">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <label>
        Identifier: 
        <InputText @bind-Value="Model!.Id" />
    </label>
    <button type="submit">Submit</button>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => Logger.LogInformation("Id = {Id}", Model?.Id);

    public class Starship
    {
        [Required]
        [StringLength(10, ErrorMessage = "Id is too long.")]
        public string? Id { get; set; }
    }
}
@page "/starship-2"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship2> Logger

<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship2">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <label>
        Identifier: 
        <InputText @bind-Value="Model!.Id" />
    </label>
    <button type="submit">Submit</button>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit() => Logger.LogInformation("Id = {Id}", Model?.Id);

    public class Starship
    {
        [Required]
        [StringLength(10, ErrorMessage = "Id is too long.")]
        public string? Id { get; set; }
    }
}
@page "/starship-2"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship2> Logger

<EditForm Model="Model" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <InputText @bind-Value="Model!.Id" />
    <button type="submit">Submit</button>
</EditForm>

@code {
    public Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void Submit()
    {
        Logger.LogInformation("Id = {Id}", Model?.Id);
    }

    public class Starship
    {
        [Required]
        [StringLength(10, ErrorMessage = "Id is too long.")]
        public string? Id { get; set; }
    }
}

フォームの送信を処理する

EditForm には、フォームの送信を処理するための次のコールバックが用意されています。

  • OnValidSubmit は、有効なフィールドを含むフォームが送信されたときに実行するイベント ハンドラーを割り当てるために使用します。
  • OnInvalidSubmit は、無効なフィールドを含むフォームが送信されたときに実行するイベント ハンドラーを割り当てるために使用します。
  • OnSubmit は、フォーム フィールドの検証状態に関係なく実行するイベント ハンドラーを割り当てるために使用します。 フォームは、イベント ハンドラー メソッドで EditContext.Validate を呼び出すことによって検証されます。 Validate によって true が返された場合、フォームは有効です。

フォームまたはフィールドをクリアする

フォームをリセットするには、そのモデルをクリアして既定の状態に戻します。これは、EditForm マークアップの内部または外部で実行することができます。

<button @onclick="ClearForm">Clear form</button>

...

private void ClearForm() => Model = new();

または、明示的な Razor 式を使用します。

<button @onclick="@(() => Model = new())">Clear form</button>

モデル値をクリアして既定の状態に戻すことでフィールドをリセットします。

<button @onclick="ResetId">Reset Identifier</button>

...

private void ResetId() => Model!.Id = string.Empty;

または、明示的な Razor 式を使用します。

<button @onclick="@(() => Model!.Id = string.Empty)">Reset Identifier</button>

前の例では StateHasChanged を呼び出す必要はありません。これは、イベント ハンドラーが呼び出された後にコンポーネントを再レンダリングするために、Blazor フレームワークによって StateHasChanged が自動的に呼び出されるためです。 フォームまたはフィールドをクリアするメソッドを呼び出すためにイベント ハンドラーを使用しない場合は、開発者コードで StateHasChanged を呼び出してコンポーネントを再レンダリングする必要があります。

偽造防止サポート

Program ファイルで AddRazorComponents が呼び出されると、偽造防止サービスが Blazor アプリに自動的に追加されます。

アプリは、Program ファイル内の要求処理パイプラインで UseAntiforgery を呼び出して、偽造防止ミドルウェアを使用します。 UseRouting の呼び出しの後に UseAntiforgery が呼び出されます。 UseRoutingUseEndpoints の呼び出しがある場合、UseAntiforgery の呼び出しはそれらの間に置く必要があります。 UseAntiforgery の呼び出しは、UseAuthenticationUseAuthorization の呼び出しの後に置く必要があります。

AntiforgeryToken コンポーネントでは、偽造防止トークンが非表示フィールドとしてレンダリングされ、[RequireAntiforgeryToken] 属性によって偽造防止が有効になります。 偽造防止チェックが失敗した場合、400 - Bad Request 応答がスローされ、フォームは処理されません。

EditForm に基づくフォームの場合、偽造防止を提供するため、AntiforgeryToken コンポーネントと [RequireAntiforgeryToken] 属性が自動的に追加されます。

HTML <form> 要素を基礎とするフォームの場合、AntiforgeryToken コンポーネントをフォームに手動で追加します:

<form method="post" @onsubmit="Submit" @formname="starshipForm">
    <AntiforgeryToken />
    <input id="send" type="submit" value="Send" />
</form>

@if (submitted)
{
    <p>Form submitted!</p>
}

@code{
    private bool submitted = false;

    private void Submit() => submitted = true;
}

警告

EditForm または HTML <form> 要素に基づくフォームの場合、[RequireAntiforgeryToken] 属性に required: false を渡すことで、偽造防止を無効にできます。 次の例では偽造防止が無効になり、パブリック アプリには推奨されません

@using Microsoft.AspNetCore.Antiforgery
@attribute [RequireAntiforgeryToken(required: false)]

詳細については、「ASP.NET Core の Blazor 認証と承認」を参照してください。

オーバーポスティング攻撃を軽減する

静的にレンダリングされたサーバー側フォーム (フォーム モデルを使用してデータベース内のレコードを作成および編集するコンポーネントで通常使用されるフォームなど) は、"オーバーポスティング" 攻撃 (別名 "マス アサインメント" 攻撃) に対して脆弱になるおそれがあります。 オーバーポスト攻撃は、悪意のあるユーザーが、レンダリングされたフォームの一部ではなく、開発者がユーザーに修正を許可しないプロパティのデータを処理する HTML フォームの POST をサーバーに発行したときに発生します。 "オーバーポスティング" という用語は、文字どおり、悪意のあるユーザーがフォームで "過剰に" ポストすることを意味します。

モデルの作成および更新操作に制限のあるプロパティが含まれていない場合は、オーバーポスティングは心配ありません。 ただし、保守している静的 SSR ベースの Blazor フォームを使用する場合は、オーバーポスティングに注意することが重要です。

オーバーポスティングを軽減するために、作成 (挿入) および更新操作でフォームとデータベースに対して個別のビュー モデルまたはデータ転送オブジェクト (DTO) を使用することをお勧めします。 フォームが送信されると、ビュー モデルまたは DTO のプロパティのみがコンポーネントと C# コードによって使用され、データベースが変更されます。 悪意のあるユーザーによって含まれる余分なデータは破棄されるため、悪意のあるユーザーによるオーバーポスティング攻撃を防ぎます。

拡張フォーム処理

EditForm フォームの Enhance パラメーターまたは HTML フォーム (<form>) の data-enhance 属性を使って、フォーム POST 要求に拡張ナビゲーションを採用しています:

<EditForm ... Enhance ...>
    ...
</EditForm>
<form ... data-enhance ...>
    ...
</form>

サポート外: フォームの先祖要素に拡張ナビゲーションを設定して、拡張フォーム処理を有効にすることはできません。

<div ... data-enhance ...>
    <form ...>
        <!-- NOT enhanced -->
    </form>
</div>

拡張フォームの POST は、Blazor エンドポイントでのみ機能します。 拡張フォームを Blazor 以外のエンドポイントに POST すると、エラーが発生します。

拡張フォーム処理を無効にするには:

  • EditForm の場合は、フォーム要素から Enhance パラメーターを削除します (または、それを false に設定します: Enhance="false")。
  • HTML <form> の場合は、フォーム要素から data-enhance 属性を削除します (または、それを false に設定します: data-enhance="false")。

更新された内容がサーバー レンダリングの一部でない場合、Blazor の拡張ナビゲーションとフォーム処理は DOM に対する動的な変更を元に戻す可能性があります。 要素の内容を保持するには、data-permanent 属性を使用します。

次の例では、ページが読み込まれるときに、<div> 要素の内容がスクリプトによって動的に更新されます。

<div data-permanent>
    ...
</div>

拡張ナビゲーションとフォーム処理をグローバルに無効にするには、「ASP.NET Core Blazor の起動」をご覧ください。

enhancedload イベントを使って拡張されたページの更新をリッスンする方法については、「ASP.NET Core の Blazor ルーティングとナビゲーション」をご覧ください。

例では、フォーム POST 要求用の拡張フォーム処理は採用されていませんが、「拡張フォーム処理」セクションのガイダンスに従うことで、拡張機能を採用するようにすべての例を更新できます。

例では、C# 9.0 および .NET 5 で導入されたターゲット型 new 演算子を使用します。 次の例では、new 演算子に対して型が明示的に指定されていません。

public ShipDescription ShipDescription { get; set; } = new();

C# 8.0 以前 (ASP.NET Core 3.1) を使用している場合、new 演算子に型を示すようにコード例を変更します。

public ShipDescription ShipDescription { get; set; } = new ShipDescription();

コンポーネントでは null 許容参照型 (NRT) が使用され、.NET コンパイラでは null 状態スタティック分析が実行されます。いずれも .NET 6 以降でサポートされています。 詳細については、「ASP.NET Core 5.0 から 6.0 への移行」を参照してください。

C# 9.0 以前 (.NET 5 以前) を使用している場合、例から NRT を削除します。 これは通常、コード例の型から疑問符 (?) と感嘆符 (!) を削除するだけです。

.NET SDK は、.NET 6 以降を対象とするとき、暗黙的なグローバル using ディレクティブをプロジェクトに適用します。 この例では、ロガーを使用してフォーム処理に関する情報をログに記録しますが、コンポーネントの例で Microsoft.Extensions.Logging 名前空間の @using ディレクティブを指定する必要はありません。 詳細については、「.NET プロジェクト SDK: 暗黙的な using ディレクティブ」を参照してください。

C# 9.0 以前 (.NET 5 以前) を使用している場合、例で必要なあらゆる API の @page ディレクティブの後、コンポーネントの先頭に @using ディレクティブを追加します。 Visual Studio (オブジェクトを右クリックして [ピーク定義] を選択) または .NET API ブラウザーを利用して API 名前空間を見つけます。

フォームとデータ注釈検証が連動するしくみを示すため、例のコンポーネントで System.ComponentModel.DataAnnotations API を全面的に利用しています。 データ注釈を使用するコンポーネントでのコード行追加を避けるには、imports ファイル (_Imports.razor) を使用して、アプリのコンポーネント全体で名前空間を使用できるようにします。

@using System.ComponentModel.DataAnnotations

フォームの例では、スター トレック ユニバースのアスペクトを参照します。 Star Trek の著作権は CBS StudiosParamount にあります ©1966-2023。

クライアント側の検証には回線が必要です

Blazor Web App において、クライアント側の検証にはアクティブな BlazorSignalR 回線が必要です。 静的サーバー側レンダリング (静的 SSR) を採用したコンポーネントのフォームでは、クライアント側の検証を利用できません。 静的 SSR を採用するフォームは、フォームの送信後にサーバー上で検証されます。

サポートされていない検証機能

[Remote] 検証属性を除き、データ注釈の組み込み検証コントロールは、すべて Blazor でサポートされています。

jQuery 検証は、 Razor コンポーネントではサポートされていません。 次のいずれかの方法をお勧めします。

サーバー上の静的にレンダリングされたフォームの場合、クライアント側検証の新しいメカニズムは、2025 年後半に .NET 10 で検討されています。 詳細については、「 回線なしの Blazor を使用してクライアント検証を使用してサーバーレンダリングフォームを作成する (dotnet/aspnetcore #51040)を参照してください。

その他のリソース