Можно ли использовать аннотации данных для проверки параметров, переданных методу действия контроллера?

Я использую аннотации данных для проверки моей модели в ASP.NET MVC. Это хорошо работает для методов действий со сложными параметрами, например,

public class Params  
{  
    [Required] string Param1 {get; set;}   
    [StringLength(50)] string Param2 {get; set;}  
}


ActionResult MyAction(Params params)  
{  
   If(ModeState.IsValid)  
   {  
      // Do Something  
   }  
}

Что, если я хочу передать одну строку методу действия (как показано ниже). Есть ли способ использовать аннотации данных или мне придется обернуть строку в класс?

ActionResult MyAction(string param1, string param2)  
{  
   If(ModeState.IsValid)  
   {  
     // Do Something  
   }  
}  

person dannie.f    schedule 26.04.2010    source источник


Ответы (5)


Я не верю, что для того, что вы предлагаете, существует метод аннотаций данных. Однако, если вы хотите, чтобы проверка выполнялась до вызова метода действия, рассмотрите возможность добавления атрибута пользовательского связывателя модели к параметру и укажите конкретный модуль связывания модели, который вы хотите использовать.

Пример:

public ActionResult MyAction [ModelBinder(typeof(StringBinder)] string param1, [ModelBinder(typeof(StringBinder2)] string param2)
{
  .........
}
person Tejs    schedule 26.04.2010
comment
И сделать ужас из простого решения с моделью просмотра... Я считаю, что не нужно искать другую. - person LukLed; 27.04.2010

Создай свою модель...

public class Params  
{  
    [Required] string param1 {get; set;}   
    [StringLength(50)] string param2 {get; set;}  
}

И измените свою подпись контроллера на стороне сервера:

[HttpGet]
ActionResult MyAction([FromUri] Params params)  
{  
    If(ModeState.IsValid)  
    {  
        // Do Something  
    }  
}  

Если ваш клиентский код уже работал, вам не нужно его менять... Пожалуйста, обратите внимание, что свойства вашей модели совпадают с параметром, который вы передаете сейчас (string param1, string param2)... и они чувствительны к регистру.. .

EDIT: я имею в виду, что вы можете вызвать свой контроллер следующим образом:

http://localhost/api/values/?param1=xxxx¶m2=yyyy

person Ciccio    schedule 15.05.2015
comment
Да, но... если им не хватает строки запроса, действие все еще может выполняться, а модель может быть нулевой и по-прежнему выполнять действие. Итак, нулевая проверка модели. - person Patrick Knott; 28.05.2020
comment
[FromUri] Params params у меня не работает, теперь мне пришлось бы переписать все мои тесты, чтобы вместо этого предоставить этот класс Params. К сожалению, это не жизнеспособное решение. - person Essej; 05.06.2020

С ActionFilterAttribute можно использовать DataAnnotation для параметров действия. Это позволяет вам делать такие вещи:

ActionResult MyAction([Required] string param1, [StringLength(50)] string param2)  
{  
   If(ModeState.IsValid)  
   {  
     // Do Something  
   }  
}

См. решение здесь: https://blog.markvincze.com/how-to-validate-action-parameters-with-dataannotation-attributes/

Он использует фильтр действий, чтобы пройти через все параметры действия запроса и выполнить аннотации данных для них (если они есть).


EDIT: Приведенное выше решение работает только в .NET Core. Я сделал слегка модифицированную версию, которая работает на .NET Framework 4.5 (может работать и на более старых версиях).

public class ValidateActionParametersAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext context)
    {
        var parameters = context.ActionDescriptor.GetParameters();

        foreach (var parameter in parameters)
        {
            var argument = context.ActionArguments[parameter.ParameterName];

            EvaluateValidationAttributes(parameter, argument, context.ModelState);
        }

        base.OnActionExecuting(context);
    }

    private void EvaluateValidationAttributes(HttpParameterDescriptor parameter, object argument, ModelStateDictionary modelState)
    {
        var validationAttributes = parameter.GetCustomAttributes<ValidationAttribute>();

        foreach (var validationAttribute in validationAttributes)
        {
            if (validationAttribute != null)
            {
                var isValid = validationAttribute.IsValid(argument);
                if (!isValid)
                {
                    modelState.AddModelError(parameter.ParameterName, validationAttribute.FormatErrorMessage(parameter.ParameterName));
                }
            }
        }
    }
}
person Maxime    schedule 17.07.2017

ОБНОВЛЕНИЕ: ASP.NET Core 3

В ASP.net Core 3 это работает так, как и должно быть: просто украсьте параметры, как и любое другое свойство ваших DTO.

[HttpPut]
[Route("{id}/user-authorizations")]
public async Task<IActionResult> AuthorizeUsersOnAppsAsync(
   [Range(1, int.MaxValue, ErrorMessage = "Enter the company identifier")] int id,
   [FromBody] List<AuthorizeCompanyUserDto> authorizations)
{
    ...
}

Ответ

введите здесь описание изображения

Наконечник

Вам даже не нужно проверять достоверность модели вручную. Просто украсьте свой контроллер [ApiController], и ASP.NET Core автоматически проверит их.

person Maicon Heck    schedule 26.07.2020

  1. Создайте свой собственный атрибут фильтра:

    public class ActionParameterValidationAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            actionContext
                .ActionDescriptor
                .GetParameters()
                .SelectMany(p => p.GetCustomAttributes<ValidationAttribute>().Select(a => new
                {
                    IsValid = a.IsValid(actionContext.ActionArguments[p.ParameterName]),
                    p.ParameterName,
                    ErrorMessage = a.FormatErrorMessage(p.ParameterName)
                }))
                .Where(_ => !_.IsValid)
                .ToList()
                .ForEach(_ => actionContext.ModelState.AddModelError(_.ParameterName, _.ErrorMessage));
    
            if (!actionContext.ModelState.IsValid)
            {
                actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
            }
        }
    }
    
  2. Используйте его глобально:

    new HttpConfiguration { Filters = { new ModelValidationAttribute() } };
    
person Andriy Tolstoy    schedule 04.09.2017