将参数传递给验证器 - 流畅的验证

Pass parameter to validator - fluent validation

我有一个用于插入和更新的验证器。我所做的其中一项检查是查看要插入的内容是否已经存在。验证器的代码是:

public GrapeColourValidator(IGrapeRepository grapeRepository)
        {
            _grapeRepository = grapeRepository;

            RuleFor(x => x.Colour)
                .NotEmpty()
                .WithMessage("Colour is required")
                .MaximumLength(_maxLength)
                .WithMessage($"Colour cannot be more that {_maxLength} characters");

            RuleFor(x => x)
                .MustAsync(async (grapeColour, context, cancellation) =>
                {
                    return await GrapeColourExists(grapeColour.Colour).ConfigureAwait(false);
                })
                .WithMessage($"Grape colour already exists");
        }

        private async Task<bool> GrapeColourExists(string grapeColour)
        {
            var colourResult = await _grapeRepository.GetByColour(grapeColour).ConfigureAwait(false);
            return !colourResult.Any(x => x.Colour == grapeColour);
        }

这个问题是它也运行更新,所以颜色肯定存在。我想做的是传递一个参数,所以我可以做类似的事情:

if(isInsert)
            {
                RuleFor(x => x)
                .MustAsync(async (grapeColour, context, cancellation) =>
                {
                    return await GrapeColourExists(grapeColour.Colour).ConfigureAwait(false);
                })
                .WithMessage($"Grape colour already exists");
            }

这可能吗?

我通常在我正在验证的视图模型上使用 属性 来完成此操作。基本上,您需要在视图模型上有一个标志,指示它代表“新”数据还是“现有”数据。

如果您有数字标识符(包括 Guid),只需测试 Id 的默认值:

// For int identifiers:
public class ViewModel
{
    public int Id { get; set; }

    public bool IsNew => Id == default(int);
}

// For GUID identifiers:
public class ViewModel
{
    public Guid Id { get; set; }

    public bool IsNew => Id == default(Guid );
}

然后在验证规则中添加一个When(...)子句:

RuleFor(x => x.Property)
    .Must(...)
    .When(x => x.IsNew);

测试视图模型的缺点 属性 是它可能容易受到请求篡改。有人可以 POST 请求中的非默认 Guid 或 int 并使验证器认为它正在验证持久化对象。

再一次,您应该对每个请求进行身份验证和授权,并检查防伪令牌。