2

Can this only be done via a custom validator or is there anything I'm missing? Just want to make a simple check on an ICollection<string> property that it has at least one item.

Tried this with no luck:

 [Required]
 [MinLength(1, ErrorMessage = "At least one Something is required")]
 public ICollection<string> Somethings { get; set; }

Thanks!

Morten_564834
  • 1,479
  • 3
  • 15
  • 26

3 Answers3

2

This is a practical example of implementation:

class Program
{
    static void Main(string[] args)
    {
        var iceCream = new BuyIcecreamRequest { Tastes = new List<string>() { "Chocolate" } };
        var results = new List<ValidationResult>();
        bool isValid = Validator.TryValidateObject(iceCream, new ValidationContext(iceCream), results, true);
    }
}

public class MinimumCollectionLength : ValidationAttribute
{
    private readonly int _minimumCollectionLength;

    public MinimumCollectionLength(int minimumCollectionLength)
    {
        _minimumCollectionLength = minimumCollectionLength;
    }

    public override bool IsValid(object value)
    {
        var collection = value as ICollection;
        if (collection != null)
        {
            return collection.Count >= _minimumCollectionLength;
        }
        return false;
    }
}

public class BuyIcecreamRequest
{
    [Required]
    [MinimumCollectionLength(1, ErrorMessage = "At least one Taste is required")]
    public ICollection<string> Tastes { get; set; }
}
Marco Salerno
  • 5,131
  • 2
  • 12
  • 32
  • Thanks for answering Marco. I might switch to something like this with more options in the future if it becomes relevant. – Morten_564834 May 26 '20 at 16:57
1

One option could be to add an additional property to your model which calculates the length of the collection, and then validate against that:

public ICollection<string> Somethings { get; set; }

[Range(1, 9999, ErrorMessage = "At least one Something is required")]
public int SomethingsCount => Somethings == null ? 0 : Somethings.Count;

This seems messy as you're adding an extra property to your model, but if you are lazy then maybe its a good option for you.


A better option, as per the comment by Denis and this answer, you can define your own validation attribute

public class RequiredCollectionAttribute : ValidationAttribute
{
    public override bool IsValid(object value) => value is IList list && list.Count > 0;
}

And use it like this

[RequiredCollection(ErrorMessage = "At least one Something is required")]
public ICollection<string> Somethings { get; set; }
Bassie
  • 9,529
  • 8
  • 68
  • 159
  • I went with this one. Just wanted to make sure there wasn't any built-in method I missed, but this one is short and simple and what I need for now. Thanks Bassie – Morten_564834 May 26 '20 at 16:55
0

I've also provided another example for this...

public class NotNullOrEmptyCollectionAttribute : ValidationAttribute
{
    private readonly int _length;

    public NotNullOrEmptyCollectionAttribute(int length)
    {
        _length = length;
    }

    public NotNullOrEmptyCollectionAttribute()
    {
        _length = -1;
    }

    public override bool IsValid(object value)
    {
        return value switch
        {
            ICollection collection when _length > -1 => collection.Count >= _length,
            ICollection collection => collection.Count != 0,
            _ => value is IEnumerable enumerable && enumerable.GetEnumerator().MoveNext()
        };
    }
}

this can be used as

[NotNullOrEmptyCollection(1, ErrorMessage = "Please provide valid value for payment methods")]
public ICollection<PaymentMethod> PaymentMethods { get; set; }

or

[NotNullOrEmptyCollection]
public ICollection<PaymentMethod> PaymentMethods { get; set; }
Edi
  • 1,900
  • 18
  • 27