ちょっとこの質問見てみてくださいよ!
Asp.Net MVC 2 - Changing the PropertyValueRequired string. - Stack Overflow
ASP.NET MVCのDefaultModelBinderにはResourceClassKeyっていうプロパティがあって、そこに自作リソースを指定して、文字列リソースのキー名にPropertyValueInvalid/PropertyValueRequiredっていうのを作っておくと、アプリケーション全体にその文字列が適用される。でもInvalidは動作するけどRequiredがぜんぜん適用されません!っていう内容なんですね。
これ質問もなかなか面白いからか、特別ポイントが付与される質問だったんです。なので、張り切って思ってソース追っかけたりしながら動作を見てみたわけですよ。そしたら確かにInvalidはメッセージの置き換えができるのにRequiredは置き換えがおきない。
public class Person { [Required] public string Name { get; set; } [Required] [Range(0,100)] public int? Age { get; set; } [DataType(DataType.Date)] public DateTime Birthday { get; set; } [DataType(DataType.EmailAddress)] public string Email { get; set; } }
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); DefaultModelBinder.ResourceClassKey = "Messages"; }
なんでかな~、と調べてみたらDataAnnotationsのRequiredAttributeなんかは内部で参照するリソース名を固定で保持してて、DefaultModelBinderのほうの設定を参照しないんですね。分かってしまえば、そりゃそうなんですけど(日本語のエラーちゃんと出るし、GACに入ってるリソースを参照するのが正しい挙動な感じするしね)、それでもASP.NET MVCならできる方法がありそうな気がするんですよね。これだけ拡張ポイントたくさんあるんだから。
いろいろ見ていくとちゃんと用意されてるのを発見しました。
Reusable Validation Error Message Resource Strings for DataAnnotations
DataAnnotationsModelValidatorProvider.RegisterAdapterでValidationAttributeの型ごとにAdapterを指定できるんです。このAdapterのコンストラクタにはValidationAttributeクラスのインスタンスがわたってくるんですが、このAdapterを経由させてから、MVCはエラーメッセージを生成したりするので、AdapterのコンストラクタでインスタンスプロパティのErrorMessageResourceTypeとErrorMessageResourceNameを書き換えてあげれば、アプリケーション全体のメッセージを変更できるっていう仕組みです。
分かりやすいやり方としてはね、カスタムValidationAttributeを作って、ErrorMessage~の設定を上書いておくか、Modelに指定するときに属性プロパティに指定する方法なんだと思うけど、それだと属性を指定する箇所がすごい数になっちゃうじゃないですか。それでもいいけど、そうじゃなく一括して変更したいっていうのが質問の内容じゃないですか。
んで、ちゃんとサンプル書いて返信したんですよ。
public class MyRequiredAttributeAdapter : RequiredAttributeAdapter { public MyRequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, RequiredAttribute attribute) : base(metadata, context, attribute) { attribute.ErrorMessageResourceType = typeof (Messages); attribute.ErrorMessageResourceName = "PropertyValueRequired"; } }
アダプター用意して、Global.asaxに
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); DefaultModelBinder.ResourceClassKey = "Messages"; DataAnnotationsModelValidatorProvider.RegisterAdapter( typeof(RequiredAttribute), typeof(MyRequiredAttributeAdapter)); }
↑こう書けばカスタムできるよ!って。
なのに!なのになのに!カスタムValidationAttributeを作るほうに特別ポイントが!!ガッカリデス。ガッカリ過ぎてスネ毛が少し抜けたよ...。
こういう一括していの方法があることを知らなかったので、勉強になりました。