2

好吧,我的问题是我正在使用 aspnetcore 2.1 创建一个 api,为了避免代码重复,我创建了一个抽象类,其属性共享 dtos(板、板创建、板更新等)。我使用 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"});
    }
}
4

3 回答 3

4

虚拟方法添加到您的基类。

如果您想在基类中执行一些常见的验证逻辑以及在每个具体实现中执行额外的验证逻辑,则将虚拟验证方法添加到基类验证函数中调用的基类。

添加到您的基类:

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。此外,因为它 isvirtual和 not abstract,所以您只需要在有额外的自定义逻辑要执行时覆盖它。

于 2019-01-06T18:28:43.857 回答
1

使用虚拟并使用收益率。 IValidatableObject是一个非常清晰的界面,具有非常清晰的意图 - 它在控制器中使用,就像这样

if (ModelState.IsValid) {....}

因此,如果您的 Action 看起来像这样(又好又干净)

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

我的观点是这是一个迭代过程——每个子类必须“继承”其父类的所有验证检查,并在它们之上添加新的验证检查。

于 2020-12-16T14:38:30.280 回答
0

与接受的答案类似,您可以将 Validate 方法的 Base Class 实现虚拟化,然后在您的子类中,覆盖 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;
    }
}
于 2021-05-29T06:18:13.373 回答