.NET Web API:如果实例为null,则类级别验证属性使Web API引发ArgumentNullException [英] .NET Web API: Class level validation attribute causes Web API to throw ArgumentNullException if instance is null

查看:101
本文介绍了.NET Web API:如果实例为null,则类级别验证属性使Web API引发ArgumentNullException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个看起来像这样的DTO类:

I have a DTO class that looks, for example, like this:

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; }
}

例如,如果用户提供了错误的日期,例如

If, as an example, a user provides an incorrect date, such as this:

<?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(并且在

or simply just an empty body, then the ExampleDto argument passed into the action will be null (and in the former case, the ModelState will have errors).

我将CustomValidationAttribute应用于类,因此类声明如下:

I applied a CustomValidationAttribute to the class, so the class declaration looks like this:

[CustomValidation(typeof(CustomExampleValidator), "Validate")]
public class ExampleDto

现在我添加了这个内容,如果ExampleDto参数为null(由于为空的正文或序列化问题),则会引发ArgumentNullException:

Now that I've added this, if the ExampleDto argument is null (because of an empty body, or a serialization problem), an ArgumentNullException is thrown:

<?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.&lt;&gt;c__DisplayClass1.&lt;ExecuteBindingAsync&gt;b__0(Object
                model) at System.Threading.Tasks.TaskHelpersExtensions.&lt;&gt;c__DisplayClass36`1.&lt;&gt;c__DisplayClass38.&lt;Then&gt;b__35()
                at System.Threading.Tasks.TaskHelpersExtensions.&lt;&gt;c__DisplayClass49.&lt;ToAsyncVoidTask&gt;b__48()
                at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1
                func, CancellationToken cancellationToken)</StackTrace>
        </Error>
    </Errors>
</Response>

Reflector显示对ValidationContext构造函数中的对象执行了空参数检查,就在之前CustomValidationAttribute被执行。这似乎有些奇怪,因为null参数可以用作控制器操作的参数,不是吗?我认为这里的任何空参数检查都应该在用户代码中或通过验证属性(而不是框架)显式执行。

Reflector shows that a null argument check is performed against the object in the constructor of the ValidationContext, just before the CustomValidationAttribute is executed. This seems a bit bizarre, because null arguments are acceptable as arguments to controller actions, no? I think any null argument checks here SHOULD be performed in user code or explicitly by validation attributes, instead of by the framework.

如果用户提交了正确的XML / JSON,则不会引发此异常,并且CustomValidationAttribute会按预期执行,但是始终无法信任用户提交正确的XML / JSON,并且会因工作不便而看起来像ArgumentNullException,而不是我可以返回的内容。

If the user submits correct XML/JSON, then this exception isn't thrown and the CustomValidationAttribute executes as expected, but the users can't always be trusted to submit correct XML/JSON, and will get an obtuse looking ArgumentNullException for their efforts, instead of one that I'm able to return myself.

我正在努力寻找其他经历过此事的人。有很多在属性级别应用复合验证器的示例,但是对我来说,在此处在类级别应用验证更有意义(因为如果特定属性不为null,则需要多个属性,如果一个不为null,则需要其他属性不同的属性不为null),并且我什么都说不支持在类级别应用的验证属性。

I'm struggling to find anyone else who has experienced this. There are plenty of examples of applying "compound" validators at property level, but it makes more sense for me to apply the validation at class level here (because multiple properties are required IF a specific property is not null, and others are required IF a different property is not null), and I can't find anything to say that validation attributes applied at class level are unsupported.

推荐答案

我有同样的问题。不幸的是有很多ValidationAttributes。因此,在发布之前将所有这些都重写为IValidatableObject并不是真正可行的。因此,我的快速又肮脏解决方案是在过滤器中捕获这些异常并发送回适当的响应:

I have the same issue. Unfortunately with quite a few ValidationAttributes. So rewriting all of them to IValidatableObject just before a release is not really feasible. So my quick and dirty solution was to catch these exceptions in a filter and send back a proper Response:

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中全局注册文件管理器: / p>

And register the filer globally in WebApiConfig.cs:

config.Filters.Add(new GeneralExceptionFilterAttribute());

这篇关于.NET Web API:如果实例为null,则类级别验证属性使Web API引发ArgumentNullException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆