是否可以使用数据注释来验证传递给控制器​​的操作方法的参数?

发布于 2024-08-30 12:37:51 字数 536 浏览 6 评论 0原文

我正在使用数据注释来验证 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  
   }  
}  

I am using Data Annotations to validate my Model in ASP.NET MVC. This works well for action methods that has complex parameters e.g,

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


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

What if I want to pass a single string to an Action Method (like below). Is there a way to use Data Annotations or will I have to wrap the string into a class?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

携余温的黄昏 2024-09-06 12:37:51

创建您自己的模型...

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

如果您的客户端代码已经工作,则不必更改它...请注意,模型的属性与参数相同您现在正在传递(字符串 param1,字符串 param2)...并且它们区分大小写...

编辑
我的意思是你可以通过这种方式调用你的控制器:

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

Create your own model...

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

And change your signature of your server side controller:

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

If your client side code already worked you don't have to change it... Please, note that the properties of your Model are the same of the parameter you are passing now (string param1, string param2)... and they are case sensitive...

EDIT:
I mean that you can call your controller in this way:

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

人生百味 2024-09-06 12:37:51

我不相信您所提议的方法有数据注释方法。但是,如果您希望在调用操作方法之前进行验证,请考虑向参数添加自定义模型绑定程序属性并指定要使用的特定模型绑定程序。

例子:

public ActionResult MyAction [ModelBinder(typeof(StringBinder)] string param1, [ModelBinder(typeof(StringBinder2)] string param2)
{
  .........
}

I don't believe there is a Data Annotations method to what you are proposing. However, if you want your validation to happen before the action method is invoked, consider adding a custom model binder attribute to the parameter and specify a specific model binder you want to use.

Example:

public ActionResult MyAction [ModelBinder(typeof(StringBinder)] string param1, [ModelBinder(typeof(StringBinder2)] string param2)
{
  .........
}
紫南 2024-09-06 12:37:51

通过 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/

它使用一个动作过滤器来传递查询的所有动作参数并执行它们的数据注释(如果有的话)。


编辑:上述解决方案仅适用于.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));
                }
            }
        }
    }
}

With ActionFilterAttribute it is possible to use DataAnnotation on action parameters. This enables you to do things like this:

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

See the solution here: https://blog.markvincze.com/how-to-validate-action-parameters-with-dataannotation-attributes/

It uses an action filter to pass through all the action parameters of the query and execute the data annotations on them (if there is any).


EDIT: The solution above only works in .NET Core. I made a slightly modified version that works on .NET Framework 4.5 (might work on older versions)

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));
                }
            }
        }
    }
}
清音悠歌 2024-09-06 12:37:51

更新: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)
{
    ...
}

响应

enter image description here

提示

您甚至不需要手动检查模型有效性。
只需使用 [ApiController] 装饰您的控制器,ASP.NET Core 就会自动验证它们。

UPDATE: ASP.NET Core 3

In ASP.net Core 3 it's working as supposed to be: Just decorate the parameters like any other property of your DTOs.

[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)
{
    ...
}

Response

enter image description here

Tip

You don't even need to check the model validity manually.
Just decorate your controller with the [ApiController] and ASP.NET Core will automatic validate them.

夜雨飘雪 2024-09-06 12:37:51

在这里发表评论是因为这里的解决方案不适合我的场景,所以只是想出了我自己的解决方案。

这适用于 MVC5 Web 应用程序中的 ASP.NET Framework 4.5.2。这段代码绝不是完美的,因为我很快就把它组合在一起以进行概念验证,但它确实可以编译。您可以删除我返回 BadRequest 状态代码结果的部分,并将验证错误添加到模型状态 - 或者执行您的要求所需的任何操作。

首先创建一个自定义属性类:

public class DataAnnotationFilterAttribute : ActionFilterAttribute, IResultFilter
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {

        var actionParams = filterContext.ActionDescriptor.GetParameters();

        if (actionParams != null)
        {
            foreach (var param in actionParams)
            {
                ValidationAttribute[] atts = (ValidationAttribute[])param.GetCustomAttributes(typeof(ValidationAttribute), false);

                if (atts != null && filterContext.ActionParameters.TryGetValue(param.ParameterName, out object value))
                {
                    foreach(ValidationAttribute att in atts)
                    {
                        if (!att.IsValid(value))
                            filterContext.Result = new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
                    }
                }
            }
        }
        
        base.OnActionExecuting(filterContext);
    }
}

然后在 FilterConfig.cs 中注册您的属性,该属性应该已经是您项目的一部分:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute()); // this was existing
        filters.Add(new DataAnnotationFilterAttribute());
    }
}

现在您可以在 MVC 操作参数上使用从“ValidationAttribute”继承的属性。

Commenting here because the solutions on here weren't right for my scenario, so just came up with my own solution instead.

This works for ASP.NET Framework 4.5.2, in an MVC5 web application. This code is by no means perfect as I threw it together very quickly for a proof of concept, but it does compile. You can remove the part where I return a BadRequest status code result and add the validation errors to the model state - or do whatever your requirements need.

First create a custom attribute class:

public class DataAnnotationFilterAttribute : ActionFilterAttribute, IResultFilter
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {

        var actionParams = filterContext.ActionDescriptor.GetParameters();

        if (actionParams != null)
        {
            foreach (var param in actionParams)
            {
                ValidationAttribute[] atts = (ValidationAttribute[])param.GetCustomAttributes(typeof(ValidationAttribute), false);

                if (atts != null && filterContext.ActionParameters.TryGetValue(param.ParameterName, out object value))
                {
                    foreach(ValidationAttribute att in atts)
                    {
                        if (!att.IsValid(value))
                            filterContext.Result = new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
                    }
                }
            }
        }
        
        base.OnActionExecuting(filterContext);
    }
}

Then register your attribute in FilterConfig.cs, which should already be part of your project:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute()); // this was existing
        filters.Add(new DataAnnotationFilterAttribute());
    }
}

Now you can use attributes that inherit from the "ValidationAttribute" on your MVC action parameters.

归属感 2024-09-06 12:37:51
  1. 创建您自己的过滤器属性:

    公共类 ActionParameterValidationAttribute : ActionFilterAttribute
    {
        公共覆盖无效OnActionExecuting(HttpActionContext actionContext)
        {
            动作上下文
                .ActionDescriptor
                .GetParameters()
                .SelectMany(p => p.GetCustomAttributes().Select(a => new
                {
                    IsValid = a.IsValid(actionContext.ActionArguments[p.ParameterName]),
                    p.参数名称,
                    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() } };
    
  1. Create your own filter attribute:

    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. Use it globally:

    new HttpConfiguration { Filters = { new ModelValidationAttribute() } };
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文