是否可以从 ValidationAttribute 中的不同模型访问属性
Is it possible to access properties from a different model in a ValidationAttribute
我有一个网络 api,其中包含一些嵌套模型,它们是这样绑定的:
public class Class1 {
//This data is needed in Class2 and Class3 validation
public bool ImportantInformation {get; set;}
public Class2 A {get; set;}
public Class3 B {get; set;}
}
public class Class2 {
[ConditionallyValidatedAttribute]
public string X {get; set;}
}
public class Class3 {
[ConditionallyValidatedAttribute]
public string Y {get; set;}
}
ConditionallyValidatedAttribute
看起来像这样:
public sealed class ConditionallyValidatedAttribute : ValidationAttribute {
protected override ValidationResult IsValid(object value, ValidationContext vc) {
bool importantInformation = //How do I get Class1.ImportantInformation?
if(importantImformation && value == null) {
return new ValidationResult($"{vc.MemberName} is invalid");
}
return ValidationResult.Success;
}
}
我的问题是有什么方法可以根据需要将 ImportantInformation
注入 ConditionallyValidatedAttribute
吗?
据我所知 - 没有办法做到这一点,例如 A
本身并不知道它属于 parent
.
但还有另一种方法。您可以将 ConditionallyValidatedAttribute
应用于 属性 X
或 Y
,而不是将其应用于整个 A
或 B
parent
].这样做,您可以访问 IsValid
方法中的整个 A
和 ImportantInformation
。类似的东西:
public class Class1
{
public bool ImportantInformation {get; set;}
[ConditionallyValidatedAttribute] //-->Validation Attribute here
public Class2 A {get; set;}
public Class3 B {get; set;}
}
public class Class2
{
public string X {get; set;}
}
public sealed class ConditionallyValidatedAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext vc)
{
var importantInformation = bool.Parse(vc.ObjectType.GetProperty("ImportantInformation")?.GetValue(vc.ObjectInstance)?.ToString() ?? "false");
if (importantInformation && (!(value is Class2) || string.IsNullOrEmpty(((Class2)value).X)))
{
return new ValidationResult($"{vc.MemberName} is invalid");
}
return ValidationResult.Success;
}
}
对于这个问题,我遇到了两种解决方案。第一个是 Roman 的(在 class 层次结构中向上移动属性)。第二个是不使用需要来自多个 classes 的信息的验证属性。这是它的样子:
public class MyController : ApiController {
public IHttpActionResult Post(Class1 class1) {
IHttpActionResult actionResult = ValidateSchema(class1);
if(actionResult != null) {
return actionResult;
}
//Do business stuff here
return Ok();
}
private IHttpActionResult ValidateSchema(Class1 class1) {
if(class1.ImportantInformation) {
if(class1.A.X == null) {
ModelState.AddModelError("A.X", "X is invalid");
}
if(class1.B.Y == null) {
ModelState.AddModelError("B.Y", "Y is invalid");
}
}
if(!ModelState.IsValid) {
return BadRequest(ModelState);
}
}
}
我有一个网络 api,其中包含一些嵌套模型,它们是这样绑定的:
public class Class1 {
//This data is needed in Class2 and Class3 validation
public bool ImportantInformation {get; set;}
public Class2 A {get; set;}
public Class3 B {get; set;}
}
public class Class2 {
[ConditionallyValidatedAttribute]
public string X {get; set;}
}
public class Class3 {
[ConditionallyValidatedAttribute]
public string Y {get; set;}
}
ConditionallyValidatedAttribute
看起来像这样:
public sealed class ConditionallyValidatedAttribute : ValidationAttribute {
protected override ValidationResult IsValid(object value, ValidationContext vc) {
bool importantInformation = //How do I get Class1.ImportantInformation?
if(importantImformation && value == null) {
return new ValidationResult($"{vc.MemberName} is invalid");
}
return ValidationResult.Success;
}
}
我的问题是有什么方法可以根据需要将 ImportantInformation
注入 ConditionallyValidatedAttribute
吗?
据我所知 - 没有办法做到这一点,例如 A
本身并不知道它属于 parent
.
但还有另一种方法。您可以将 ConditionallyValidatedAttribute
应用于 属性 X
或 Y
,而不是将其应用于整个 A
或 B
parent
].这样做,您可以访问 IsValid
方法中的整个 A
和 ImportantInformation
。类似的东西:
public class Class1
{
public bool ImportantInformation {get; set;}
[ConditionallyValidatedAttribute] //-->Validation Attribute here
public Class2 A {get; set;}
public Class3 B {get; set;}
}
public class Class2
{
public string X {get; set;}
}
public sealed class ConditionallyValidatedAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext vc)
{
var importantInformation = bool.Parse(vc.ObjectType.GetProperty("ImportantInformation")?.GetValue(vc.ObjectInstance)?.ToString() ?? "false");
if (importantInformation && (!(value is Class2) || string.IsNullOrEmpty(((Class2)value).X)))
{
return new ValidationResult($"{vc.MemberName} is invalid");
}
return ValidationResult.Success;
}
}
对于这个问题,我遇到了两种解决方案。第一个是 Roman 的(在 class 层次结构中向上移动属性)。第二个是不使用需要来自多个 classes 的信息的验证属性。这是它的样子:
public class MyController : ApiController {
public IHttpActionResult Post(Class1 class1) {
IHttpActionResult actionResult = ValidateSchema(class1);
if(actionResult != null) {
return actionResult;
}
//Do business stuff here
return Ok();
}
private IHttpActionResult ValidateSchema(Class1 class1) {
if(class1.ImportantInformation) {
if(class1.A.X == null) {
ModelState.AddModelError("A.X", "X is invalid");
}
if(class1.B.Y == null) {
ModelState.AddModelError("B.Y", "Y is invalid");
}
}
if(!ModelState.IsValid) {
return BadRequest(ModelState);
}
}
}