【问题标题】:Using Required field optionally with ASP.NET MVC Data Annotation可选地使用必填字段和 ASP.NET MVC 数据注释
【发布时间】:2019-12-10 07:29:31
【问题描述】:

我在 ASP.NET MVC 项目中使用 EF 数据注释,对于必填字段,我定义如下所示的字段:

型号:

[Required(ErrorMessage = "Required!");
public string PhoneHome{ get; set; }

[Required(ErrorMessage = "Required!");
public string PhoneWork{ get; set; }

[Required(ErrorMessage = "Required!");
public string PhoneMobile { get; set; }


查看:

@Html.TextBoxFor(m => m.PhoneHome)
@Html.ValidationMessageFor(m => m.PhoneHome, null, new { @class = "field-validation-error" })

@Html.TextBoxFor(m => m.PhoneWork)
@Html.ValidationMessageFor(m => m.PhoneWork, null, new { @class = "field-validation-error" })

@Html.TextBoxFor(m => m.PhoneMobile )
@Html.ValidationMessageFor(m => m.PhoneMobile , null, new { @class = "field-validation-error" })


我只想将这些字段中的一个设为必填(如果用户填写其中一个字段就可以了,但如果他没有填写任何一个字段,我想显示一条错误消息并且不要让他提交表单),但不知道执行此操作的最合适和更智能的方法?我应该在提交时使用 JavaScript 检查所有这些字段并显示必要的错误消息吗?还是我应该只使用数据注释来执行此操作?

【问题讨论】:

  • 澄清一下,您已经知道该解决方案,但是如果您想在 UI 或服务器端进行验证,您会遇到冲突吗?
  • 我认为您最好根据Required 属性创建自己的验证规则,但需要一些额外的参数和额外的验证逻辑。这将在服务器端验证,但您可以轻松地在客户端实现它。
  • @JerdineSabio 实际上这并不能解决问题,因为如果我使用这种方法,则不允许用户仅填写一个字段而将其他两个字段留空。但我想让用户至少填写一个字段。我错了吗?
  • @lordvlad30 我几年前使用过ExpressiveAnnotations。在这个场景中,您的意思是在服务器端使用 ExpressiveAnnotations 并在客户端使用 Javascript 进行必要的更新?
  • @hexadecimal 我将创建您自己的属性来扩展ValidationAttribute (System.ComponentModel.DataAnnotations) 并支持客户端验证,您需要实现IClientValidatable 接口(System.Web.Mvc)。但是,如果您只需要它一次,我可能不会投入太多工作,只需在控制器中验证它,然后再检查 ModelState.IsValid

标签: c# asp.net-mvc entity-framework asp.net-core data-annotations


【解决方案1】:

好的,我举了一个例子。我创建了一个自定义验证属性,其中包含一些参数,例如需要哪些属性以及有多少(最小和最大)。命名不是最好的,但可以完成工作(未经测试)。如果您不关心客户端上的验证(使用 jquery 验证,不引人注目......),您可以删除 ICientValidatable。

属性是这样制作的:

public class OptionalRequired : ValidationAttribute, IClientValidatable
{
    /// <summary>
    /// The name of the client validation rule
    /// </summary>
    private readonly string type = "optionalrequired";

    /// <summary>
    /// The (minimum) amount of properties that are required to be filled in. Use -1 when there is no minimum. Default 1.
    /// </summary>
    public int MinimumAmount { get; set; } = 1;
    /// <summary>
    /// The maximum amount of properties that need to be filled in. Use -1 when there is no maximum. Default -1.
    /// </summary>
    public int MaximumAmount { get; set; } = -1;

    /// <summary>
    /// The collection of property names
    /// </summary>
    public string[] Properties { get; set; }


    public OptionalRequired(string[] properties)
    {
        Properties = properties;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        int validPropertyValues = 0;

        // Iterate the properties in the collection
        foreach (var propertyName in Properties)
        {
            // Find the property
            var property = validationContext.ObjectType.GetProperty(propertyName);

            // When the property is not found throw an exception
            if (property == null)
                throw new ArgumentException($"Property {propertyName} not found.");

            // Get the value of the property
            var propertyValue = property.GetValue(validationContext.ObjectInstance);

            // When the value is not null and not empty (very simple validation)
            if (propertyValue != null && String.IsNullOrEmpty(propertyValue.ToString()))
                validPropertyValues++;
        }

        // Check if the minimum allowed is exceeded
        if (MinimumAmount != -1 && validPropertyValues < MinimumAmount)
            return new ValidationResult($"You are required to fill in a minimum of {MinimumAmount} fields.");

        // Check if the maximum allowed is exceeded
        else if (MaximumAmount != -1 && validPropertyValues > MaximumAmount)
            return new ValidationResult($"You can only fill in {MaximumAmount} of fields");

        // 
        else
            return ValidationResult.Success;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        ModelClientValidationRule rule = new ModelClientValidationRule();

        rule.ErrorMessage = "Enter your error message here or manipulate it on the client side";
        rule.ValidationParameters.Add("minimum", MinimumAmount);
        rule.ValidationParameters.Add("maximum", MaximumAmount);
        rule.ValidationParameters.Add("properties", string.Join(",", Properties));

        rule.ValidationType = type;

        yield return rule;
    }
}

你在你的类/视图模型上这样使用它:

public class Person
{
    [OptionalRequired(new string[] { nameof(MobileNumber), nameof(LandLineNumber), nameof(FaxNumber) }, MinimumAmount = 2)]
    public string MobileNumber { get; set; }
    public string LandLineNumber { get; set; }
    public string FaxNumber { get; set; }
}

使用此配置,您需要填写至少 2 个必填字段,否则将显示错误。 您可以将属性放在每个属性上,以便在所有属性上弹出错误消息。这就是你想要的

对于客户端验证,我在属性上添加了接口并设置了不同的参数,但我没有 JavaScript 本身。你需要查一下(例如here

此代码未经测试,但我认为它可以让您很好地了解事情是如何完成的。

【讨论】:

    【解决方案2】:
    public class MyModel : IValidatableObject
    {
        [Required(ErrorMessage = "Required!");
        public string PhoneHome{ get; set; }
    
        [Required(ErrorMessage = "Required!");
        public string PhoneWork{ get; set; }
    
        [Required(ErrorMessage = "Required!");
        public string PhoneMobile { get; set; }
    
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
    
            if ((PhoneHome+PhoneWork+PhoneMobile).Length < 1)
            {
                yield return new ValidationResult("You should set up any phone number!", new [] { "ConfirmForm" });
            }
        }
    }
    

    【讨论】:

    • 感谢您的回复。我会尝试一下,但是通过使用我的问题中的代码它可以在客户端工作吗?
    • 它似乎可以工作,并在控制器中生成ModelState.IsValid false。但我没有在 ModelState 中看到错误消息(“您应该设置任何电话号码!”)。任何的想法?投票赞成...
    • 另一方面,在这种情况下,[Required(ErrorMessage = "Required!"); 部分应从所有 3 个电话属性中删除。这是真的吗?
    • 当然,您应该从字段中删除必填属性。
    猜你喜欢
    • 2020-02-27
    • 1970-01-01
    • 1970-01-01
    • 2014-01-26
    • 2014-03-04
    • 1970-01-01
    • 2011-05-31
    • 1970-01-01
    • 2011-02-12
    相关资源
    最近更新 更多