using System.ComponentModel.DataAnnotations.Resources;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
namespace System.ComponentModel.DataAnnotations {
///
/// Validation attribute to assert a string property, field or parameter does not exceed a maximum length
///
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
[SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")]
public class StringLengthAttribute : ValidationAttribute {
///
/// Gets the maximum acceptable length of the string
///
public int MaximumLength {
get;
private set;
}
///
/// Gets or sets the minimum acceptable length of the string
///
public int MinimumLength {
get;
set;
}
///
/// Constructor that accepts the maximum length of the string.
///
/// The maximum length, inclusive. It may not be negative.
public StringLengthAttribute(int maximumLength)
: base(() => DataAnnotationsResources.StringLengthAttribute_ValidationError) {
this.MaximumLength = maximumLength;
}
///
/// Override of
///
/// This method returns true if the is null.
/// It is assumed the is used if the value may not be null.
/// The value to test.
/// true if the value is null or less than or equal to the set maximum length
/// is thrown if the current attribute is ill-formed.
#if !SILVERLIGHT
public
#else
internal
#endif
override bool IsValid(object value) {
// Check the lengths for legality
this.EnsureLegalLengths();
// Automatically pass if value is null. RequiredAttribute should be used to assert a value is not null.
// We expect a cast exception if a non-string was passed in.
int length = value == null ? 0 : ((string)value).Length;
return value == null || (length >= this.MinimumLength && length <= this.MaximumLength);
}
///
/// Override of
///
/// The name to include in the formatted string
/// A localized string to describe the maximum acceptable length
/// is thrown if the current attribute is ill-formed.
public override string FormatErrorMessage(string name) {
this.EnsureLegalLengths();
bool useErrorMessageWithMinimum = this.MinimumLength != 0 && !this.CustomErrorMessageSet;
string errorMessage = useErrorMessageWithMinimum ?
DataAnnotationsResources.StringLengthAttribute_ValidationErrorIncludingMinimum : this.ErrorMessageString;
// it's ok to pass in the minLength even for the error message without a {2} param since String.Format will just
// ignore extra arguments
return String.Format(CultureInfo.CurrentCulture, errorMessage, name, this.MaximumLength, this.MinimumLength);
}
///
/// Checks that MinimumLength and MaximumLength have legal values. Throws InvalidOperationException if not.
///
private void EnsureLegalLengths() {
if (this.MaximumLength < 0) {
throw new InvalidOperationException(DataAnnotationsResources.StringLengthAttribute_InvalidMaxLength);
}
if (this.MaximumLength < this.MinimumLength) {
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.RangeAttribute_MinGreaterThanMax, this.MaximumLength, this.MinimumLength));
}
}
}
}