自定义验证属性未在模型上验证 - WebAPI C# 和 JSON
Posted
技术标签:
【中文标题】自定义验证属性未在模型上验证 - WebAPI C# 和 JSON【英文标题】:Custom Validation Attribute not validating on Model - WebAPI C# and JSON 【发布时间】:2020-11-04 00:08:32 【问题描述】:我创建了一个模型和一个自定义验证属性,以确保该值大于零。我遇到的问题是自定义属性的构造函数被命中,但 IsValid 覆盖从未被命中。
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class GreaterThanZeroAttribute : ValidationAttribute
/// <summary>
/// Ensures that the value is greater than zero.
/// </summary>
public GreaterThanZeroAttribute()
: base("The value 0 must be greater than 0.")
public override bool IsValid(object value)
bool isValueLong = long.TryParse(value?.ToString(), out long longValue);
if (isValueLong && longValue > 0)
return true;
else
return false;
public class ApplicationModel
[Required]
public string Name get; set;
[GreaterThanZero]
public IEnumerable<string> AssignedUserGroupIDs get; set;
现在,客户端将在 JSON 中设置 AssignedUserGroupIDs
。我想验证该集合中的每个 ID 是否大于零。
这是请求的示例 JSON:
"name": "Test Application",
"assignedUserGroupIDs": [ "1", "-1001" ]
对于它的价值,我使用 JsonOptions 来使用驼峰式大小写作为属性名称并将字符串转换为枚举。我之所以提到这一点,是因为我不确定 Json 是否会导致任何问题。
public static IServiceCollection AddWebApiServices(this IServiceCollection services)
_ = services ?? throw new ArgumentNullException(nameof(services));
Setup.AddServices(services);
services.AddMvcCore(ConfigureDefaults)
.AddJsonFormatters()
.AddJsonOptions(options =>
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
options.SerializerSettings.Converters.Add(new StringEnumConverter());
)
.AddCors("*")
.AddControllers();
return services;
这里是控制器:
[HttpPost]
[Route("applications")]
[EnableCors(PolicyName = CorsPolicies.Default)]
public IActionResult CreateApplication([FromBody] ApplicationModel postModel)
List<long> assignedUserGroups = new List<long>();
foreach (string stringUserGroupID in postModel.AssignedUserGroupIDs)
assignedUserGroups.Add(Convert.ToInt64(stringUserGroupID));
// business logic here...
return new JsonResult(applicationID);
【问题讨论】:
【参考方案1】:如果要验证集合中的每个 ID 是否大于零,则需要将 value
强制转换为 IEnumerable
,然后循环遍历列表中的每个项目:
/*
* Changes:
* 1. Rename to CollectionGreaterThanZero to better reflect this validation is
* against a collection.
* 2. Change AttributeUsage to include Field, as there is a backing field behind
* AssignedUserGroupIDs get; set; , and when the data comes in, the backing
* field gets set. That's when you want to run your validation.
* 3. Set AllowMultiple=false as there is no point to run this validation multiple
* times on the same property or field.
*/
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class CollectionGreaterThanZeroAttribute : ValidationAttribute
public override bool IsValid(object value)
// This will case the value to IEnumerable silently.
var enumerable = value as IEnumerable;
if (enumerable != null)
foreach (var item in enumerable)
bool isLong = long.TryParse(item?.ToString(), out long longValue);
if (!isLong)
return false;
// I don't know if you consider an empty collection as a valid
// collection or not in your domain.
return true;
return false;
显示它被击中的屏幕截图:
【讨论】:
现在,客户端将在 JSON 中设置 AssignedUserGroupID。我想验证该集合中的每个 ID 是否大于零。这是请求的示例 JSON:``` "name": "Test Application", "assignedUserGroupIDs": [ "1", "-1001" ] ``` 我真的很喜欢这种方法。谢谢你。我添加了这个,但是当我在方法的第一行放置一个断点时,它永远不会被击中。这让我认为验证实际上并没有发生。有趣的是,如果我添加一个构造函数,它就会被命中。只是不覆盖。 @dn238608:所以客户正在将数据发回给您(因为您的 OP 中并不清楚)?如果是这种情况,我建议将属性用法也更改为包含 Field,因为public IEnumerable<string> AssignedUserGroupIDs get; set;
后面有一个支持字段,并且当客户端将数据发回给您时,支持字段被设置。您希望将此验证应用于支持字段。我还更改了AllowMultiple=false
,因为没有必要在同一个属性或字段上多次应用此验证。请再次查看我的更新。
抱歉,是的,客户(为了测试我正在使用邮递员)正在发回数据。如果值正确,它会发回我期望的值,但是,我将“-1001”作为值,这应该无法通过验证。即使添加了AttributeTargets.Property | AttributeTargets.Field
,我仍然无法在 IsValid 方法中设置断点。
嗯,您可能还想发布您的控制器代码。以上是关于自定义验证属性未在模型上验证 - WebAPI C# 和 JSON的主要内容,如果未能解决你的问题,请参考以下文章
剃须刀页面上自定义验证属性的 ASP.NET Core 客户端验证