Take the 2-minute tour ×

I found a RequiredIfAttribute on the internet which I modified to RequiredNotIf. The attribute can be used like this.

[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; }

And the source code to the attribute...

[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;

        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;

The drawback with this - as I see it - is the magic string in the attribute "header". How can I get rid of it?

share|improve this question
Are you sure you need that? In your use case, the Required attribute should do the trick. –  ssg Dec 5 '11 at 7:48
Yes, I need it. I use a for loop to view the form multiple times. Therefore, there might be a pair of FirstName and LastName that both contains values, and there might also be a pair with don't. The RequiredNotIfAttributes then becomes handy if a pair only contains only one value. –  Bridget the Midget Dec 5 '11 at 8:22
add comment

2 Answers

up vote 4 down vote accepted

You can't get rid of it because attributes are metadata and values must be known at compile time. If you want to do more advanced validation without magic strings I would very strongly recommend you FluentValidation.NET. Performing validation with attributes in a declarative manner is very limiting IMHO. Just look at the quantity of source code you have to write for something as standard and easy as RequiredIf or RequiredNotIf. I don't know what the designers of the framework were thinking when they choose Data Annotations for validation. It's just ridiculous. Maybe in the future they will enrich it and allow for more complex scenarios but until then I stick with FV.

share|improve this answer
Totally agree. I use FluentValidation too, on businesslayer for POCO validation. The only rare cases I use dataannotations is when I have a view that handles data that is not sent to the DB (i.e. a contact form) so I can keep the whole loop in the UI level. For everything else, FluentValidation. –  Matteo Mosca Dec 5 '11 at 8:21
FluentValidation seems to be the way to go! Thank you! –  Bridget the Midget Dec 5 '11 at 8:48
add comment

Assuming you mean the other property name; you can't. Attributes can only use a limited number of parameter types - Expression is not one of them, so you can't use the lambda trick (not that it would be a good idea anyway). And C# does not have a infoof / memberof operator. So all you have is things like strings.

Well, I guess you could add a non-magic key (i.e. one that doesn't tie directly to a member-name), but it seems massive overkill, for example:

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

public string Bar {get;set;}

This has removed the member-name, but still has a dependency on the key (1) resolving to another attributed member, and is more complex. It is also less clear, i.e. on a non-trivial class you might have to scan up and down to see which other member has the matching tag. I'm not a fan ;p

share|improve this answer
add comment

Your Answer


