たとえば、次のような DTO クラスがあります。
public class ExampleDto
{
[DataMember(Name = "Date", IsRequired = true, Order = 1), Required]
public DateTime Date { get; set; }
[DataMember(Name = "ParentExample", IsRequired = false, Order = 2, EmitDefaultValue = false)]
public Guid? ParentExampleId { get; set; }
}
例として、ユーザーが次のように間違った日付を提供した場合:
<?xml version="1.0" encoding="UTF-8" ?>
<ExampleDto xmlns="http://customurl/">
<Date>2012-05-25T18:23:INCORRECTDATE</Date>
<ParentExample>B62F10A8-4998-4626-B5B0-4B9118E11BEC</ParentExample>
</ExampleDto>
または単に空の本体のみの場合、アクションに渡される ExampleDto 引数は null になります (前者の場合、ModelState にエラーが発生します)。
クラスに CustomValidationAttribute を適用したので、クラス宣言は次のようになります。
[CustomValidation(typeof(CustomExampleValidator), "Validate")]
public class ExampleDto
これを追加したので、ExampleDto 引数が null の場合 (空の本体またはシリアル化の問題のため)、ArgumentNullException がスローされます。
<?xml version="1.0" encoding="UTF-8"?>
<Response xmlns="http://customurl" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Type>Failure</Type>
<Message>An unknown error has occurred</Message>
<Errors>
<Error>
<Message>System.ArgumentNullException</Message>
<MessageDetail>Value cannot be null. Parameter name:
instance</MessageDetail>
<StackTrace> at System.ComponentModel.DataAnnotations.ValidationContext..ctor(Object
instance, IServiceProvider serviceProvider,
IDictionary`2 items) at System.Web.Http.Validation.Validators.DataAnnotationsModelValidator.Validate(ModelMetadata
metadata, Object container) at System.Web.Http.Validation.DefaultBodyModelValidator.ShallowValidate(ModelMetadata
metadata, ValidationContext validationContext,
Object container) at System.Web.Http.Validation.DefaultBodyModelValidator.ValidateNodeAndChildren(ModelMetadata
metadata, ValidationContext validationContext,
Object container) at System.Web.Http.Validation.DefaultBodyModelValidator.Validate(Object
model, Type type, ModelMetadataProvider metadataProvider,
HttpActionContext actionContext, String keyPrefix)
at System.Web.Http.ModelBinding.FormatterParameterBinding.<>c__DisplayClass1.<ExecuteBindingAsync>b__0(Object
model) at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass36`1.<>c__DisplayClass38.<Then>b__35()
at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass49.<ToAsyncVoidTask>b__48()
at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1
func, CancellationToken cancellationToken)</StackTrace>
</Error>
</Errors>
</Response>
Reflector は、CustomValidationAttribute が実行される直前に、ValidationContext のコンストラクターでオブジェクトに対して null 引数チェックが実行されることを示しています。null 引数はコントローラー アクションの引数として受け入れられるため、これは少し奇妙に思えます。ここでのnull引数チェックは、フレームワークではなく、ユーザーコードで、または検証属性によって明示的に実行する必要があると思います。
ユーザーが正しい XML/JSON を送信した場合、この例外はスローされず、CustomValidationAttribute は期待どおりに実行されますが、ユーザーが正しい XML/JSON を送信することを常に信頼できるとは限りません。私が自分自身を返すことができるものの代わりに。
これを経験した人を他に見つけるのに苦労しています。プロパティ レベルで「複合」バリデータを適用する例はたくさんありますが、ここではクラス レベルで検証を適用する方が理にかなっています (特定のプロパティが null でない場合は複数のプロパティが必要であり、ある場合は他のプロパティが必要になるためです)。別のプロパティはnullではありません)、クラスレベルで適用される検証属性がサポートされていないと言うことは何も見つかりません.