C # MVC 3: предотвратить магическую строку в атрибуте свойства - PullRequest
1 голос
/ 05 декабря 2011

В Интернете я нашел атрибут 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;
    }
}

Недостаток с этим - как я вижуэто - волшебная строка в атрибуте «заголовок».Как от этого избавиться?

Ответы [ 2 ]

5 голосов
/ 05 декабря 2011

Вы не можете избавиться от этого, потому что атрибуты являются метаданными, а значения должны быть известны во время компиляции. Если вы хотите выполнить более сложную проверку без волшебных строк, я настоятельно рекомендую вам FluentValidation.NET . Выполнение проверки с атрибутами декларативным способом является очень ограничивающим ИМХО. Просто посмотрите на количество исходного кода, которое вы должны написать для чего-то стандартного и простого, например RequiredIf или RequiredNotIf. Я не знаю, о чем думали дизайнеры фреймворка, когда выбирали аннотации данных для проверки. Это просто смешно. Возможно, в будущем они обогатят его и позволят использовать более сложные сценарии, но до тех пор я буду придерживаться FV.

0 голосов
/ 05 декабря 2011

Предполагая, что вы имеете в виду другое свойство ты не можешь Атрибуты могут использовать только ограниченное количество типов параметров - Expression не является одним из них, поэтому вы не можете использовать лямбда-трюк (хотя в любом случае это было бы неплохо). А в C # нет оператора infoof / memberof. Так что все, что у вас есть, это такие вещи, как строки

Ну, я думаю, вы могли бы добавить немагический ключ (то есть тот, который не привязан непосредственно к имени участника), но это кажется чрезмерным излишним, например:

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

[SomeKey(1)]
public string Bar {get;set;}

Это позволило удалить имя члена, но все еще зависит от ключа (1), разрешающего другой приписанный член, и является более сложным. Это также менее понятно, то есть для нетривиального класса вам, возможно, придется сканировать вверх и вниз, чтобы увидеть, какой другой член имеет соответствующий тег. Я не фанат; р

...