好吧,我的问题是我正在使用aspnetcore 2.1创建一个api,为避免代码重复,我创建了一个抽象类,该类具有共享dto的属性(board,boardforcreation,boardforupdate等)。我添加了使用ivalidatableobject的抽象类的个性化验证,现在,我想向从抽象类派生的类中添加个性化验证,但它告诉我从ivalidatableobject接口扩展是多余的,因为它已经在基类中声明了,并且当我在派生类中添加Validate方法时,它告诉我已经声明并实现了该方法,那么,如何使用ivalidatableobject在抽象类和派生类中添加验证?还是有另一种方法来实现这一目标。预先谢谢你。
public class Board : BoardAbstractBase, IValidatableObject
{
public Guid BoardId { get; set; }
public DateTimeOffset StartDate { get; set; }
public DateTimeOffset EndDate { get; set; }
}
public abstract class BoardAbstractBase : AbstractBasicEntity, IValidatableObject
{
public DateTimeOffset EstimatedStartDate { get; set; }
public DateTimeOffset EstimatedEndDate { get; set; }
public decimal EstimatedBudget { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!(EstimatedStartDate < EstimatedEndDate))
yield return new ValidationResult(
"StartDateBeforeEndDate|The estimated start date should be smaller than the end date.",
new[] {"BoardAbstractBase"});
}
}
答案 0 :(得分:2)
向基类添加虚拟方法。
如果要在基类中执行一些通用的验证逻辑,并在每个具体实现中执行额外的验证逻辑,则可以在基类中添加一个虚拟验证方法,该方法在基类验证函数中调用。
添加到您的基类:
public abstract class BoardAbstractBase {
...
protected virtual bool RepoValidate() {
return true;
}
...
}
然后在每个具体的实现中,以RepoValidate
所需的自定义验证逻辑来实现protected override bool RepoValidate() {...}
。
例如
public class Board : BoardAbstractBase, IValidatableObject
{
...
protected override bool RepoValidate() {
return this.BoardId == "";
}
...
}
然后在BoardAbstractBase.Validate
中输入
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!(EstimatedStartDate < EstimatedEndDate))
yield return new ValidationResult(
"StartDateBeforeEndDate|The estimated start date should be smaller than the end date.",
new[] {"BoardAbstractBase"});
if (!this.RepoValidate()){ ... }
}
现在,您可以随时修改RepoValidate
以返回验证结果,如果验证失败,则可以接受任何参数,但是仅出于示例的目的,该结果仅返回false。另外,由于它是virtual
而不是abstract
,因此仅在需要执行其他自定义逻辑时才需要覆盖它。
答案 1 :(得分:0)
使用虚拟并使用收益率。
IValidatableObject
是一个非常清晰的界面,带有非常清晰的意图-像这样在Controller中使用
if (ModelState.IsValid) {....}
因此,如果您的“操作”看起来像这样(干净漂亮)
public Task<IActionResult> DoSomeAction(SomeClass model)
{
if (ModelState.IsValid) {
...
}
else return View(model);
}
然后您的代码将类似于
public BaseClass : IValidatableObject
{
// and implements
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (...)
yield return new ValidationResult($"...error - ",
new string[] { "variable1 name" });
if (...)
yield return new ValidationResult($"...error2 - ",
new string[] { "variable1", "variable2" });
}
public class SomeClass : SomeBaseClass, IValidatableObject
{
// and implements
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var baseErrors = base.Validate(validationContext);
if (baseErrors != null && baseErrors.Any())
{
foreach (var item in baseErrors)
{
yield return item;
}
}
if (...some error condition...)
yield return new ValidationResult($"Validation error - condition 1",
new string[] { "variable1 });
}
我的意思是,这是一个反复的过程-每个子类都必须“继承”其父代的所有验证检查,并在其之上添加新的验证检查。
答案 2 :(得分:0)
与接受的答案类似,您可以将 Validate 方法的基类实现虚拟化,然后在您的子类中,覆盖 Validate 方法,首先返回继承的结果,然后为子类添加自定义验证逻辑。请参阅下面的简化示例
public abstract class BoardBase: IValidatableObject
{
public int Id { get; set; }
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
if (Id != 1)
{
results.Add(new ValidationResult("Id must be 1"));
}
return results;
}
}
public class Board: BoardBase
{
public string Name { get; set; }
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = base.Validate(validationContext).ToList();
if (Name.Length > 4)
{
results.Add(new ValidationResult("Name must be shorter than 5"));
}
return results;
}
}