📝

ASP.NET Core 10でのモデル検証の改善

に公開

.NET 9以前

従来、Blazorで入れ子になったオブジェクトとコレクション項目のプロパティ項目の検証(バリデーション)は実験的なパッケージObjectGraphDataAnnotationsValidatorを使用していました。
実験的なパッケージということでなかなかプロダクションでは使いにくくかといってフォーム検証の仕組みを使う限りにおいてはこれ以外方法もなく。。。FluentValidationを使うという方法もありますがそれは別の話。

コード例

画面側

<EditForm ...>
    <ObjectGraphDataAnnotationsValidator /> <% ←これ %>
    ...
</EditForm>

親モデル

using System;
using System.ComponentModel.DataAnnotations;

public class Starship
{
    ...

    [ValidateComplexType]  // ←これ
    public ShipDescription ShipDescription { get; set; } = new();

    ...
}

子モデル

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; }
}

.NET 10の場合

新しい検証機能をオプトインするには:

  • サービスが登録されているAddValidation ファイルで、Program拡張メソッドを呼び出します。
  • Razor コンポーネント (.razor) ではなく、C# クラス ファイルでフォーム モデル型を宣言します。
  • [ValidatableType]属性を使用して、ルート フォーム モデルの種類に注釈を付けます。

前の手順に従わないと、検証動作は以前の .NET リリースと同じままです。

コード例

画面側

<EditForm Model="Model"> <% ←これ %>
     
    ...
</EditForm>
@code {
   public Starship Model { get; set; }
   protected override void OnInitialized() => Model ??= new();
}

サービスを追加

Program.cs
...

builder.Services.AddValidation();
...

親モデル

using System;
using System.ComponentModel.DataAnnotations;

[ValidatableType]  // ←これ
public class Starship
{
    ...

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

    ...
}

子モデル

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; }
}

この、検証機能自体がソースジェネレーターを使用しているため別のソースジェネレーターの出力を別のソースジェネレーターの入力して使用することはできません。

これまでの、リフレクションベースの実装からソースジェネレーターベースの実装になったことによりAOTコンパイルとの互換性を向上やパフォーマンスの改善が図られています。

Discussion