【问题标题】:How could i use DRY(don't repeat yourself) in DataAnnotations Error messages form Resourse我如何在来自 Resource 的 DataAnnotations 错误消息中使用 DRY(不要重复自己)
【发布时间】:2017-04-23 09:51:21
【问题描述】:

这是我的代码

    [Required(ErrorMessageResourceType = typeof(DCC.RegistrationVMLiterals), ErrorMessageResourceName = "Required")]
    [RegularExpression("^[0-9]*$", ErrorMessageResourceType =typeof(DCC.RegistrationVMLiterals),ErrorMessageResourceName ="MustBeNumber")]
    [Display(Name = "BeneficiaryNo")]
    public long BeneficiaryNo { get; set; }

    [Required(ErrorMessageResourceType = typeof(DCC.RegistrationVMLiterals), ErrorMessageResourceName = "Required")]
    [RegularExpression("^[a-zA-z]*$",ErrorMessage ="must only be letters")]
    [Display(Name = "FullName")]
    public string FullName { get; set; }
    [Required(ErrorMessageResourceType = typeof(DCC.RegistrationVMLiterals), ErrorMessageResourceName = "Required")]
    [Display(Name = "GenderID")]
    public int GenderID { get; set; }`

【问题讨论】:

  • 您可以编写自定义类范围的ValidationAttribute,它可以在构造函数中接受,例如要检查的属性名称。请参阅代码示例here
  • 如果你看到我发布的简单代码,我使用错误消息资源类型为三个,我怎么能不重复自己
  • 我会告诉你的。

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


【解决方案1】:

我认为你误解了这个概念或 DRY。

你在重复的事实

[Required(ErrorMessageResourceType = typeof(DCC.RegistrationVMLiterals), ErrorMessageResourceName = "Required")]
[RegularExpression("^[0-9]*$", ErrorMessageResourceType =typeof(DCC.RegistrationVMLiterals),ErrorMessageResourceName ="MustBeNumber")]

在这种情况下不是重复。

重复会是这样的:

public void DoSomething()
{
    string myString = "ABC";
    Print(myString);
    Do something...
}

public void DoSomething1()
{
    string myString = "ABC";
    Print(myString);
    Do something different...
}

对此的 DRY 响应是

public void DoSomething()
{
    Print(getString());
    Do something...
}

public void DoSomething1()
{
    Print(getString());
    Do something different...
}

public string getString()
{
    return "ABC";
}

【讨论】:

  • 我个人认为你的代码很好。如果您想抽象注释的重复,您的代码将变得比它需要的复杂得多,在这种情况下没有任何好处。
  • @AndrewHarris,无论如何这有点重复问题,所以如果你有一个巨大的领域模型,你可以为自己简化一点工作。
  • @Ryan 我不同意。 DRY 是关于解决重复代码块在一个地方而不是另一个地方更新的问题(作为一个例子)。这里的每个字段都是并且应该单独定义。
  • @AndrewHarris,完全同意你的看法。实际上,对于当前的特殊情况,我的解决方案看起来像是过度工程,在大型项目中更重要的是,这是一个权衡问题:将属性应用于类,或者只是多次复制粘贴相同的代码。但是解决方案有权生存,所以没有必要争论。
  • 在您想要重用正则表达式之类的东西的大型项目中,将日志记录应用到属性和其他一些事情我绝对同意您可以这样做,但在大多数情况下它不能解决问题 DRY看起来可以防止(重复的正则表达式模式除外)。
【解决方案2】:

试试这个,没有测试过,但这应该可以工作:

[AttributeUsage(AttributeTargets.Class)]
public class AggregatedRequiredAttribute: ValidationAttribute
{
    private readonly string[] _propertiesToValidate;
    private readonly string message = Resources.ValRequired;

    public AggregatedRequiredAttribute(params string[] propertiesToValidate)
    {
        if (propertiesToValidate == null || !propertiesToValidate.Any()) throw new ArgumentException(nameof(propertiesToValidate));
        _propertiesToValidate = propertiesToValidate;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (!validationContext.ObjectType.GetMember(validationContext.MemberName).Any())
            throw new InvalidOperationException("Current type does not contain such property.");

        if (!_propertiesToValidate.Contains(validationContext.MemberName))
            return ValidationResult.Success;

        var defaultRequired = new RequiredAttribute() {ErrorMessage = message};
        return defaultRequired.IsValid(value) ? ValidationResult.Success : new ValidationResult(message);
    }
}

然后你可以像这样使用它(默认MVC模板中的ViewModel):

[AggregatedRequired("Email","Password")]
public class RegisterViewModel
{
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}

请注意,我只使用了一次错误消息字符串,您也可以在错误消息中使用一些字母并将其动态替换为正在验证的属性的实际名称。

更新

我不确定第一个if 语句,你应该测试它。

更新 2

另外我猜我使用了错误的IsValid 方法,但想法本身很清楚。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-07
    相关资源
    最近更新 更多