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

作成者: Daniel RothLuke LathamBy Daniel Roth and Luke Latham

データ注釈を使用した 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()
    {
        Console.WriteLine("OnValidSubmit");
    }
}

前の例の場合: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:
    • InputText コンポーネントの Value プロパティへのモデルプロパティ (_exampleModel.Name)。The model property (_exampleModel.Name) to the InputText component's Value property.
    • InputText コンポーネントの ValueChanged プロパティに対する変更イベントデリゲート。A change event delegate to the InputText component's ValueChanged property.
  • DataAnnotationsValidator コンポーネントは、データ注釈を使用して検証サポートをアタッチします。The DataAnnotationsValidator 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).

ユーザー入力の受信と検証には、一連の組み込みの入力コンポーネントを使用できます。A set of built-in input 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…
InputText <input>
InputTextArea <textarea>
InputSelect <select>
InputNumber <input type="number">
InputCheckbox <input type="checkbox">
InputDate <input type="date">

すべての入力コンポーネント (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 on edit and changing their CSS class to reflect the field state. 一部のコンポーネントには、役に立つ解析ロジックが含まれています。Some components include useful parsing logic. たとえば、InputDateInputNumber では、解析不能な値を検証エラーとして登録することによって適切に処理します。For example, InputDate and InputNumber handle unparseable values gracefully by registering them 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();

    private void HandleValidSubmit()
    {
        Console.WriteLine("OnValidSubmit");
    }
}

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. EditForm は、有効かつ無効な送信 (OnValidSubmitOnInvalidSubmit) にも便利なイベントを提供します。The EditForm also provides convenient events for valid and invalid submits (OnValidSubmit, OnInvalidSubmit). または、OnSubmit を使用して、カスタム検証コードで検証フィールドとチェックフィールドの値をトリガーします。Alternatively, use OnSubmit to trigger the validation and check field values with custom validation code.

たとえば、行が次のように表示されているとします。In the following example:

  • HandleSubmit メソッドは、 [送信] ボタンを選択したときに実行されます。The HandleSubmit method runs when the Submit button is selected.
  • フォームは、フォームの EditContextを使用して検証されます。The form is validated using the form's EditContext.
  • このフォームは、サーバー上で web API エンドポイントを呼び出す ServerValidate メソッドに EditContext を渡すことによってさらに検証されます (表示されません)。The form is further validated by passing the EditContext to the ServerValidate method that calls a web API endpoint on the server (not shown).
  • isValidをチェックすることによって、クライアント側とサーバー側の検証の結果に応じて、追加のコードが実行されます。Additional code is run depending on the result of the client- and server-side validation by checking isValid.
<EditForm EditContext="@_editContext" OnSubmit="@HandleSubmit">

    ...

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

@code {
    private Starship _starship = new Starship();
    private EditContext _editContext;

    protected override void OnInitialized()
    {
        _editContext = new EditContext(_starship);
    }

    private async Task HandleSubmit()
    {
        var isValid = _editContext.Validate() && 
            await ServerValidate(_editContext);

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

    private async Task<bool> ServerValidate(EditContext editContext)
    {
        var serverChecksValid = ...

        return serverChecksValid;
    }
}

入力イベントに基づく 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.

次のマークアップを使用してコンポーネントを作成し、InputText が使用される場合と同様に、コンポーネントを使用します。Create a component with the following markup, and use the component just as InputText is used:

@inherits InputText

<input 
    @attributes="AdditionalAttributes" 
    class="@CssClass" 
    value="@CurrentValue" 
    @oninput="EventCallback.Factory.CreateBinder<string>(
        this, __value => CurrentValueAsString = __value, CurrentValueAsString)" />

ラジオボタンの操作Work with radio buttons

フォームでオプションボタンを使用する場合、オプションボタンはグループとして評価されるため、データバインディングは他の要素とは異なる方法で処理されます。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()
    {
        Console.WriteLine("valid");
    }

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

検証のサポート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. ASP.NET Core の実装は、参照ソース: Data注釈を検証するために、 adddata注釈を使用して/ます。The ASP.NET Core implementation is available for inspection in the reference source: DataAnnotationsValidator/AddDataAnnotationsValidation.

Blazor は、次の2種類の検証を実行します。 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 コンポーネントには、検証メッセージタグヘルパーに似た、特定のフィールドの検証メッセージが表示されます。The ValidationMessage 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 コンポーネントと ValidationSummary コンポーネントでは、任意の属性がサポートされています。The ValidationMessage 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.

カスタム検証属性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 MyCustomValidator : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, 
        ValidationContext validationContext)
    {
        ...

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

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

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

[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. BlazorAspNetCore です。DataAnnotations。検証実験的なパッケージでは、これらの制限を回避する追加の検証属性 ComparePropertyAttributeが導入されています。The Microsoft.AspNetCore.Blazor.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でデータ注釈を使用してフォーム入力を検証する機能をサポートしています。 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.

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

    ...
}

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.
<EditForm EditContext="@_editContext">
    <DataAnnotationsValidator />
    <ValidationSummary />

    ...

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

@code {
    private Starship _starship = new Starship();
    private bool _formInvalid = true;
    private EditContext _editContext;

    protected override void OnInitialized()
    {
        _editContext = new EditContext(_starship);

        _editContext.OnFieldChanged += (_, __) =>
        {
            _formInvalid = !_editContext.Validate();
            StateHasChanged();
        };
    }
}

前の例では、次の場合に _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.

上記の方法の副作用として、ユーザーが1つのフィールドを操作した後に、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";
    }
}