【问题标题】:FluentValidation compare 2 values from different classesFluentValidation 比较来自不同类的 2 个值
【发布时间】:2021-10-22 18:00:09
【问题描述】:

我在模型中有 2 个类,我想验证一个类的字段中的值是否小于第二类的字段。我浏览了 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);

    }

谢谢。

【问题讨论】:

  • 首先你需要定义这两个类之间的一些关系,否则会在什么基础上比较对象属性?
  • 我需要那个吗?他们都是双打所以我不明白它还需要什么。

标签: c# fluentvalidation


【解决方案1】:

假设您使用的是最新版本的 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 存储库作为构造函数;验证仍然是服务器端,但可以在中间件中自动完成)。

【讨论】:

  • 感谢您的回复。是的 inputModel 和 poitnLoad 都是用户对字段的输入。那么有没有办法简化你的答案呢?谢谢
  • 验证器使用单个模型,要比较两个模型,您需要一种方法来获取另一个模型。如果它们都是同一个请求的输入,那么您需要将它们关联起来,或者将它们放入容器中并验证容器,或者按照我上面的描述进行操作。如果两个模型都在同一个请求中输入,那么它们有什么理由在不同的模型中?您对环境的描述不够充分,无法给您更具体的答案。
猜你喜欢
  • 2023-03-10
  • 1970-01-01
  • 2016-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-10
  • 1970-01-01
相关资源
最近更新 更多