问题描述
我有一个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(在前一个情况下,模型符号将具有错误).
我向类应用了一个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>
反射器显示在执行CustomValidationAttribute之前,对validationContext的构造函数中的对象执行NULL参数检查.这似乎有点奇怪,因为null参数是控制器操作的参数可以接受,因为没有?我认为此处的任何NULL参数检查应在用户代码中或通过验证属性而不是框架明确地执行.
如果用户提交正确的XML/JSON,则不会抛出此异常,并且自定义ValidationAttribute按预期执行,但用户不能总是被信任提交正确的XML/JSON,并且可以获得看起来的ArgumentNulLException他们的努力,而不是我能够回归自己的努力.
我正在努力找到遇到过这个的别人.有大量的例子在物业级别应用"化合物"验证器,但它对我来说更有意义以在此处应用验证在类级别(因为如果特定属性未为空,则需要多个属性,并且如果a不同的属性不是null),我找不到任何可以说在类级别应用的验证属性不受支持.
推荐答案
我有同样的问题.遗憾的是,有很多验证了.因此,在释放之前,将所有它们重写为rivalidatableObject并不是可行的.所以我的快速和肮脏的解决方案是在过滤器中捕获这些例外,并发回适当的响应:
public class GeneralExceptionFilterAttribute : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext context) { var exceptionType = context.Exception.GetType(); HttpResponseMessage response = null; if(exceptionType == typeof(ArgumentNullException) && context.Exception.StackTrace.TrimStart().StartsWith("at System.ComponentModel.DataAnnotations.ValidationContext..ctor")) { response = new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent(context.Exception.Message) }; } else { response = new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent(context.Exception.Message), ReasonPhrase = "Unhandled exception" }; } context.Response = response; _errorLogger.LogError(response?.ReasonPhrase, context.Exception); } }
并在webapiconfig.cs中全局注册文件管理器:
config.Filters.Add(new GeneralExceptionFilterAttribute());