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

如何在不同视图复用同一ViewModel并排除必填属性?

嘿,这个问题我之前做项目的时候也遇到过——不想新建ViewModel又要跳过特定属性的必填验证,其实有几个实用的方案可以解决,我给你详细说说:

方案1:实现IValidatableObject接口做场景化验证

这种方式能让你在ViewModel内部根据不同的使用场景,灵活控制是否验证那些必填属性。你只需要给ViewModel加一个场景标识属性,然后在Validate方法里判断场景,选择性执行验证逻辑。

修改后的ViewModel代码示例:

public class AddBookingsViewModel : IValidatableObject
{
    // 新增场景标识,用来区分不同视图的使用场景
    public string ValidationScenario { get; set; }

    // 这里可以先去掉原来的[Required]注解,或者保留也没关系,因为我们会手动控制验证逻辑
    public string CustomerName { get; set; }

    public string ContactNo { get; set; }

    public string VehicleRegNo { get; set; }
    // 其他属性...

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        // 如果当前场景不是AddAppointment(也就是你要复用的那个视图场景),直接跳过必填验证
        if (ValidationScenario != "AddAppointment")
        {
            yield break;
        }

        // 手动执行必填项验证
        if (string.IsNullOrEmpty(CustomerName))
        {
            yield return new ValidationResult("客户姓名不能为空", new[] { nameof(CustomerName) });
        }
        if (string.IsNullOrEmpty(ContactNo))
        {
            yield return new ValidationResult("联系电话不能为空", new[] { nameof(ContactNo) });
        }
    }
}

然后在不需要验证必填项的Action里,设置场景标识:

public IActionResult ReuseView(AddBookingsViewModel model)
{
    model.ValidationScenario = "ReuseScenario";
    // 框架会自动调用Validate方法进行验证
    if (!ModelState.IsValid)
    {
        // 处理验证失败逻辑
    }
    // 后续业务逻辑
    return View(model);
}
方案2:在Action中手动移除模型状态错误

如果你的场景比较简单,不想改ViewModel的话,可以直接在Action里把那两个必填属性的错误从ModelState中移除,这样模型就会被判定为有效。

示例代码:

public IActionResult ReuseView(AddBookingsViewModel model)
{
    // 移除指定属性的验证错误
    ModelState.Remove(nameof(model.CustomerName));
    ModelState.Remove(nameof(model.ContactNo));

    // 现在重新检查模型有效性
    if (ModelState.IsValid)
    {
        // 执行业务逻辑
    }
    return View(model);
}

这个方法很直接,但要注意硬编码了属性名,如果后续属性改名,记得同步修改这里,不然会出问题。

方案3:自定义条件验证特性

你可以创建一个自定义的RequiredIfScenario特性,替代原来的[Required],这样就能根据场景动态决定是否启用必填验证,比手动写逻辑更优雅。

先定义自定义特性:

public class RequiredIfScenarioAttribute : ValidationAttribute
{
    // 需要验证的场景名称
    public string TargetScenario { get; set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var viewModel = validationContext.ObjectInstance as AddBookingsViewModel;
        if (viewModel == null)
        {
            return ValidationResult.Success;
        }

        // 如果当前场景不是目标场景,直接跳过验证
        if (viewModel.ValidationScenario != TargetScenario)
        {
            return ValidationResult.Success;
        }

        // 否则执行必填验证
        if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
        {
            return new ValidationResult(ErrorMessage ?? $"{validationContext.DisplayName} 不能为空");
        }

        return ValidationResult.Success;
    }
}

然后修改ViewModel的属性注解:

public class AddBookingsViewModel
{
    public string ValidationScenario { get; set; }

    [RequiredIfScenario(TargetScenario = "AddAppointment", ErrorMessage = "客户姓名不能为空")]
    public string CustomerName { get; set; }

    [RequiredIfScenario(TargetScenario = "AddAppointment", ErrorMessage = "联系电话不能为空")]
    public string ContactNo { get; set; }

    public string VehicleRegNo { get; set; }
    // 其他属性...
}

使用方式和方案1一样,在Action里设置ValidationScenario即可,这个特性还能复用在其他ViewModel上,扩展性更好。

方案4:使用FluentValidation(推荐)

如果你的项目可以引入FluentValidation库,那它的条件验证能力会更强大,完全解耦验证逻辑和ViewModel,后期维护也更方便。

首先安装NuGet包FluentValidation.AspNetCore,然后创建验证器:

public class AddBookingsViewModelValidator : AbstractValidator<AddBookingsViewModel>
{
    public AddBookingsViewModelValidator()
    {
        // 只有在AddAppointment场景下,才验证CustomerName和ContactNo为必填
        RuleFor(x => x.CustomerName)
            .NotEmpty()
            .WithMessage("客户姓名不能为空")
            .When(x => x.ValidationScenario == "AddAppointment");

        RuleFor(x => x.ContactNo)
            .NotEmpty()
            .WithMessage("联系电话不能为空")
            .When(x => x.ValidationScenario == "AddAppointment");

        // 其他验证规则可以在这里添加
    }
}

然后在Startup.cs里注册验证器:

services.AddControllersWithViews()
    .AddFluentValidation(fv => 
        fv.RegisterValidatorsFromAssemblyContaining<AddBookingsViewModelValidator>());

使用时同样在Action里设置ValidationScenario,FluentValidation会自动根据场景应用对应的验证规则,这种方式特别适合复杂的验证场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:18:18