FluentValidation 比较来自不同 类 的 2 个值

FluentValidation compare 2 values from different classes

我在模型中有 2 个 class,我想验证一个 class 的字段中的值小于第二个 class 的字段。我浏览了 Fluent 文档,但找不到真实示例。

public class inputModel
{
    public double Iy { get; set; }
    public bool selfWeight { get; set; }
    public double span { get; set; }
    public string spanType { get; set; }
}

public class pointLoad
{
    public double pLoad { get; set; }
    public double pDist { get; set; }
}

我需要验证字段 pDist 不能大于 span。

public class pointLoadFluentValidator : AbstractValidator<pointLoad>
{
    public pointLoadFluentValidator()
    {
        RuleFor(x => x.pLoad)
            .NotEmpty()
            .NotNull()
            .LessThan(9999);

        RuleFor(x => x.pDist)
            .NotEmpty()
            .NotNull()
            .LessThan(99);

    }

谢谢。

假设您使用的是最新版本的 FV,并且无法在模型之间建立关系,我通常会使用 RootDataContext 来解决这个问题。您还没有说明如何调用验证器,但是此方法成为服务器端调用 - 您需要手动调用验证器,因为您需要填充根数据上下文字典。

提供以上花色,则开始加规则:

RuleFor(x => x.pDist).Must((pointLoad, pDist, validationContext) =>
{
    if (!validationContext.RootContextData.ContainsKey("inputModelToCompareAgainst"))
    {
        return true;
    }

    var inputModel = (inputModel)validationContext.RootContextData["inputModelToCompareAgainst"];
    return pDist <= inputModel.span;
})
.WithMessage("My error message");

然后使用验证上下文调用验证器:

var validator = new pointLoadFluentValidator();
var validationContext = new ValidationContext<pointLoad>(pointLoad);
validationContext.RootContextData["inputModelToCompareAgainst"] = inputModel;
var validationResult = validator.Validate(validationContext);

工作 LINQPad 示例(包含 CustomMust 验证器的示例):

void Main()
{
    var fixture = new Fixture();
    var pointLoad = fixture.Build<pointLoad>().With(x => x.pLoad, 10).With(x => x.pDist, 20).Create();
    var inputModel = fixture.Build<inputModel>().With(x => x.span, pointLoad.pDist - 1).Create();

    var validator = new pointLoadFluentValidator();
    var validationContext = new ValidationContext<pointLoad>(pointLoad);
    validationContext.RootContextData["inputModelToCompareAgainst"] = inputModel;
    var validationResult = validator.Validate(validationContext);

    validationResult.Errors.Select(x => x.ErrorMessage).Should().BeEquivalentTo(new[] { "My error message" });
}

// You can define other methods, fields, classes and namespaces here
public class inputModel
{
    public double Iy { get; set; }
    public bool selfWeight { get; set; }
    public double span { get; set; }
    public string spanType { get; set; }
}

public class pointLoad
{
    public double pLoad { get; set; }
    public double pDist { get; set; }
}

public class pointLoadFluentValidator : AbstractValidator<pointLoad>
{
    public pointLoadFluentValidator()
    {
        RuleFor(x => x.pLoad)
            .NotEmpty()
            .NotNull()
            .LessThan(9999);

        RuleFor(x => x.pDist)
            .NotEmpty()
            .NotNull()
            .LessThan(99);

        //pointLoad.pDist cannot be greater than inputModel.span, therefore pointLoad.pDist must be less than or equal to inputModel.span

        //RuleFor(x => x.pDist).Custom((pDist, validationContext) =>
        //{
        //  if (validationContext.RootContextData.ContainsKey("inputModelToCompareAgainst"))
        //  {
        //      var inputModel = (inputModel)validationContext.RootContextData["inputModelToCompareAgainst"];
        //      if (pDist > inputModel.span)
        //          validationContext.AddFailure("My error message");
        //  }
        //});

        RuleFor(x => x.pDist).Must((pointLoad, pDist, validationContext) =>
        {
            if (!validationContext.RootContextData.ContainsKey("inputModelToCompareAgainst"))
            {
                return true;
            }

            var inputModel = (inputModel)validationContext.RootContextData["inputModelToCompareAgainst"];
            return pDist <= inputModel.span;
        })
        .WithMessage("My error message");
    }
}

如果您依赖 HTTP 请求管道中间件来调用验证器,那么我们需要更多信息。听起来 inputModel 是用户输入。 pointLoad 也是输入吗?它是来自存储库的数据吗?可能还有其他选项(例如,在 inputModel 验证器中执行此验证规则,它将 pointLoad 存储库作为构造函数;验证仍然是服务器端,但可以在中间件中自动完成)。