【问题标题】:How to do Semi-Required attributes in ASP MVC?如何在 ASP MVC 中做半必需的属性?
【发布时间】:2011-12-21 04:21:50
【问题描述】:

我有一个具有 DropDownList 和 TextBox 的 MVC 应用程序。我正在使用 MVC 验证,对此我很满意。

目前 DropDownList 是 [必需的],但我想让 TextBox 可以作为 DropDownList 的“其他:请指定”样式输入。

如何使 DropDownList 上的 [Required] 属性以 TextBox 为空为条件?

This 问题类似,但已经有一年多了。当前版本的 MVC 中有什么可以让这变得容易吗?

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3 validation


    【解决方案1】:

    编写自定义验证属性非常容易:

    public class RequiredIfPropertyIsEmptyAttribute : RequiredAttribute
    {
        private readonly string _otherProperty;
        public RequiredIfPropertyIsEmptyAttribute(string otherProperty)
        {
            _otherProperty = otherProperty;
        }
    
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var property = validationContext.ObjectType.GetProperty(_otherProperty);
            if (property == null)
            {
                return new ValidationResult(string.Format("Unknown property {0}", _otherProperty));
            }
    
            var otherPropertyValue = property.GetValue(validationContext.ObjectInstance, null);
            if (otherPropertyValue == null)
            {
                return base.IsValid(value, validationContext);
            }
            return null;
        }
    }
    

    那么你可以有一个视图模型:

    public class MyViewModel
    {
        public string Foo { get; set; }
    
        [RequiredIfPropertyIsEmpty("Foo")]
        public string SelectedItemId { get; set; }
    
        public IEnumerable<SelectListItem> Items {
            get
            {
                return new[] 
                {
                    new SelectListItem { Value = "1", Text = "item 1" },
                    new SelectListItem { Value = "2", Text = "item 2" },
                    new SelectListItem { Value = "3", Text = "item 3" },
                };
            }
        }
    }
    

    控制器:

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View(new MyViewModel());
        }
    
        [HttpPost]
        public ActionResult Index(MyViewModel model)
        {
            return View(model);
        }
    }
    

    当然还有观点:

    @model MyViewModel
    
    @using (Html.BeginForm())
    {
        <div>
            @Html.LabelFor(x => x.Foo)
            @Html.EditorFor(x => x.Foo)
        </div>
        <div>
            @Html.LabelFor(x => x.SelectedItemId)
            @Html.DropDownListFor(x => x.SelectedItemId, Model.Items, "-- select an item --")
            @Html.ValidationMessageFor(x => x.SelectedItemId)
        </div>
    
        <input type="submit" value="OK" />
    }
    

    或者你可以像我一样做:下载并使用FluentValidation.NET library,忘记数据注释并编写以下验证逻辑,这看起来很不言自明:

    public class MyViewModelValidator: AbstractValidator<MyViewModel> 
    {
        public MyViewModelValidator() 
        {
            RuleFor(x => x.SelectedItemId)
                .NotEmpty()
                .When(x => !string.IsNullOrEmpty(x.Foo));
        }
    }
    

    请继续Install-Package FluentValidation.MVC3,让您的生活更轻松。

    【讨论】:

    • FluentValidation 方法是否意味着我必须为我使用的任何 ViewModel 编写一个单独的验证类?我确实很欣赏语法,但似乎我会为自己做额外的工作,编写一个单独的 ModelValidator 类和包含 RuleFor(x => x.name).NotNull() 的构造函数,而我可以只写 [Required]?
    • 其实上面的第一种方法似乎对我不起作用。没有编译或运行时错误或任何东西,它只是不会发生。即使填充了 TextBox,仍然会捕获空的 DropDownList。毕竟我可能会尝试 FluentValidation
    • roryok - 您不会为您编写的每个 ViewModel 使用单独的数据注释吗?
    • @roryok,是的,使用 FluentValidation,这意味着用于执行验证的单独类。这就是它的重要部分。验证与视图模型是分开的。它也可以单独和隔离地进行单元测试。相信我,一旦你尝试过,你将永远不会再写一个数据注释了。
    • @roryok,如果它不适合你,你一定错过了一些东西。我已经测试了代码并且它有效。创建一个新的 ASP.NET MVC 3 项目,并完全按照我的答案所示粘贴代码。您的视图模型上可能有 Required 属性或其他内容。
    【解决方案2】:

    您可以创建一个 ConditionalAttribute。

    ASP.net MVC conditional validation

    ASP.NET MVC Conditional validation

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-27
      • 1970-01-01
      • 1970-01-01
      • 2012-09-16
      • 2013-04-24
      • 1970-01-01
      • 2011-12-17
      • 1970-01-01
      相关资源
      最近更新 更多