Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

255
Views
FluentValidation: validate only one property is set

I'm struggling with implementing a validator for a class, where only one property should be set.

Let's say we have the following class:

public class SomeClass
{
    public DateTime SomeDate {get; set;}
    public IEnumerable<int> FirstOptionalProperty {get; set;}
    public IEnumerable<int> SecondOptionalProperty {get; set;}
    public IEnumerable<int> ThirdOptionalProperty {get; set;}
}

This class has one mandatory property - SomeDate. Other properties are optional and only one can be set e.g if FirstOptionalProperty is set - SecondOptionalProperty and ThirdOptionalProperty should be null, if SecondOptionalProperty is set - FirstOptionalProperty and ThirdOptionalProperty should be null and so forth.

In other words: if one of IEnumerable props is set - other IEnumerables should be null.

Any tips/ideas on implementing validator for such type of class? The only thing I came up with is writing chunks of When rules, but this way of writing code is error prone and result looks ugly.

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

You can take advantage of the Must overload that gives you access to the whole class object so that you can do a property validation against other properties. See FluentValidation rule for multiple properties for more details.

public class SomeClassValidator : AbstractValidator<SomeClass>
{
    private const string OneOptionalPropertyMessage = "Only one of FirstOptionalProperty, SecondOptionalProperty, or ThirdOptionalProperty can be set.";

    public SomeClassValidator()
    {
        RuleFor(x => x.FirstOptionalProperty)
            .Must(OptionalPropertiesAreValid)
            .WithMessage(OneOptionalPropertyMessage);

        RuleFor(x => x.SecondOptionalProperty)
            .Must(OptionalPropertiesAreValid)
            .WithMessage(OneOptionalPropertyMessage);

        RuleFor(x => x.ThirdOptionalProperty)
            .Must(OptionalPropertiesAreValid)
            .WithMessage(OneOptionalPropertyMessage);
    }

    // this "break out" method only works because all of the optional properties
    // in the class are of the same type. You'll need to move the logic back
    // inline in the Must if that's not the case.
    private bool OptionalPropertiesAreValid(SomeClass obj, IEnumerable<int> prop)
    {
        // "obj" is the important parameter here - it's the class instance.
        // not going to use "prop" parameter.

        // if they are all null, that's fine
        if (obj.FirstOptionalProperty is null && 
            obj.SecondOptionalProperty is null && 
            obj.ThirdOptionalProperty is null)
        {
            return true;
        }

        // else, check that exactly 1 of them is not null
        return new [] 
        { 
            obj.FirstOptionalProperty is not null,
            obj.SecondOptionalProperty is not null, 
            obj.ThirdOptionalProperty is not null
        }
        .Count(x => x == true) == 1;
        // yes, the "== true" is not needed, I think it looks better
    }
}

You can tweak the check function. As this currently stands, if you set 2 or more of the optional properties, ALL of them will throw an error. That may or may not be fine for your needs.

You could also make a RuleFor ONLY for the first optional property, rather than all of them, as all the properties will be executing the same IsValid code and return the same message, your user might just get a bit confused if they get an error message for OptionalProperty1 but they didn't supply that one.

The downside to this approach is that you need to know at compile time what all your properties are (so you can write the code for it), and you need to maintain this validator if you add/remove optional entries. This downside may or may not be important to you.

over 4 years ago · Santiago Trujillo Report

0

one thing that comes to my mind is to use reflection here:

SomeClass someClass = new SomeClass
{
    SomeDate = DateTime.Now,
    FirstOptionalProperty = new List<int>(),
    //SecondOptionalProperty = new List<int>() // releasing this breakes the test
};

var info = typeof(SomeClass).GetProperties()
                            .SingleOrDefault(x =>
                                 x.PropertyType != typeof(DateTime) &&
                                 x.GetValue(someClass) != null);

basically if info is null then more than 1 of the optional properties was instantiated

over 4 years ago · Santiago Trujillo Report

0

I would use a helper function for this.

private static bool OnlyOneNotNull(params object[] properties) =>
    properties.Count(p => p is not null) == 1;

You would use it like this.

SomeClass s = new SomeClass();
/* ... */

if(!OnlyOneNotNull(s.FirstOptionalProperty, s.SecondOptionalProperty, s.ThirdOptionalProperty))
{
    /* handle error case */
}
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!