先の記事「ASP.NET Core MVC 整数型プロパティの検証とエラーメッセージ」に書きましたように、クライアント側での検証を無効にして、整数型のプロパティに対し "2000x" というような整数としては無効な文字列を送信するとモデルバインディングの際にエラーとなり、Model のプロパティに付与した Required 属性や RegularExpression 属性による検証は行われません。(注: アプリ全体としての検証が通るわけではありません。ModelState.IsValid は false になります)
結果、エラーメッセージは Required 属性や RegularExpression 属性に設定した ErrorMessage とはならず、フレームワーク組み込みの英文のエラーメッセージとなります。例えば、未入力の場合は「The value '' is invalid.」、"2000x" とした場合は「The value '2000x' is not valid for 価格2 (int).」となります。
検証属性による検証が働かないところは妥協するとして、せめて英文のエラーメッセージを以下の画像のように「値 '' は無効です。」「値 '2000x' は 価格2 (int) に対して無効です。」というような日本語に書き換えたいというケースがあると思います。以下にその方法を書きます。
自力でコードを書いてローカライズする方法は Stackoverflow の記事 ASP.NET Core Model Binding Error Messages Localization 他に見つかりました。
しかし、その記事に書いてある方法は、多言語対応のため複数のリソースファイルを作り、それからカルチャに応じてその言語のエラーメッセージの文字列をリソースファイルから取得して、デフォルトのエラーメッセージを書き換えるという少々複雑なことを行っています。
今回のケースでのエラーメッセージ「The value '2000x' is not valid for 価格2 (int).」と「The value '' is invalid.」を日本語化するだけならもっと簡単にできます。
どうすればよいかと言うと、Program.cs (.NET 5.0 以前は Startup.cs) の AddControllersWithViews メソッドで DefaultModelBindingMessageProvider を取得し、SetAttemptedValueIsInvalidAccessor, SetValueMustNotBeNullAccessor メソッドを使ってデフォルトのエラーメッセージを差し替えてやります。
具体例は下のコードを見てください。Visual Studio 2022 のテンプレートで作った .NET 7.0 の ASP.NET Core MVC の場合のサンプルです。
builder.Services.AddControllersWithViews(options => {
DefaultModelBindingMessageProvider provider =
options.ModelBindingMessageProvider;
provider.SetAttemptedValueIsInvalidAccessor(
(s1, s2) => $"値 '{s1}' は {s2} に対して無効です。");
provider.SetValueMustNotBeNullAccessor(
(s) => $"値 '{s}' は無効です。");
});
上のコードにより、先の記事のデフォルトの英語のエラーメッセージ「The value '2000x' is not valid for 価格2 (int).」と「The value '' is invalid.」がそれぞれ「値 '2000x' は 価格2 (int) に対して無効です。」と「値 '' は無効です。」に書き換えられます。この記事の上の画像がその結果です。
デフォルトの Model Binding Error Messages には、上の AttemptedValueIsInvalid, ValueMustNotBeNull を含めて全部で 11 種類あります。
以下に一覧表を載せておきます。それぞれに SetXxxxxAccessor (Xxxxx は下の表の「名前」) というメソッドが用意されていて、それによりデフォルトのエラーメッセージを差し替えることができます。
名前 | デフォルト | 原因 |
---|---|---|
AttemptedValueIsInvalid | The value '{0}' is not valid for {1}. | Exception is of type FormatException or OverflowException, value is known, and error is associated with a property. |
ValueMustNotBeNull | The value '{0}' is invalid. | a null value is bound to a non-Nullable property. |
MissingBindRequiredValue | A value for the '{0}' parameter or property was not provided. | a property with an associated BindRequiredAttribute is not bound. |
MissingKeyOrValue | A value is required. | either the key or the value of a KeyValuePair<Key,TValue> is bound but not both. |
MissingRequestBodyRequiredValue | A non-empty request body is required. | no value is provided for the request body, but a value is required. |
NonPropertyAttemptedValueIsInvalid | The value '{0}' is not valid. | Exception is of type FormatException or OverflowException, value is known, and error is associated with a collection element or parameter. |
NonPropertyUnknownValueIsInvalid | The supplied value is invalid. | Exception is of type FormatException or OverflowException, value is unknown, and error is associated with a collection element or parameter. |
NonPropertyValueMustBeANumber | The field must be a number. | Error message HTML and tag helpers add for client-side validation of numeric formats. Visible in the browser if the field for a float (for example) collection element or action parameter does not have a correctly-formatted value. |
UnknownValueIsInvalid | The supplied value is invalid for {0}. | Exception is of type FormatException or OverflowException, value is unknown, and error is associated with a property. |
ValueIsInvalid | The value '{0}' is invalid. | Fallback error message HTML and tag helpers display when a property is invalid but the ModelErrors have nullErrorMessages. |
ValueMustBeANumber | The field {0} must be a number. | Error message HTML and tag helpers add for client-side validation of numeric formats. Visible in the browser if the field for a float (for example) property does not have a correctly-formatted value. |