c# MVC 3:防止在属性属性中使用魔法字符串

本文关键字:属性 字符串 MVC | 更新日期: 2023-09-27 18:16:35

我在互联网上发现了一个RequiredIfAttribute,我将其修改为RequiredNotIf。该属性可以这样使用:

[RequiredNotIf("LastName", null, ErrorMessage = "You must fill this.")]
public string FirstName { get; set; }
[RequiredNotIf("FirstName", null, ErrorMessage = "You must fill this")]
public string LastName { get; set; }

源代码到属性…

[AttributeUsageAttribute(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = true)]
public class RequiredNotIfAttribute : RequiredAttribute, IClientValidatable
{
    private string OtherProperty { get; set; }
    private object Condition { get; set; }
    public RequiredNotIfAttribute(string otherProperty, object condition)
    {
        OtherProperty = otherProperty;
        Condition = condition;
    }
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var property = validationContext.ObjectType.GetProperty(OtherProperty);
        if (property == null)
        {
            return new ValidationResult(String.Format("Property {0} not found.", OtherProperty));
        }
        var propertyValue = property.GetValue(validationContext.ObjectInstance, null);
        var conditionIsMet = !Equals(propertyValue, Condition);
        return conditionIsMet ? base.IsValid(value, validationContext) : null;
    }
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
            ValidationType = "requiredif",
        };
        var depProp = BuildDependentPropertyId(metadata, context as ViewContext);
        var targetValue = (Condition ?? "").ToString();
        if (Condition != null && Condition is bool)
        {
            targetValue = targetValue.ToLower();
        }
        rule.ValidationParameters.Add("otherproperty", depProp);
        rule.ValidationParameters.Add("condition", targetValue);
        yield return rule;
    }
    private string BuildDependentPropertyId(ModelMetadata metadata, ViewContext viewContext)
    {
        var depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(OtherProperty);
        var thisField = metadata.PropertyName + "_";
        if (depProp.StartsWith(thisField))
        {
            depProp = depProp.Substring(thisField.Length);
        }
        return depProp;
    }
}

这样做的缺点——正如我所看到的——是属性"header"中的魔法字符串。我怎样才能摆脱它?

c# MVC 3:防止在属性属性中使用魔法字符串

不能去掉它,因为属性是元数据,值必须在编译时知道。如果你想在没有魔法字符串的情况下进行更高级的验证,我强烈推荐你使用FluentValidation.NET。以声明的方式对属性执行验证是非常有限的。只要看看您必须为RequiredIf或RequiredNotIf这样标准而简单的东西编写的源代码的数量就知道了。我不知道框架的设计者在选择数据注释进行验证时是怎么想的。这太荒谬了。也许将来他们会丰富它,允许更复杂的场景,但在那之前我坚持使用FV。

假设您指的是另一个属性名;你不能。属性只能使用有限数量的参数类型—Expression不是其中之一,因此您不能使用lambda技巧(无论如何,这不是一个好主意)。c#没有infoof/memberof运算符。你有的只是字符串之类的东西。

嗯,我猜你可以添加一个非魔法键(即不直接绑定到成员名的键),但这似乎太过了,例如:

// NOT a recommendation
[RequiredNotIf(1, ...)]
public string Foo {get;set;}
[SomeKey(1)]
public string Bar {get;set;}

这已经删除了成员名,但仍然依赖于解析到另一个属性成员的键(1),并且更复杂。它也不太清楚,即在非平凡类上,您可能必须上下扫描以查看哪个其他成员具有匹配的标记。我不喜欢;p