如何在 C# 中创建自定义验证属性
如何使用 C# 创建一个简单的验证属性
引言
在创建 REST 等 Web 应用程序时,我们必须处理接收到错误数据的情况。通常,现成的特性不足以正确检查数据,因此在本技巧中,我将尝试解释如何编写我们自己的验证器。
Using the Code
第一步是创建一个新的应用程序。
下一步是安装所需的 NuGet 包。您可以直接从控制台或使用菜单管理器进行安装。
Install-Package System.Linq.Dynamic -Version 1.0.7
本文将创建一个使用条件必需示例的自定义验证器。
现在让我们创建一个继承自“ValidationAttribute
”的类。类似于这样
using System;
using System.ComponentModel.DataAnnotations;
namespace HRP.Services.Attributes
{
public class RequiredIfAttribute : ValidationAttribute
{
protected override ValidationResult IsValid
(object value, ValidationContext validationContext)
{
}
}
}
这个类应该重写继承的 IsValid
方法。这将允许我们将代码连接到数据验证的位置。
整个过程将基于将一个表达式以 string
的形式传递给特性,然后将其重新解析并应用于数据。为此,我们需要添加一个接受 string
值的构造函数,然后将其赋值给一个变量。
private readonly string _condition;
public RequiredIfAttribute(string condition)
{
_condition = condition;
}
下一步是创建一个接受这种表达式形式的文本并将其解析为特定值的方法。
private static Delegate CreateExpression(Type objectType, string expression)
{
var lambdaExpression =
DynamicExpression.ParseLambda(
objectType, typeof(bool), expression);
var func = lambdaExpression.Compile();
return func;
}
现在我们已经准备好这样的方法,应该在检查数据正确性的方法中使用它。
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var conditionFunction = CreateExpression(
validationContext.ObjectType, _condition);
var conditionMet = (bool) conditionFunction.DynamicInvoke(
validationContext.ObjectInstance);
if (!conditionMet) return null;
if (value != null && int.TryParse(value.ToString(), out var parsedValue))
{
return parsedValue == 0
? new ValidationResult($"Field {validationContext.MemberName} is required")
: null;
}
return new ValidationResult($"Field {validationContext.MemberName} is required");
}
我们已经准备好了所有内容,现在只需在模型中应用此验证器即可,例如这样。
public class GetHotelReviewRequest
{
[RequiredIf("AllRecords==false")]
[Range(0, 10, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public int ItemsPerPage { get; set; }
[RequiredIf("AllRecords==false")]
[Range(0, int.MaxValue, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public int Page { get; set; }
[Required] public bool AllRecords { get; set; }
}
我个人将此特性用于分页。我有一个名为“AllRecords
”的值,它是必需的。当应用程序接收到 false 值时,模型中所有具有 [RequiredIf ("AllRecords == false")]
特性的字段也必须填写。
摘要
总而言之,我们创建的特性仅检查给定字段是否有任何值,并且在“int
”的情况下,它是否与零或默认值不同。当然,该特性可以扩展到检查不同类型的值,但是本技巧的主要目标是展示如何使用 DynamicExpression
来创建自己的特性。
历史
- 2020 年 1 月 21 日:初始版本