ASP.NET Core Blazor のフォームと検証ASP.NET Core Blazor forms and validation

フォームと検証は、Blazor でデータ注釈を使用してサポートされています。Forms and validation are supported in Blazor using data annotations.

次の ExampleModel 型は、データ注釈を使用して検証ロジックを定義します。The following ExampleModel type defines validation logic using data annotations:

using System.ComponentModel.DataAnnotations;

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

フォームは、EditForm コンポーネントを使用して定義されます。A form is defined using the EditForm component. 次のフォームは、一般的な要素、コンポーネント、および Razor コードを示しています。The following form demonstrates typical elements, components, and Razor code:

<EditForm Model="@exampleModel" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <InputText id="name" @bind-Value="exampleModel.Name" />

    <button type="submit">Submit</button>
</EditForm>

@code {
    private ExampleModel exampleModel = new ExampleModel();

    private void HandleValidSubmit()
    {
        ...
    }
}

前の例の場合:In the preceding example:

  • フォームは、ExampleModel 型で定義されている検証を使用して、name フィールドのユーザー入力を検証します。The form validates user input in the name field using the validation defined in the ExampleModel type. モデルはコンポーネントの @code ブロック内に作成され、プライベート フィールド (exampleModel) に保持されます。The model is created in the component's @code block and held in a private field (exampleModel). フィールドは、<EditForm> 要素の Model 属性に割り当てられます。The field is assigned to the Model attribute of the <EditForm> element.
  • InputText コンポーネントの @bind-Value は次のようにバインドします。The InputText component's @bind-Value binds:
  • DataAnnotationsValidator 検証コンポーネントは、データ注釈を使用して検証サポートをアタッチします。The DataAnnotationsValidator validator component attaches validation support using data annotations.
  • ValidationSummary コンポーネントは、検証メッセージの概要を示します。The ValidationSummary component summarizes validation messages.
  • HandleValidSubmit は、フォームが正常に送信される (検証に合格する) とトリガーされます。HandleValidSubmit is triggered when the form successfully submits (passes validation).

組み込みフォームのコンポーネントBuilt-in forms components

一連の組み込みコンポーネントを、ユーザー入力の受信と検証に使用できます。A set of built-in components are available to receive and validate user input. 入力は、それらが変更されたときとフォームが送信されたときに検証されます。Inputs are validated when they're changed and when a form is submitted. 次の表に、使用できる入力コンポーネントを示しています。Available input components are shown in the following table.

入力コンポーネントInput component … とレンダリングRendered as…
InputCheckbox <input type="checkbox">
InputDate<TValue> <input type="date">
InputFile <input type="file">
InputNumber<TValue> <input type="number">
InputRadio <input type="radio">
InputRadioGroup <input type="radio">
InputSelect<TValue> <select>
InputText <input>
InputTextArea <textarea>
入力コンポーネントInput component … とレンダリングRendered as…
InputCheckbox <input type="checkbox">
InputDate<TValue> <input type="date">
InputNumber<TValue> <input type="number">
InputSelect<TValue> <select>
InputText <input>
InputTextArea <textarea>

注意

InputRadioInputRadioGroup は、ASP.NET Core 5.0 以降で使用できます。The InputRadio and InputRadioGroup components are available in ASP.NET Core 5.0 or later. 詳細については、この記事のバージョン 5.0 以降を選択してください。For more information, select a 5.0 or later version of this article.

すべての入力コンポーネント (EditForm を含む) で、任意の属性がサポートされています。All of the input components, including EditForm, support arbitrary attributes. コンポーネント パラメーターに一致しない属性は、レンダリングされる HTML 要素に追加されます。Any attribute that doesn't match a component parameter is added to the rendered HTML element.

入力コンポーネントにより、フィールド変更時に検証するための既定の動作が提供されます。これには、フィールドの状態を反映するようにフィールドの CSS クラスを更新することが含まれます。Input components provide default behavior for validating when a field is changed, including updating the field CSS class to reflect the field state. 一部のコンポーネントには、便利な解析ロジックが含まれます。Some components include useful parsing logic. たとえば、InputDate<TValue>InputNumber<TValue> では、解析不能な値を検証エラーとして登録することによって、解析不能な値を適切に処理します。For example, InputDate<TValue> and InputNumber<TValue> handle unparseable values gracefully by registering unparseable values as validation errors. NULL 値を受け入れることができる型では、ターゲット フィールドの NULL 値の許容もサポートしています (int? など)。Types that can accept null values also support nullability of the target field (for example, int?).

次の Starship 型では、以前の ExampleModel よりも大きなプロパティとデータ注釈のセットを使用して検証ロジックを定義しています。The following Starship type defines validation logic using a larger set of properties and data annotations than the earlier ExampleModel:

using System;
using System.ComponentModel.DataAnnotations;

public class Starship
{
    [Required]
    [StringLength(16, ErrorMessage = "Identifier too long (16 character limit).")]
    public string Identifier { get; set; }

    public string Description { get; set; }

    [Required]
    public string Classification { get; set; }

    [Range(1, 100000, ErrorMessage = "Accommodation invalid (1-100000).")]
    public int MaximumAccommodation { get; set; }

    [Required]
    [Range(typeof(bool), "true", "true", 
        ErrorMessage = "This form disallows unapproved ships.")]
    public bool IsValidatedDesign { get; set; }

    [Required]
    public DateTime ProductionDate { get; set; }
}

前の例では、データ注釈が存在しないため、Description は省略可能です。In the preceding example, Description is optional because no data annotations are present.

次のフォームでは、Starship モデルで定義されている検証を使用してユーザー入力を検証します。The following form validates user input using the validation defined in the Starship model:

@page "/FormsValidation"

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="@starship" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <p>
        <label>
            Identifier:
            <InputText @bind-Value="starship.Identifier" />
        </label>
    </p>
    <p>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="starship.Description" />
        </label>
    </p>
    <p>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="starship.Classification">
                <option value="">Select classification ...</option>
                <option value="Exploration">Exploration</option>
                <option value="Diplomacy">Diplomacy</option>
                <option value="Defense">Defense</option>
            </InputSelect>
        </label>
    </p>
    <p>
        <label>
            Maximum Accommodation:
            <InputNumber @bind-Value="starship.MaximumAccommodation" />
        </label>
    </p>
    <p>
        <label>
            Engineering Approval:
            <InputCheckbox @bind-Value="starship.IsValidatedDesign" />
        </label>
    </p>
    <p>
        <label>
            Production Date:
            <InputDate @bind-Value="starship.ProductionDate" />
        </label>
    </p>

    <button type="submit">Submit</button>

    <p>
        <a href="http://www.startrek.com/">Star Trek</a>, 
        &copy;1966-2019 CBS Studios, Inc. and 
        <a href="https://www.paramount.com">Paramount Pictures</a>
    </p>
</EditForm>

@code {
    private Starship starship = new Starship() { ProductionDate = DateTime.UtcNow };

    private void HandleValidSubmit()
    {
        ...
    }
}

EditForm では、変更されたフィールドと現在の検証メッセージを含む、編集プロセスに関するメタデータを追跡するカスケード値 として EditContext を作成します。The EditForm creates an EditContext as a cascading value that tracks metadata about the edit process, including which fields have been modified and the current validation messages.

EditContext または EditForm.ModelいずれかEditForm に割り当てます。Assign either an EditContext or an EditForm.Model to an EditForm. 両方とも割り当てることはサポートされておらず、ランタイム エラー が生成されます。Assignment of both isn't supported and generates a runtime error.

EditForm では、有効および無効のフォームを送信するための便利なイベントが提供されます。The EditForm provides convenient events for valid and invalid form submission:

カスタム コードを使用して検証をトリガーし、フィールドの値をチェックするには、OnSubmit を使用します。Use OnSubmit to use custom code to trigger validation and check field values.

次に例を示します。In the following example:

  • Submit ボタンが選択されると、HandleSubmit メソッドが実行されます。The HandleSubmit method executes when the Submit button is selected.
  • EditContext.Validate を呼び出して、フォームを検証します。The form is validated by calling EditContext.Validate.
  • 検証結果に応じて、追加のコードが実行されます。Additional code is executed depending on the validation result. OnSubmit に割り当てられたメソッドにビジネス ロジックを配置します。Place business logic in the method assigned to OnSubmit.
<EditForm EditContext="@editContext" OnSubmit="@HandleSubmit">

    ...

    <button type="submit">Submit</button>
</EditForm>

@code {
    private Starship starship = new Starship() { ProductionDate = DateTime.UtcNow };
    private EditContext editContext;

    protected override void OnInitialized()
    {
        editContext = new EditContext(starship);
    }

    private async Task HandleSubmit()
    {
        var isValid = editContext.Validate();

        if (isValid)
        {
            ...
        }
        else
        {
            ...
        }
    }
}

注意

検証メッセージを EditContext から直接クリアする Framework API は存在しません。Framework API doesn't exist to clear validation messages directly from an EditContext. このため、通常、フォームの新しい ValidationMessageStore に検証メッセージを追加することはお勧めしません。Therefore, we don't generally recommend adding validation messages to a new ValidationMessageStore in a form. 検証メッセージを管理するには、この記事で説明するように、ビジネス ロジック検証コード検証コンポーネントを使用します。To manage validation messages, use a validator component with your business logic validation code, as described in this article.

表示名のサポートDisplay name support

"このセクションは、.NET 5 リリース候補 1 (RC1) 以降の ASP.NET Core に適用されます。 "This section applies to ASP.NET Core in .NET 5 Release Candidate 1 (RC1) or later.

次の組み込みコンポーネントでは、DisplayName パラメーターを使用した表示名がサポートされています。The following built-in components support display names with the DisplayName parameter:

InputDate コンポーネントの例を次に示します。In the following InputDate component example:

  • 表示名 (DisplayName) が birthday に設定されています。The display name (DisplayName) is set to birthday.
  • コンポーネントは、DateTime 型として BirthDate プロパティにバインドされています。The component is bound to the BirthDate property as a DateTime type.
<InputDate @bind-Value="BirthDate" DisplayName="birthday" />

@code {
    public DateTime BirthDate { get; set; }
}

ユーザーが日付の値を指定しなかった場合、次のように検証エラーが表示されます。If the user doesn't provide a date value, the validation error appears as:

The birthday must be a date.

検証コンポーネントValidator components

検証コンポーネントでは、フォームの EditContextValidationMessageStore を管理することで、フォームの検証をサポートします。Validator components support form validation by managing a ValidationMessageStore for a form's EditContext.

Blazor フレームワークでは、検証属性 (データ注釈)に基づいて検証サポートをフォームにアタッチする DataAnnotationsValidator コンポーネントを提供します。The Blazor framework provides the DataAnnotationsValidator component to attach validation support to forms based on validation attributes (data annotations). カスタム検証コンポーネントを作成して、同じページの異なるフォームの検証メッセージを処理するか、フォーム処理の異なるステップ (たとえば、クライアント側の検証の後のサーバー側の検証) で同じフォームの検証メッセージを処理します。Create custom validator components to process validation messages for different forms on the same page or the same form at different steps of form processing, for example client-side validation followed by server-side validation. このセクションで示す検証コンポーネントの例 (CustomValidator) は、この記事の次のセクションで使用します。The validator component example shown in this section, CustomValidator, is used in the following sections of this article:

注意

多くの場合、カスタムのデータ注釈検証属性をカスタム検証コンポーネントの代わりに使用できます。Custom data annotation validation attributes can be used instead of custom validator components in many cases. フォームのモデルに適用されるカスタム属性は、DataAnnotationsValidator コンポーネントを使用してアクティブ化されます。Custom attributes applied to the form's model activate with the use of the DataAnnotationsValidator component. サーバー側の検証で使用する場合、モデルに適用されるカスタム属性はすべてサーバー上で実行可能である必要があります。When used with server-side validation, any custom attributes applied to the model must be executable on the server. 詳細については、「ASP.NET Core MVC でのモデルの検証」を参照してください。For more information, see ASP.NET Core MVC でのモデルの検証.

ComponentBaseから検証コンポーネントを作成します。Create a validator component from ComponentBase:

  • フォームの EditContext は、コンポーネントのカスケード パラメーターですThe form's EditContext is a cascading parameter of the component.
  • 検証コンポーネントが初期化されると、フォーム エラーの現在の一覧を保持するために新しい ValidationMessageStore が作成されます。When the validator component is initialized, a new ValidationMessageStore is created to maintain a current list of form errors.
  • フォームのコンポーネント内の開発者コードで DisplayErrors メソッドが呼び出されると、メッセージ ストアでエラーが受け取られます。The message store receives errors when developer code in the form's component calls the DisplayErrors method. そのエラーは、Dictionary<string, List<string>>内の DisplayErrors メソッドに渡されます。The errors are passed to the DisplayErrors method in a Dictionary<string, List<string>>. ディクショナリでは、キーは、1 つ以上のエラーがあるフォーム フィールドの名前です。In the dictionary, the key is the name of the form field that has one or more errors. 値は、エラー一覧です。The value is the error list.
  • 次のいずれかが発生すると、メッセージはクリアされます。Messages are cleared when any of the following have occurred:
    • EditContext で検証が要求され、OnValidationRequested イベントが発生した場合。Validation is requested on the EditContext when the OnValidationRequested event is raised. すべてのエラーがクリアされます。All of the errors are cleared.
    • フォームのフィールドが変更され、OnFieldChanged イベントが発生した場合。A field changes in the form when the OnFieldChanged event is raised. そのフィールドのエラーのみがクリアされます。Only the errors for the field are cleared.
    • 開発者コードによって ClearErrors メソッドが呼び出された場合。The ClearErrors method is called by developer code. すべてのエラーがクリアされます。All of the errors are cleared.
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;

public class CustomValidator : ComponentBase
{
    private ValidationMessageStore messageStore;

    [CascadingParameter]
    private EditContext CurrentEditContext { get; set; }

    protected override void OnInitialized()
    {
        if (CurrentEditContext == null)
        {
            throw new InvalidOperationException(
                $"{nameof(CustomValidator)} requires a cascading " +
                $"parameter of type {nameof(EditContext)}. " +
                $"For example, you can use {nameof(CustomValidator)} " +
                $"inside an {nameof(EditForm)}.");
        }

        messageStore = new ValidationMessageStore(CurrentEditContext);

        CurrentEditContext.OnValidationRequested += (s, e) => 
            messageStore.Clear();
        CurrentEditContext.OnFieldChanged += (s, e) => 
            messageStore.Clear(e.FieldIdentifier);
    }

    public void DisplayErrors(Dictionary<string, List<string>> errors)
    {
        foreach (var err in errors)
        {
            messageStore.Add(CurrentEditContext.Field(err.Key), err.Value);
        }

        CurrentEditContext.NotifyValidationStateChanged();
    }

    public void ClearErrors()
    {
        messageStore.Clear();
        CurrentEditContext.NotifyValidationStateChanged();
    }
}

注意

匿名のラムダ式は、OnValidationRequested と前の例の OnFieldChanged に対して登録されているイベント ハンドラーです。Anonymous lambda expressions are registered event handlers for OnValidationRequested and OnFieldChanged in the preceding example. このシナリオでは、IDisposable を実装したり、イベント デリゲートの登録を解除したりする必要はありません。It isn't necessary to implement IDisposable and unsubscribe the event delegates in this scenario. 詳細については、「ASP.NET Core Blazor ライフサイクル」を参照してください。For more information, see ASP.NET Core Blazor ライフサイクル.

ビジネス ロジックの検証Business logic validation

ビジネス ロジックの検証は、ディクショナリ内のフォーム エラーを受け取る検証コンポーネントを使用して実現されます。Business logic validation can be accomplished with a validator component that receives form errors in a dictionary.

次に例を示します。In the following example:

  • この記事の「検証コンポーネント」セクションのCustomValidator コンポーネントが使用されています。The CustomValidator component from the Validator components section of this article is used.
  • 検証では、ユーザーがDefense船の分類 (Classification) を選択した場合に船の説明 (Description) の値を要求します。The validation requires a value for the ship's description (Description) if the user selects the Defense ship classification (Classification).

検証メッセージは、コンポーネント内で設定されると、検証コンポーネントの ValidationMessageStore に追加され、EditForm に表示されます。When validation messages are set in the component, they're added to the validator's ValidationMessageStore and shown in the EditForm:

@page "/FormsValidation"

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="@starship" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <CustomValidator @ref="customValidator" />
    <ValidationSummary />

    ...

</EditForm>

@code {
    private CustomValidator customValidator;
    private Starship starship = new Starship() { ProductionDate = DateTime.UtcNow };

    private void HandleValidSubmit()
    {
        customValidator.ClearErrors();

        var errors = new Dictionary<string, List<string>>();

        if (starship.Classification == "Defense" &&
                string.IsNullOrEmpty(starship.Description))
        {
            errors.Add(nameof(starship.Description),
                new List<string>() { "For a 'Defense' ship classification, " +
                "'Description' is required." });
        }

        if (errors.Count() > 0)
        {
            customValidator.DisplayErrors(errors);
        }
        else
        {
            // Process the form
        }
    }
}

注意

検証コンポーネントを使用する代わりに、データ注釈検証属性を使用することもできます。As an alternative to using validation components, data annotation validation attributes can be used. フォームのモデルに適用されるカスタム属性は、DataAnnotationsValidator コンポーネントを使用してアクティブ化されます。Custom attributes applied to the form's model activate with the use of the DataAnnotationsValidator component. サーバー側の検証で使用する場合、属性はサーバーで実行できる必要があります。When used with server-side validation, the attributes must be executable on the server. 詳細については、「ASP.NET Core MVC でのモデルの検証」を参照してください。For more information, see ASP.NET Core MVC でのモデルの検証.

サーバーの検証Server validation

サーバーの検証は、サーバー検証コンポーネントを使用して実現できます。Server validation can be accomplished with a server validator component:

  • DataAnnotationsValidator コンポーネントを使用して、フォーム内のクライアント側の検証を処理します。Process client-side validation in the form with the DataAnnotationsValidator component.
  • フォームによってクライアント側の検証が渡されると (OnValidSubmit が呼び出されると)、フォーム処理のために、EditContext.Model がバックエンド サーバー API に送信されます。When the form passes client-side validation (OnValidSubmit is called), send the EditContext.Model to a backend server API for form processing.
  • サーバーでモデルの検証を処理します。Process model validation on the server.
  • サーバー API には、組み込みのフレームワーク データ注釈検証と開発者によって提供されるカスタムの検証ロジックの両方が含まれています。The server API includes both the built-in framework data annotations validation and custom validation logic supplied by the developer. サーバーで検証が成功すると、フォームが処理され、成功の状態コード (200 - OK) が返されます。If validation passes on the server, process the form and send back a success status code (200 - OK). 検証が失敗すると、失敗の状態コード (400 - 無効な要求) とフィールド検証エラーが返されます。If validation fails, return a failure status code (400 - Bad Request) and the field validation errors.
  • 成功時にフォームを無効にするか、エラーを表示します。Either disable the form on success or display the errors.

次の例は、以下のものに基づいています。The following example is based on:

次の例では、サーバー API で、ユーザーが Defense 船の分類 (Classification) を選択した場合に船の説明 (Description) の値が提供されるかどうかを検証します。In the following example, the server API validates that a value is provided for the ship's description (Description) if the user selects the Defense ship classification (Classification).

Starship モデルをソリューションの Shared プロジェクトに配置して、クライアントとサーバーの両方のアプリでモデルを使用できるようにします。Place the Starship model into the solution's Shared project so that both the client and server apps can use the model. モデルにはデータ注釈が必要であるため、System.ComponentModel.Annotations のパッケージ参照を Shared プロジェクトのプロジェクト ファイルに追加します。Since the model requires data annotations, add a package reference for System.ComponentModel.Annotations to the Shared project's project file:

<ItemGroup>
  <PackageReference Include="System.ComponentModel.Annotations" Version="{VERSION}" />
</ItemGroup>

パッケージのプレビュー版以外の最新バージョンを確認するには、NuGet.orgでパッケージの バージョン履歴 を参照してください。To determine the latest non-preview version of the package, see the package Version History at NuGet.org.

サーバー API プロジェクトでは、starship 検証要求 (Controllers/StarshipValidation.cs) を処理し、失敗した検証のメッセージを返すコントローラーを追加します。In the server API project, add a controller to process starship validation requests (Controllers/StarshipValidation.cs) and return failed validation messages:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using BlazorSample.Shared;

namespace {ASSEMBLY NAME}.Controllers
{
    [Authorize]
    [ApiController]
    [Route("[controller]")]
    public class StarshipValidationController : ControllerBase
    {
        private readonly ILogger<StarshipValidationController> logger;

        public StarshipValidationController(
            ILogger<StarshipValidationController> logger)
        {
            this.logger = logger;
        }

        [HttpPost]
        public async Task<IActionResult> Post(Starship starship)
        {
            try
            {
                if (starship.Classification == "Defense" && 
                    string.IsNullOrEmpty(starship.Description))
                {
                    ModelState.AddModelError(nameof(starship.Description),
                        "For a 'Defense' ship " +
                        "classification, 'Description' is required.");
                }
                else
                {
                    // Process the form asynchronously
                    // async ...

                    return Ok(ModelState);
                }
            }
            catch (Exception ex)
            {
                logger.LogError("Validation Error: {Message}", ex.Message);
            }

            return BadRequest(ModelState);
        }
    }
}

前の例では、プレースホルダー {ASSEMBLY NAME} はアプリのアセンブリ名です (たとえば BlazorSample.Server)。In the preceding example, the placeholder {ASSEMBLY NAME} is the app's assembly name (for example, BlazorSample.Server).

サーバーでモデル バインド検証エラーが発生した場合、通常、ApiController (ApiControllerAttribute) により、既定の無効な要求応答ValidationProblemDetails が返されます。When a model binding validation error occurs on the server, an ApiController (ApiControllerAttribute) normally returns a default bad request response with a ValidationProblemDetails. Starfleet Starship Database フォームのすべてのフィールドが送信されず、フォームの検証が失敗した場合、次の例に示すように、応答には、検証エラー以外のデータも含まれます。The response contains more data than just the validation errors, as shown in the following example when all of the fields of the Starfleet Starship Database form aren't submitted and the form fails validation:

{
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "Identifier": ["The Identifier field is required."],
    "Classification": ["The Classification field is required."],
    "IsValidatedDesign": ["This form disallows unapproved ships."],
    "MaximumAccommodation": ["Accommodation invalid (1-100000)."]
  }
}

サーバー API によって、前述の既定の JSON 応答が返された場合、クライアントでは、応答を解析して、errors ノードの子を取得することができます。If the server API returns the preceding default JSON response, it's possible for the client to parse the response to obtain the children of the errors node. ただし、ファイルの解析は容易ではありません。However, it's inconvenient to parse the file. JSON を解析するには、フォーム検証エラーを処理するためのエラーの Dictionary<string, List<string>> を生成するために、ReadFromJsonAsync を呼び出した後に追加のコードが必要です。Parsing the JSON requires additional code after calling ReadFromJsonAsync in order to produce a Dictionary<string, List<string>> of errors for forms validation error processing. サーバー API で検証エラーのみを返すのが理想的です。Ideally, the server API should only return the validation errors:

{
  "Identifier": ["The Identifier field is required."],
  "Classification": ["The Classification field is required."],
  "IsValidatedDesign": ["This form disallows unapproved ships."],
  "MaximumAccommodation": ["Accommodation invalid (1-100000)."]
}

サーバー API の応答を変更して、検証エラーのみが返されるようにするには、Startup.ConfigureServicesApiControllerAttribute で注釈が付けられたアクションで呼び出されるデリゲートを変更します。To modify the server API's response to make it only return the validation errors, change the delegate that's invoked on actions that are annotated with ApiControllerAttribute in Startup.ConfigureServices. API エンドポイント (/StarshipValidation) の場合、BadRequestObjectResultModelStateDictionary が返されます。For the API endpoint (/StarshipValidation), return a BadRequestObjectResult with the ModelStateDictionary. 他の API エンドポイントの場合、オブジェクトの結果と新しい ValidationProblemDetailsが返され、既定の動作が保持されます。For any other API endpoints, preserve the default behavior by returning the object result with a new ValidationProblemDetails:

using Microsoft.AspNetCore.Mvc;

...

services.AddControllersWithViews()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.InvalidModelStateResponseFactory = context =>
        {
            if (context.HttpContext.Request.Path == "/StarshipValidation")
            {
                return new BadRequestObjectResult(context.ModelState);
            }
            else
            {
                return new BadRequestObjectResult(
                    new ValidationProblemDetails(context.ModelState));
            }
        };
    });

詳細については、「ASP.NET Core Web API のエラーを処理する」を参照してください。For more information, see ASP.NET Core Web API のエラーを処理する.

クライアント プロジェクトでは、「検証コンポーネント」セクションで示した検証コンポーネントを追加します。In the client project, add the validator component shown in the Validator components section.

また、Starfleet Starship Database フォームが、CustomValidator コンポーネントを使用してサーバー検証エラーを示すように更新されます。In the client project, the Starfleet Starship Database form is updated to show server validation errors with help of the CustomValidator component. サーバー API によって検証メッセージが返されると、それらは、CustomValidator コンポーネントの ValidationMessageStoreに追加されます。When the server API returns validation messages, they're added to the CustomValidator component's ValidationMessageStore. エラーは、フォームの ValidationSummaryで表示するために、フォームの EditContext で使用することができます。The errors are available in the form's EditContext for display by the form's ValidationSummary:

@page "/FormValidation"
@using System.Net
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Microsoft.Extensions.Logging
@using BlazorSample.Shared
@attribute [Authorize]
@inject HttpClient Http
@inject ILogger<FormValidation> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="@starship" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <CustomValidator @ref="customValidator" />
    <ValidationSummary />

    <p>
        <label>
            Identifier:
            <InputText @bind-Value="starship.Identifier" disabled="@disabled" />
        </label>
    </p>
    <p>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="starship.Description" 
                disabled="@disabled" />
        </label>
    </p>
    <p>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="starship.Classification" disabled="@disabled">
                <option value="">Select classification ...</option>
                <option value="Exploration">Exploration</option>
                <option value="Diplomacy">Diplomacy</option>
                <option value="Defense">Defense</option>
            </InputSelect>
        </label>
    </p>
    <p>
        <label>
            Maximum Accommodation:
            <InputNumber @bind-Value="starship.MaximumAccommodation" 
                disabled="@disabled" />
        </label>
    </p>
    <p>
        <label>
            Engineering Approval:
            <InputCheckbox @bind-Value="starship.IsValidatedDesign" 
                disabled="@disabled" />
        </label>
    </p>
    <p>
        <label>
            Production Date:
            <InputDate @bind-Value="starship.ProductionDate" disabled="@disabled" />
        </label>
    </p>

    <button type="submit" disabled="@disabled">Submit</button>

    <p style="@messageStyles">
        @message
    </p>

    <p>
        <a href="http://www.startrek.com/">Star Trek</a>,
        &copy;1966-2019 CBS Studios, Inc. and
        <a href="https://www.paramount.com">Paramount Pictures</a>
    </p>
</EditForm>

@code {
    private bool disabled;
    private string message;
    private string messageStyles = "visibility:hidden";
    private CustomValidator customValidator;
    private Starship starship = new Starship() { ProductionDate = DateTime.UtcNow };

    private async Task HandleValidSubmit(EditContext editContext)
    {
        customValidator.ClearErrors();

        try
        {
            var response = await Http.PostAsJsonAsync<Starship>(
                "StarshipValidation", (Starship)editContext.Model);

            var errors = await response.Content
                .ReadFromJsonAsync<Dictionary<string, List<string>>>();

            if (response.StatusCode == HttpStatusCode.BadRequest && 
                errors.Count() > 0)
            {
                customValidator.DisplayErrors(errors);
            }
            else if (!response.IsSuccessStatusCode)
            {
                throw new HttpRequestException(
                    $"Validation failed. Status Code: {response.StatusCode}");
            }
            else
            {
                disabled = true;
                messageStyles = "color:green";
                message = "The form has been processed.";
            }
        }
        catch (AccessTokenNotAvailableException ex)
        {
            ex.Redirect();
        }
        catch (Exception ex)
        {
            Logger.LogError("Form processing error: {Message}", ex.Message);
            disabled = true;
            messageStyles = "color:red";
            message = "There was an error processing the form.";
        }
    }
}

注意

検証コンポーネントの代わりに、データ注釈検証属性を使用することもできます。As an alternative to validation components, data annotation validation attributes can be used. フォームのモデルに適用されるカスタム属性は、DataAnnotationsValidator コンポーネントを使用してアクティブ化されます。Custom attributes applied to the form's model activate with the use of the DataAnnotationsValidator component. サーバー側の検証で使用する場合、属性はサーバーで実行できる必要があります。When used with server-side validation, the attributes must be executable on the server. 詳細については、「ASP.NET Core MVC でのモデルの検証」を参照してください。For more information, see ASP.NET Core MVC でのモデルの検証.

注意

このセクションで説明したサーバー側の検証は、このドキュメント セットにある、Blazor WebAssemblyでホストされるどのソリューション例にも適しています。The server-side validation approach in this section is suitable for any of the Blazor WebAssembly hosted solution examples in this documentation set:

入力イベントに基づく InputTextInputText based on the input event

change イベントではなく、input イベントを使用するカスタム コンポーネントを作成するには、InputText コンポーネントを使用します。Use the InputText component to create a custom component that uses the input event instead of the change event.

次の例では、CustomInputText コンポーネントによってフレームワークの InputText コンポーネントが継承され、イベント バインディングが oninput イベントに設定されます。In the following example, the CustomInputText component inherits the framework's InputText component and sets event binding to the oninput event.

Shared/CustomInputText.razor:Shared/CustomInputText.razor:

@inherits InputText

<input @attributes="AdditionalAttributes" class="@CssClass" 
    @bind="CurrentValueAsString" @bind:event="oninput" />

CustomInputText コンポーネントは、InputText が使用される場所であればどこでも使用できます。The CustomInputText component can be used anywhere InputText is used:

Pages/TestForm.razor:Pages/TestForm.razor:

@page "/testform"
@using System.ComponentModel.DataAnnotations;

<EditForm Model="@exampleModel" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <CustomInputText @bind-Value="exampleModel.Name" />

    <button type="submit">Submit</button>
</EditForm>

<p>
    CurrentValue: @exampleModel.Name
</p>

@code {
    private ExampleModel exampleModel = new ExampleModel();

    private void HandleValidSubmit()
    {
        ...
    }

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

ラジオ ボタンRadio buttons

ラジオ ボタン グループを作成するには、InputRadioGroup コンポーネントと共に InputRadio コンポーネントを使用します。Use InputRadio components with the InputRadioGroup component to create a radio button group. 次の例では、「組み込みフォームのコンポーネント」セクションで説明されている Starship モデルにプロパティが追加されています。In the following example, properties are added to the Starship model described in the Built-in forms components section:

[Required]
[Range(typeof(Manufacturer), nameof(Manufacturer.SpaceX), 
    nameof(Manufacturer.VirginGalactic), ErrorMessage = "Pick a manufacturer.")]
public Manufacturer Manufacturer { get; set; } = Manufacturer.Unknown;

[Required, EnumDataType(typeof(Color))]
public Color? Color { get; set; } = null;

[Required, EnumDataType(typeof(Engine))]
public Engine? Engine { get; set; } = null;

アプリに以下の enums を追加します。Add the following enums to the app. enums を保持する新しいファイルを作成するか、Starship.cs ファイルに enums を追加します。Create a new file to hold the enums or add the enums to the Starship.cs file. Starship モデルと Starfleet Starship Database フォームから enums にアクセスできるようにします。Make the enums accessible to the Starship model and the Starfleet Starship Database form:

public enum Manufacturer { SpaceX, NASA, ULA, VirginGalactic, Unknown }
public enum Color { ImperialRed, SpacecruiserGreen, StarshipBlue, VoyagerOrange }
public enum Engine { Ion, Plasma, Fusion, Warp }

組み込みフォームのコンポーネント」セクションで説明している Starfleet Starship Database フォームを更新します。Update the Starfleet Starship Database form described in the Built-in forms components section. 生成するコンポーネントを追加します。Add the components to produce:

  • 船舶製造元のラジオ ボタン グループ。A radio button group for the ship manufacturer.
  • 船の色およびエンジン用の入れ子になったラジオ ボタン グループ。A nested radio button group for ship color and engine.
<p>
    <InputRadioGroup @bind-Value="starship.Manufacturer">
        Manufacturer:
        <br>
        @foreach (var manufacturer in (Manufacturer[])Enum
            .GetValues(typeof(Manufacturer)))
        {
            <InputRadio Value="manufacturer" />
            @manufacturer
            <br>
        }
    </InputRadioGroup>
</p>

<p>
    Pick one color and one engine:
    <InputRadioGroup Name="engine" @bind-Value="starship.Engine">
        <InputRadioGroup Name="color" @bind-Value="starship.Color">
            <InputRadio Name="color" Value="Color.ImperialRed" />Imperial Red<br>
            <InputRadio Name="engine" Value="Engine.Ion" />Ion<br>
            <InputRadio Name="color" Value="Color.SpacecruiserGreen" />
                Spacecruiser Green<br>
            <InputRadio Name="engine" Value="Engine.Plasma" />Plasma<br>
            <InputRadio Name="color" Value="Color.StarshipBlue" />Starship Blue<br>
            <InputRadio Name="engine" Value="Engine.Fusion" />Fusion<br>
            <InputRadio Name="color" Value="Color.VoyagerOrange" />
                Voyager Orange<br>
            <InputRadio Name="engine" Value="Engine.Warp" />Warp<br>
        </InputRadioGroup>
    </InputRadioGroup>
</p>

注意

Name を省略した場合、InputRadio コンポーネントは最新の先祖を基準にグループ化されます。If Name is omitted, InputRadio components are grouped by their most recent ancestor.

フォームでオプション ボタンを使用する場合、オプション ボタンはグループとして評価されるため、データ バインディングが他の要素と異なる方法で処理されます。When working with radio buttons in a form, data binding is handled differently than other elements because radio buttons are evaluated as a group. 各オプション ボタンの値は固定ですが、オプション ボタン グループの値は、選択されたオプション ボタンの値です。The value of each radio button is fixed, but the value of the radio button group is the value of the selected radio button. 以下の例では、次のことを行っています。The following example shows how to:

  • オプション ボタン グループのデータバインディングを処理する。Handle data binding for a radio button group.
  • カスタム InputRadio コンポーネントを使用した検証をサポートする。Support validation using a custom InputRadio component.
@using System.Globalization
@typeparam TValue
@inherits InputBase<TValue>

<input @attributes="AdditionalAttributes" type="radio" value="@SelectedValue" 
       checked="@(SelectedValue.Equals(Value))" @onchange="OnChange" />

@code {
    [Parameter]
    public TValue SelectedValue { get; set; }

    private void OnChange(ChangeEventArgs args)
    {
        CurrentValueAsString = args.Value.ToString();
    }

    protected override bool TryParseValueFromString(string value, 
        out TValue result, out string errorMessage)
    {
        var success = BindConverter.TryConvertTo<TValue>(
            value, CultureInfo.CurrentCulture, out var parsedValue);
        if (success)
        {
            result = parsedValue;
            errorMessage = null;

            return true;
        }
        else
        {
            result = default;
            errorMessage = $"{FieldIdentifier.FieldName} field isn't valid.";

            return false;
        }
    }
}

次の EditForm では、前の InputRadio コンポーネントを使用して、ユーザーから評価を取得して検証しています。The following EditForm uses the preceding InputRadio component to obtain and validate a rating from the user:

@page "/RadioButtonExample"
@using System.ComponentModel.DataAnnotations

<h1>Radio Button Group Test</h1>

<EditForm Model="@model" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    @for (int i = 1; i <= 5; i++)
    {
        <label>
            <InputRadio name="rate" SelectedValue="i" @bind-Value="model.Rating" />
            @i
        </label>
    }

    <button type="submit">Submit</button>
</EditForm>

<p>You chose: @model.Rating</p>

@code {
    private Model model = new Model();

    private void HandleValidSubmit()
    {
        ...
    }

    public class Model
    {
        [Range(1, 5)]
        public int Rating { get; set; }
    }
}

C# オブジェクトの null 値への <select> 要素オプションのバインドBinding <select> element options to C# object null values

次の理由により、<select> 要素のオプション値を C# オブジェクトの null 値として表すよい方法はありません。There's no sensible way to represent a <select> element option value as a C# object null value, because:

  • HTML 属性には null 値を設定できません。HTML attributes can't have null values. HTML で null に最も近いのは、<option> 要素から HTML の value 属性を除去することです。The closest equivalent to null in HTML is absence of the HTML value attribute from the <option> element.
  • value 属性のない <option> を選択すると、ブラウザーではその <option> の要素の "テキスト コンテンツ" として値が扱われます。When selecting an <option> with no value attribute, the browser treats the value as the text content of that <option>'s element.

Blazor フレームワークでは、次の処理が必要になるため、既定の動作の抑制は試みられません。The Blazor framework doesn't attempt to suppress the default behavior because it would involve:

  • フレームワークでの特殊なケースの回避策のチェーンの作成。Creating a chain of special-case workarounds in the framework.
  • 現在のフレームワークの動作に対する破壊的変更。Breaking changes to current framework behavior.

HTML で null に最も近いと思われるものは、"空の文字列" の value です。The most plausible null equivalent in HTML is an empty string value. Blazor フレームワークでは、<select> の値への双方向バインドに対する空の文字列変換として null が処理されます。The Blazor framework handles null to empty string conversions for two-way binding to a <select>'s value.

Blazor フレームワークでは、<select> の値への双方向バインドを試みるときに、null は空の文字列変換として自動的に処理されません。The Blazor framework doesn't automatically handle null to empty string conversions when attempting two-way binding to a <select>'s value. 詳細については、「null 値への <select> のバインドの修正 (dotnet/aspnetcore #23221)」を参照してください。For more information, see Fix binding <select> to a null value (dotnet/aspnetcore #23221).

検証のサポートValidation support

DataAnnotationsValidator コンポーネントは、データ注釈を使用した検証サポートをカスケードされた EditContext にアタッチします。The DataAnnotationsValidator component attaches validation support using data annotations to the cascaded EditContext. データ注釈を使用した検証のサポートを有効にするには、この明示的なジェスチャが必要です。Enabling support for validation using data annotations requires this explicit gesture. データ注釈と異なる検証システムを使用するには、DataAnnotationsValidator をカスタム実装に置き換えます。To use a different validation system than data annotations, replace the DataAnnotationsValidator with a custom implementation. 参照ソース DataAnnotationsValidator/AddDataAnnotationsValidation での検査に、ASP.NET Core 実装を使用できます。The ASP.NET Core implementation is available for inspection in the reference source: DataAnnotationsValidator/AddDataAnnotationsValidation. 上記の参照ソースへのリンクからは、リポジトリの master ブランチが提供されます。このブランチは、ASP.NET Core の次回リリースのための製品単位の現行開発を表します。The preceding links to reference source provide code from the repository's master branch, which represents the product unit's current development for the next release of ASP.NET Core. 別のリリースのブランチを選択するには、GitHub ブランチ セレクターを使用します (release/3.1 など)。To select the branch for a different release, use the GitHub branch selector (for example release/3.1).

Blazor は 2 種類の検証を実行します。Blazor performs two types of validation:

  • フィールド検証 は、ユーザーがタブでフィールドを離れたときに実行されます。Field validation is performed when the user tabs out of a field. フィールドの検証時に、DataAnnotationsValidator コンポーネントによって、報告されたすべての検証結果がフィールドに関連付けられます。During field validation, the DataAnnotationsValidator component associates all reported validation results with the field.
  • モデル検証 は、ユーザーがフォームを送信したときに実行されます。Model validation is performed when the user submits the form. モデルの検証時に、DataAnnotationsValidator コンポーネントは、検証結果で報告されたメンバー名に基づいてフィールドを判断しようとします。During model validation, the DataAnnotationsValidator component attempts to determine the field based on the member name that the validation result reports. 個々のメンバーに関連付けられていない検証結果は、フィールドではなくモデルに関連付けられます。Validation results that aren't associated with an individual member are associated with the model rather than a field.

検証概要コンポーネントと検証メッセージ コンポーネントValidation Summary and Validation Message components

ValidationSummary コンポーネントは、すべての検証メッセージを要約します。これは検証概要タグヘルパーと似ています。The ValidationSummary component summarizes all validation messages, which is similar to the Validation Summary Tag Helper:

<ValidationSummary />

Model パラメーターを使用して、特定のモデルの検証メッセージを出力します。Output validation messages for a specific model with the Model parameter:

<ValidationSummary Model="@starship" />

ValidationMessage<TValue> コンポーネントは、特定のフィールドの検証メッセージを表示します。これは、検証メッセージ タグ ヘルパーに似ています。The ValidationMessage<TValue> component displays validation messages for a specific field, which is similar to the Validation Message Tag Helper. For 属性と、モデル プロパティに名前を付けるラムダ式で、検証するフィールドを指定します。Specify the field for validation with the For attribute and a lambda expression naming the model property:

<ValidationMessage For="@(() => starship.MaximumAccommodation)" />

ValidationMessage<TValue> コンポーネントと ValidationSummary コンポーネントでは、任意の属性をサポートしています。The ValidationMessage<TValue> and ValidationSummary components support arbitrary attributes. コンポーネント パラメーターに一致しない属性は、生成された <div> 要素または <ul> 要素に追加されます。Any attribute that doesn't match a component parameter is added to the generated <div> or <ul> element.

アプリのスタイルシート (wwwroot/css/app.css または wwwroot/css/site.css) での検証メッセージのスタイルを制御します。Control the style of validation messages in the app's stylesheet (wwwroot/css/app.css or wwwroot/css/site.css). 既定の validation-message クラスでは、検証メッセージのテキストの色が赤に設定されます。The default validation-message class sets the text color of validation messages to red:

.validation-message {
    color: red;
}

カスタム検証属性Custom validation attributes

カスタム検証属性を使用するときに、検証結果がフィールドに正しく関連付けられるようにするには、ValidationResult の作成時に検証コンテキストの MemberName を渡します。To ensure that a validation result is correctly associated with a field when using a custom validation attribute, pass the validation context's MemberName when creating the ValidationResult:

using System;
using System.ComponentModel.DataAnnotations;

private class CustomValidator : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, 
        ValidationContext validationContext)
    {
        ...

        return new ValidationResult("Validation message to user.",
            new[] { validationContext.MemberName });
    }
}

注意

ValidationContext.GetServicenullです。ValidationContext.GetService is null. IsValid メソッドでの検証に対する挿入サービスはサポートされていません。Injecting services for validation in the IsValid method isn't supported.

カスタム検証クラス属性Custom validation class attributes

カスタム検証クラス名は、Bootstrap などの CSS フレームワークと統合する場合に便利です。Custom validation class names are useful when integrating with CSS frameworks, such as Bootstrap. カスタム検証クラス名を指定するには、FieldCssClassProvider から派生したクラスを作成し、そのクラスを EditContext インスタンスに設定します。To specify custom validation class names, create a class derived from FieldCssClassProvider and set the class on the EditContext instance:

var editContext = new EditContext(model);
editContext.SetFieldCssClassProvider(new MyFieldClassProvider());

...

private class MyFieldClassProvider : FieldCssClassProvider
{
    public override string GetFieldCssClass(EditContext editContext, 
        in FieldIdentifier fieldIdentifier)
    {
        var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();

        return isValid ? "good field" : "bad field";
    }
}

Blazor データ注釈検証パッケージBlazor data annotations validation package

Microsoft.AspNetCore.Components.DataAnnotations.Validation は、DataAnnotationsValidator コンポーネントを使用して検証エクスペリエンスのギャップを埋めるパッケージです。The Microsoft.AspNetCore.Components.DataAnnotations.Validation is a package that fills validation experience gaps using the DataAnnotationsValidator component. パッケージは現在、試験段階 です。The package is currently experimental.

注意

Microsoft.AspNetCore.Components.DataAnnotations.Validation パッケージには、Nuget.org に "リリース候補" の最新バージョンが含まれています。現時点では、"試験的" リリース候補パッケージを継続して使用します。The Microsoft.AspNetCore.Components.DataAnnotations.Validation package has a latest version of release candidate at Nuget.org. Continue to use the experimental release candidate package at this time. パッケージのアセンブリは、将来のリリースでフレームワークまたはランタイムのいずれかに移動される可能性があります。The package's assembly might be moved to either the framework or the runtime in a future release. 更新の詳細については、Announcements GitHub リポジトリdotnet/aspnetcore GitHub リポジトリ、またはこのトピック セクションを参照してください。Watch the Announcements GitHub repository, the dotnet/aspnetcore GitHub repository, or this topic section for further updates.

[CompareProperty] 属性[CompareProperty] attribute

CompareAttribute は、検証結果を特定のメンバーに関連付けないため、DataAnnotationsValidator コンポーネントで正しく機能しません。The CompareAttribute doesn't work well with the DataAnnotationsValidator component because it doesn't associate the validation result with a specific member. これにより、フィールドレベルの検証と、送信時のモデル全体が検証されたときの動作に一貫性がなくなることがあります。This can result in inconsistent behavior between field-level validation and when the entire model is validated on a submit. Microsoft.AspNetCore.Components.DataAnnotations.Validation "試験的" パッケージでは、これらの制限を回避する追加の検証属性 ComparePropertyAttribute が導入されています。The Microsoft.AspNetCore.Components.DataAnnotations.Validation experimental package introduces an additional validation attribute, ComparePropertyAttribute, that works around these limitations. Blazor アプリでは、[CompareProperty][Compare] 属性の直接の代わりとなるものです。In a Blazor app, [CompareProperty] is a direct replacement for the [Compare] attribute.

入れ子になったモデル、コレクション型、および複合型Nested models, collection types, and complex types

Blazor では、組み込みの DataAnnotationsValidator によるデータ注釈を使用したフォーム入力の検証をサポートしています。Blazor provides support for validating form input using data annotations with the built-in DataAnnotationsValidator. ただし、DataAnnotationsValidatorで は、コレクション型または複合型のプロパティではないフォームにバインドされているモデルの最上位レベルのプロパティのみが検証されます。However, the DataAnnotationsValidator only validates top-level properties of the model bound to the form that aren't collection- or complex-type properties.

コレクション型と複合型のプロパティを含む、バインドされたモデルのオブジェクト グラフ全体を検証するには、"試験的" Microsoft.AspNetCore.Components.DataAnnotations.Validation パッケージによって提供される ObjectGraphDataAnnotationsValidator を使用します。To validate the bound model's entire object graph, including collection- and complex-type properties, use the ObjectGraphDataAnnotationsValidator provided by the experimental Microsoft.AspNetCore.Components.DataAnnotations.Validation package:

<EditForm Model="@model" OnValidSubmit="@HandleValidSubmit">
    <ObjectGraphDataAnnotationsValidator />
    ...
</EditForm>

[ValidateComplexType] でモデルのプロパティに注釈を付けます。Annotate model properties with [ValidateComplexType]. 次のモデル クラスでは、ShipDescription クラスに、モデルがフォームにバインドされたときに検証する追加のデータ注釈が含まれています。In the following model classes, the ShipDescription class contains additional data annotations to validate when the model is bound to the form:

Starship.cs:Starship.cs:

using System;
using System.ComponentModel.DataAnnotations;

public class Starship
{
    ...

    [ValidateComplexType]
    public ShipDescription ShipDescription { get; set; } = 
        new ShipDescription();

    ...
}

ShipDescription.cs:ShipDescription.cs:

using System;
using System.ComponentModel.DataAnnotations;

public class ShipDescription
{
    [Required]
    [StringLength(40, ErrorMessage = "Description too long (40 char).")]
    public string ShortDescription { get; set; }

    [Required]
    [StringLength(240, ErrorMessage = "Description too long (240 char).")]
    public string LongDescription { get; set; }
}

フォームの検証に基づいて送信ボタンを有効にするEnable the submit button based on form validation

フォームの検証に基づいて送信ボタンを有効または無効にするには:To enable and disable the submit button based on form validation:

  • コンポーネントを初期化するときに、フォームの EditContext を使用してモデルを割り当てます。Use the form's EditContext to assign the model when the component is initialized.
  • コンテキストの OnFieldChanged コールバックでフォームを検証して、送信ボタンを有効または無効にします。Validate the form in the context's OnFieldChanged callback to enable and disable the submit button.
  • IDisposable を実装し、Dispose メソッドでイベント ハンドラーの登録を解除します。Implement IDisposable and unsubscribe the event handler in the Dispose method. 詳細については、「ASP.NET Core Blazor ライフサイクル」を参照してください。For more information, see ASP.NET Core Blazor ライフサイクル.

注意

さらに、EditContextを使用する場合は、ModelEditFormに割り当てないでください。When using an EditContext, don't also assign a Model to the EditForm.

@implements IDisposable

<EditForm EditContext="@editContext">
    <DataAnnotationsValidator />
    <ValidationSummary />

    ...

    <button type="submit" disabled="@formInvalid">Submit</button>
</EditForm>

@code {
    private Starship starship = new Starship() { ProductionDate = DateTime.UtcNow };
    private bool formInvalid = true;
    private EditContext editContext;

    protected override void OnInitialized()
    {
        editContext = new EditContext(starship);
        editContext.OnFieldChanged += HandleFieldChanged;
    }

    private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
    {
        formInvalid = !editContext.Validate();
        StateHasChanged();
    }

    public void Dispose()
    {
        editContext.OnFieldChanged -= HandleFieldChanged;
    }
}

前の例では、次の場合に formInvalidfalse に設定します。In the preceding example, set formInvalid to false if:

  • フォームには、有効な既定値が事前に読み込まれています。The form is preloaded with valid default values.
  • フォームが読み込まれるときに、送信ボタンを有効にしたいと考えます。You want the submit button enabled when the form loads.

上記の方法の副作用として、ユーザーがいずれかのフィールドを操作した後に、ValidationSummary コンポーネントに無効なフィールドが設定されます。A side effect of the preceding approach is that a ValidationSummary component is populated with invalid fields after the user interacts with any one field. このシナリオは、次のいずれかの方法で対処できます。This scenario can be addressed in either of the following ways:

  • フォームでは ValidationSummary コンポーネントを使用しないでください。Don't use a ValidationSummary component on the form.
  • 送信ボタンが選択された (たとえば、HandleValidSubmit メソッドで) ときに ValidationSummary コンポーネントを表示します。Make the ValidationSummary component visible when the submit button is selected (for example, in a HandleValidSubmit method).
<EditForm EditContext="@editContext" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary style="@displaySummary" />

    ...

    <button type="submit" disabled="@formInvalid">Submit</button>
</EditForm>

@code {
    private string displaySummary = "display:none";

    ...

    private void HandleValidSubmit()
    {
        displaySummary = "display:block";
    }
}

トラブルシューティングTroubleshoot

InvalidOperationException:EditForm には、Model パラメーターまたは EditContext パラメーター (両方ではなく) が必要です。InvalidOperationException: EditForm requires a Model parameter, or an EditContext parameter, but not both.

EditForm に、Model または EditContext が指定されていることを確認します。Confirm that the EditForm has a Model or EditContext. 同じフォームに両方を使用しないでください。Don't use both for the same form.

フォームに Model を割り当てるときは、次の例に示すように、そのモデルの種類がインスタンス化されていることを確認します。When assigning a Model to the form, confirm that the model type is instantiated, as the following example shows:

private ExampleModel exampleModel = new ExampleModel();

その他の技術情報Additional resources