例如,我有一个 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 参数将为空(在前一种情况下,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 的构造函数中的对象执行空参数检查。这似乎有点奇怪,因为空参数可以作为控制器操作的参数,不是吗?我认为这里的任何空参数检查都应该在用户代码中或通过验证属性显式执行,而不是由框架执行。
如果用户提交正确的 XML/JSON,则不会引发此异常,并且 CustomValidationAttribute 会按预期执行,但不能始终信任用户提交正确的 XML/JSON,并且会因为他们的努力而得到一个看起来很钝的 ArgumentNullException,而不是我能够自己返回的。
我正在努力寻找其他经历过这种情况的人。有很多在属性级别应用“复合”验证器的示例,但对我来说,在这里应用类级别的验证更有意义(因为如果特定属性不为空,则需要多个属性,如果特定属性不为空,则需要其他属性不同的属性不为空),我找不到任何可以说在类级别应用的验证属性不受支持。