Basically, if I have a collection of objects, how can I apply a validation attribute to each item in the collection (such as MaxLengthAttribute
)?
public class Foo
{
public ICollection<string> Bars { get; set; }
}
For example, how can I ensure that Bars contains strings that validate against a max length of 256?
Update:
I understand how to apply a validation attribute on a single property, but the question is asking how to apply it on objects within a collection.
public class Foo
{
[StringLength(256)] // This is obvious
public string Bar { get; set; }
// How do you apply the necessary attribute to each object in the collection!
public ICollection<string> Bars { get; set; }
}
I know this question is kinda old, but maybe someone comes along looking for answers.
I'm not aware of a generic way to apply attributes to collection items, but for the specific string length example I used the following:
public class StringEnumerationLengthValidationAttribute : StringLengthAttribute
{
public StringEnumerationLengthValidationAttribute(int maximumLength)
: base(maximumLength)
{ }
public override bool RequiresValidationContext { get { return true; } }
public override bool IsValid(object value)
{ return false; }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var e1 = value as IEnumerable<string>;
if (e1 != null) return IsEnumerationValid(e1, validationContext);
return ValidationResult.Success; // what if applied to something else than IEnumerable<string> or it is null?
}
protected ValidationResult IsEnumerationValid(IEnumerable<string> coll, ValidationContext validationContext)
{
foreach (var item in coll)
{
// utilize the actual StringLengthAttribute to validate the items
if (!base.IsValid(item) || (MinimumLength > 0 && item == null))
{
return new ValidationResult(base.FormatErrorMessage(validationContext.DisplayName));
}
}
return ValidationResult.Success;
}
}
Apply as follows, to require 4-10 characters for each collection item:
[StringEnumerationLengthValidation(10, MinimumLength=4)]
public ICollection<string> Sample { get; set; }
OK I found a pretty nice article explaining some useful info about this:
http://blogs.msdn.com/b/codeanalysis/archive/2006/04/27/faq-why-does-donotexposegenericlists-recommend-that-i-expose-collection-lt-t-gt-instead-of-list-lt-t-gt-david-kean.aspx
Here is some suggested code that would make the Bars member of Foo do what you want.
public class Foo
{
public ValidatedStringCollection Bars = new ValidatedStringCollection(10);
}
public class ValidatedStringCollection : Collection<string>
{
int _maxStringLength;
public ValidatedStringCollection(int MaxStringLength)
{
_maxStringLength = MaxStringLength;
}
protected override void InsertItem(int index, string item)
{
if (item.Length > _maxStringLength)
{
throw new ArgumentException(String.Format("Length of string \"{0}\" is beyond the maximum of {1}.", item, _maxStringLength));
}
base.InsertItem(index, item);
}
}
class Program
{
static void Main(string[] args)
{
Foo x = new Foo();
x.Bars.Add("A");
x.Bars.Add("CCCCCDDDDD");
//x.Bars.Add("This string is longer than 10 and will throw an exception if uncommented.");
foreach (string item in x.Bars)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
The linked article has several suggestions including overriding the other methods on the collection, implementing events conditionally, etc. This should hopefully cover you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With