Использование Filter и ValidatorAttribute вызывает System.ArgumentNullException в ctor ValidationContext - PullRequest
1 голос
/ 18 февраля 2020

У меня есть asp проект webapi, и я хочу использовать пользовательский атрибут validatoratratribute, чтобы выполнить некоторую специальную проверку в моем API. Для этого я добавил фильтр в свой API-интерфейс (в настоящее время ничего особенного):

public class LogFilter : ActionFilterAttribute
{
    public LogFilter()
    {

    }

    public override void OnActionExecuting(HttpActionContext ActionContext)
    {
        Trace.WriteLine(string.Format("Action Method {0} executing at {1}", ActionContext.ActionDescriptor.ActionName, DateTime.Now.ToShortDateString()), "Web API Logs");

        if (ActionContext.ModelState.IsValid == false)
        {
            ActionContext.Response = ActionContext.Request.CreateErrorResponse(
                HttpStatusCode.BadRequest, ActionContext.ModelState);
        }
    }

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        Trace.WriteLine(string.Format("Action Method {0} executed at {1}", actionExecutedContext.ActionContext.ActionDescriptor.ActionName, DateTime.Now.ToShortDateString()), "Web API Logs");
    }
}

Следующий шаг, который я сделал, - это создание нового атрибута ValidatorAttribute с именем GroupValidatorAttribute (в настоящее время нет специальной реализации, это всего лишь минимальная рабочий пример для демонстрации моей проблемы):

[AttributeUsage(AttributeTargets.Class)]
public class GroupValidatorAttribute : ValidationAttribute
{

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value == null)
        {
            return new ValidationResult("" + validationContext.DisplayName + " cant be null");
        }

        return ValidationResult.Success;
    }
}

Итак, наконец, нам нужен класс модели, использующий атрибут GroupValidator:

[GroupValidator]
public class Student
{
    public int? Age { get; set; }
    public string name { get; set; }
}

Наверняка есть контроллер, который имеет конечную точку с типом post, которая должна получить объект класса ученик (моя модель) из тела:

    [HttpPost]
    [Route("Body")]
    public HttpResponseMessage BodyTest(int id, [FromBody] Student student)
    {
        return Request.CreateResponse(HttpStatusCode.OK,
            "Suc");
    }

Хорошо, пока все хорошо. Это почти работает, как и ожидалось, но один случай приводит меня в безумие. Если я отправляю (отправляю) пустое тело в мою конечную точку в API, возникает исключение System.ArgumentNullException.

Это полное исключение:

"ExceptionMessage": "Der Wert darf nicht NULL sein. \ R \ nParametername: instance", "ExceptionType": "System.ArgumentNullException", "StackTrace ":" bei System.ComponentModel.DataAnnotations.ValidationContext..ctor (Экземпляр объекта, IServiceProvider serviceProvider, валидаторы IDictionary 2 items)\r\n bei System.Web.Http.Validation.Validators.DataAnnotationsModelValidator.Validate(ModelMetadata metadata, Object container)\r\n bei System.Web.Http.Validation.DefaultBodyModelValidator.ShallowValidate(ModelMetadata metadata, BodyModelValidatorContext validationContext, Object container, IEnumerable 1) \ r \ n bei System.Web.Http.Validation.DefaultBodyModelValidator.ValidTataTataTetaTataDataDataTeataTataTehD , Контейнер объектов, IEnumerable`1 валидаторы) \ r \ n bei System.Web.Http.Validation.DefaultBodyModelValidator.Validate (Объектная модель, тип Type, TypeMetadataProvider, метаданныеProvider, HttpActionContext actionContext, String keyPrefix) \ r. Http.ModelBinding.FormatterParameterBinding.d__18.MoveNext () \ r \ n --- Ende der Stapelüberwachung vom vorhergehenden Ort, dem d ie Ausnahme ausgelöst wurde --- \ r \ n bei System.Runtime. ThrowForNonSuccess (Задача) \ r \ n bei System.Runtime.CompilerServices.TaskAwaiter. d ie Ausnahme ausgelöst wurde --- \ r \ n bei System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (Задача задачи) \ r \ n bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndification Task (nDug) Задача bei System.Web.Http.Controllers.ActionFilterResult.d__5.MoveNext () \ r \ n --- Ende der Stapelüberwachung vom vorhergehenden Ort, dem d ie Ausnahme ausgelöst wurde --- \ r \ n bei System.Runtime .CompilerServices.TaskAwaiter.ThrowForNonSuccess (Задача задачи) \ r \ n bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (Задача задачи) \ r \ n bei System.Web.Http.Dispatcher.xt15 (). 1018 *

В моем отладчике я вижу, что методы в моем фильтре и методы в моем валидаторе НЕ ударил. Кто-нибудь может мне помочь?

1 Ответ

0 голосов
/ 19 февраля 2020

Исключение ArgumentNullException("instance") генерируется из конструктора ValidationContext, поскольку instance в вашем случае равно нулю.

Фрагмент кода конструктора ValidationContext: Исходный код

public ValidationContext(object instance, IServiceProvider serviceProvider,
                         IDictionary<object, object> items) 
{
    if (instance == null) {
       throw new ArgumentNullException("instance");
    }
    ....

Теперь к вашему вопросу: в моем отладчике я вижу, что методы в моем фильтре и методы в моем валидаторе НЕ удаляются.

Стек вызовов похож на

DataAnnotationsModelValidator.Validate() ->
            DataAnnotations.ValidationAttribute.GetValidationResult() ->
            GroupValidatorAttribute.IsValid() 

Конструктор ValidationContext создан на Validate() stage (где возникает исключение null), но ваша реализация IsValid() вызывается позже только после того, как проверка null уже выполнена. Следовательно, IsValid() никогда не попадет в ваш случай.

...