You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用When重写FluentValidation的链式AND规则验证逻辑?

使用FluentValidation的When重写链式AND逻辑验证

问题描述

我编写了如下FluentValidation验证代码:

public ActivityValidator(IUserAccessor userAccessor)
{
    var userId = userAccessor.GetUserIdFromAccessToken();

    RuleSet("CompleteHappeningAsync", () =>
    {
        RuleFor(a => a.ActivityTypeId).IsHappening()
        .WithState(x => new BadRequest("Aktivnost nije Događaj"))
            .DependentRules(() =>
            {
                RuleFor(a => a.EndDate).LessThanOrEqualTo(DateTimeOffset.Now)
                .WithState(x => new BadRequest("Događaj se još nije završio"))
                .DependentRules(() =>
                {
                    RuleFor(a => a.EndDate).GreaterThan(DateTimeOffset.Now.AddDays(-7))
                    .WithState(x => new BadRequest("Prošlo je nedelju dana od završetka Događaja"))
                    .DependentRules(() =>
                    {
                        RuleFor(a => a.User.Id).Equal(userId)
                        .WithState(x => new BadRequest("Ne možete završiti tuđi događaj"))
                        .DependentRules(() =>
                        {
                            RuleFor(a => a.HappeningMedias).Empty()
                            .WithState(x => new BadRequest("Već ste završili događaj"));
                        });
                    });
                });
            });
    });
}

请问如何使用官方推荐的When方式重写这段以AND逻辑链式的验证?注意CascadeMode仅适用于单个属性的链式规则,无法适用于当前场景。


重写后的代码

可以通过嵌套When方法实现这种顺序依赖的AND逻辑,每个后续验证仅在前序验证通过时执行,重写后的代码如下:

public ActivityValidator(IUserAccessor userAccessor)
{
    var userId = userAccessor.GetUserIdFromAccessToken();
    var now = DateTimeOffset.Now; // 提取当前时间,避免多次计算产生不一致

    RuleSet("CompleteHappeningAsync", () =>
    {
        // 1. 验证ActivityTypeId属于活动类型
        RuleFor(a => a.ActivityTypeId)
            .IsHappening()
            .WithState(x => new BadRequest("Aktivnost nije Događaj"));

        // 2. 仅当ActivityTypeId验证通过时,验证活动已结束
        When(a => a.ActivityTypeId.IsHappening(), () =>
        {
            RuleFor(a => a.EndDate)
                .LessThanOrEqualTo(now)
                .WithState(x => new BadRequest("Događaj se još nije završio"));

            // 3. 仅当活动已结束时,验证结束时间未超过7天
            When(a => a.EndDate <= now, () =>
            {
                RuleFor(a => a.EndDate)
                    .GreaterThan(now.AddDays(-7))
                    .WithState(x => new BadRequest("Prošlo je nedelju dana od završetka Događaja"));

                // 4. 仅当结束时间在7天内时,验证用户是活动所有者
                When(a => a.EndDate > now.AddDays(-7), () =>
                {
                    RuleFor(a => a.User.Id)
                        .Equal(userId)
                        .WithState(x => new BadRequest("Ne možete završiti tuđi događaj"));

                    // 5. 仅当用户是所有者时,验证活动未被完成过(媒体列表为空)
                    When(a => a.User.Id == userId, () =>
                    {
                        RuleFor(a => a.HappeningMedias)
                            .Empty()
                            .WithState(x => new BadRequest("Već ste završili događaj"));
                    });
                });
            });
        });
    });
}

关键说明

  • 固定当前时间:将DateTimeOffset.Now提前赋值给变量now,避免多次验证中获取到不同时间,保证逻辑一致性。
  • 嵌套When逻辑:每个When的条件对应前序验证的通过规则,完美匹配原代码的链式依赖关系,只有前序验证通过才会触发后续验证。
  • 保持行为一致:所有错误提示和状态返回与原代码完全相同,验证逻辑没有改变。
  • 替代DependentRules:官方推荐用嵌套When替代深层嵌套的DependentRules,代码可读性更强,维护成本更低。

内容的提问来源于stack exchange,提问作者Marwilpuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 12:45:45