フッターコンテンツにスキップ
Iron Academy Logo
C#を学ぶ
C#を学ぶ

その他のカテゴリー

.NET 10におけるデータ検証の最小API

Tim Corey
~10m

ミニマルAPIは常にコントローラーを基にしたASP.NET Coreのスリムな代替手段でしたが、長らく注目すべきギャップがありました。それは、受信データの検証をするための組み込みサポートがないことです。 各ハンドラー内に手動チェックを組み込むか、サードパーティライブラリに依存していました。 .NET 10は、追加のパッケージなしで、クエリストリング、ヘッダー、リクエスト本文に対するファーストクラスデータアノテーションの検証により、そのギャップを埋めています。

Tim Coreyのウォークスルーに基づくこの.NET 10 Minimal APIsの詳細な説明では、検証サービスを登録し、モデルクラスに注釈を付け、セットアップを壊す可能性がある一般的なアクセス修飾子のピットフォールを避ける方法を説明します。

セットアップ: シンプルなミニマルAPI

[0:44 - 1:35] デモは、.NET 10で動作する簡素なASP.NET Core Minimal APIプロジェクトから始まります。表面積は意図的に小さく、各モデルを受け入れる2つのPOSTエンドポイントがあります。

app.MapPost("/person", (Person person) => Results.Ok(person));
app.MapPost("/login", (LoginModel login) => Results.Ok(login));
app.MapPost("/person", (Person person) => Results.Ok(person));
app.MapPost("/login", (LoginModel login) => Results.Ok(login));

Personモデルは基本的な識別フィールドを持っています。 LoginModelは認証情報を処理します: メールアドレス、パスワード、およびパスワード確認フィールド。 どちらもJSON本文として送信されます。 この時点では、入力チェックはまったくありません; APIは空の文字列や不正なメールアドレスを含むものすべてを受け入れます。

Scalar(.NET 10に付属する、最新のOpenAPI UI)が、よくテストされてリクエストをブラウザから直接送信します。このため、検証が結線される前後で、APIが確実に応答する内容を簡単に確認できます。

バリデーションサービスの登録

[2:36 - 3:06] 検証属性を有効にする前に、サービスレベルでオプトインする必要があります。 サービス登録ブロック内での単一の呼び出しが、すべてのMinimal APIエンドポイントでの強制を有効にします。

builder.Services.AddValidation();
builder.Services.AddValidation();

その1行が全体の設定ステップです。追加するミドルウェアも、フックするパイプラインステージもありません。 一度サービスが登録されると、フレームワークが自動的に引き継ぎます。 この呼び出しをスキップすると、データアノテーション属性がモデル上に存在しますが、評価されることはなく、リクエストが含むものに関わらず通過します。

これはデバッグの第一歩として覚えておく価値があります: バリデーションが何もせずに静かに動作しない場合、AddValidation()が通常欠けている部分です。

クラスモデルへのバリデーションの追加

[3:00 - 3:55] サービス登録後、クラスベースのモデルに検証を追加するには、プロパティにデータアノテーション属性を装飾するだけです。

public class Person
{
    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }
}
public class Person
{
    [Required]
    public string FirstName { get; set; }

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

ファイル上部にSystem.ComponentModel.DataAnnotations usingディレクティブを追加した後、[Required]としてマークすることで、それらがバリデーションされることが保証されます。 スカラー経由でボディなしのPOSTリクエストを送信すると、構造化されたエラー応答を伴う400 Bad Requestが返されます:

{
  "errors": {
    "FirstName": ["The FirstName field is required."],
    "LastName": ["The LastName field is required."]
  }
}

カスタムエラーハンドリングもフィルター属性もありません。 フレームワークが自動的にその応答を生成し、チェックはハンドラ本文の実行前に発生します。そのため、エンドポイントロジック内でnullをガードする必要はありません。

レコードへのバリデーションの適用

[4:29 - 5:30] 同じ属性はC#レコードにも適用されますが、レコードプロパティは通常、個別のメンバー宣言ではなく初期コンストラクタで定義されるため、構文がやや異なります。

public record LoginModel(
    [Required] [EmailAddress] string Email,
    [Required] string Password,
    [Required] string ConfirmPassword
);
public record LoginModel(
    [Required] [EmailAddress] string Email,
    [Required] string Password,
    [Required] string ConfirmPassword
);

コンストラクタパラメータの属性は生成されたプロパティに適用されるため、[EmailAddress]はクラス上での動作と全く同じように振る舞います。 Emailフィールドが無効であることを特定します。

Passwordと一致することを強制するために使用されます。 レコードでは、コンパイラにそれが生成されたメンバーでパラメータ自体ではないことを伝えるために、あからさまな動機付けが必要です。

[property: Compare(nameof(Password))]
string ConfirmPassword
[property: Compare(nameof(Password))]
string ConfirmPassword

[property:]ターゲットは、コンパイラに属性をパラメータではなく生成されたメンバーに添付するように伝えます。 それがないと、[Compare]はコンパイルされますが、チェック中に実行されることはありません。 このコンテキストでのレコードvsクラスの扱いで最も難解な部分です。クラスプロパティは自然に属性を受け入れますが、レコードパラメータはメンバーレベルで何かを操作するには明示的なターゲットが必要です。

Public Access Modifier Requirement

[7:51 - 9:00] よくある落とし穴は見逃しやすく、遭遇してもエラーメッセージを生成しません。 バリデーションシステムはリフレクションを使用して、実行時にモデルタイプを検査します。タイプのメンバーをリフレクションで見つけるためには、タイプ自体をpublicとしてマークする必要があります。

// Validation will NOT run; the class is internal by default
class Person { ... }

// Validation runs correctly
public class Person { ... }
// Validation will NOT run; the class is internal by default
class Person { ... }

// Validation runs correctly
public class Person { ... }

同じルールがレコードに適用されます。 モデルがアクセス修飾子なしで宣言されると、C#はデフォルトでinternalとし、サービスはそれを完全にスキップします。 エンドポイントはリクエストを受け取り、ハンドラーが実行され、エラーは返されません。 チェックは単に何も行わないままです。

これはASP.NET Coreの動作であり、ミニマルAPIに特有のものではありませんが、これらのプロジェクトはコンパクトである傾向があり、開発者がProgram.csと同じファイルでモデルをインラインまたは定義することがあるため、ここではより頻繁に表面化します。

プロジェクトを監査する迅速な方法: エンドポイントハンドラーに渡されるモデルタイプはすべて、publicとして明示的にマークされるべきです。 そうでなければ、どんなに多くの属性を加えてもフレームワークは発火しません。

You Can Validate

組み込みデータアノテーション属性は、追加の作業なしで最も一般的なシナリオをカバーします:

  • [Required]はnullまたは空の値を拒否します
  • [EmailAddress]はメール文字列の形式を検証します
  • [Compare]は2つのプロパティが一致することを確認します。パスワード確認に便利です
  • [Range]は数値または日付の境界を強制します
  • [StringLength]はオプションの最小値で文字列の長さを制限します
  • [RegularExpression]はカスタムパターンに対して検証します

これらはすべて、クエリ文字列パラメータ、リクエストヘッダー、およびJSON本文に対して動作します。 同じモデルクラスまたはレコードは、異なるソースからバインドされてもその属性を一切変更することなく動作します。

結論

[7:46 - end] AddValidation()が登録され、モデルが装飾されれば、ミニマルAPIはクラスとレコードの両方にわたり入力制約を自動的に強制します。これを.NET 10で動作させるには、単にpublicとしてマークされることを確認してください。

レコード上のpublic修飾子の要件が唯一の本当の注意ポイントです。 それらは見逃しがちであり、コンパイルエラーではなく無音の失敗をもたらします。したがって、入力チェックが何もしないように見える場合は、常にチェックリストに載せておいてください。

完全なソースコードウォークスルーはTim CoreyのYouTube動画で視聴できます。

Hero Worlddot related to .NET 10におけるデータ検証の最小API
Hero Affiliate related to .NET 10におけるデータ検証の最小API

好きなことを共有することで収入を増やす

.NET、C#、Java、Python、またはNode.jsを使用する開発者向けのコンテンツを作成しますか?あなたの専門知識を副収入に変えましょう!

アイアンサポートチーム

私たちは週5日、24時間オンラインで対応しています。
チャット
メール
電話してね