//
-// UIHintAttribute.cs
+// ValidationAttribute.cs
//
-// Author:
+// Authors:
// Atsushi Enomoto <atsushi@ximian.com>
+// Marek Habersack <mhabersack@novell.com>
//
-// Copyright (C) 2008 Novell Inc. http://novell.com
+// Copyright (C) 2008-2010 Novell Inc. http://novell.com
//
//
//
using System;
using System.ComponentModel;
+using System.Reflection;
namespace System.ComponentModel.DataAnnotations
{
public abstract class ValidationAttribute : Attribute
{
+ const string DEFAULT_ERROR_MESSAGE = "The field {0} is invalid.";
+#if !NET_4_0
+ string errorMessage;
+ string errorMessageResourceName;
+ string errorMessageString;
+ Type errorMessageResourceType;
+#endif
+ string fallbackErrorMessage;
+ Func <string> errorMessageAccessor;
+
protected ValidationAttribute ()
- : this ("This member is required")
{
}
- [MonoTODO]
protected ValidationAttribute (Func<string> errorMessageAccessor)
{
- throw new NotImplementedException ();
+ this.errorMessageAccessor = errorMessageAccessor;
}
protected ValidationAttribute (string errorMessage)
{
- ErrorMessage = errorMessage;
+ fallbackErrorMessage = errorMessage;
}
- [MonoTODO]
public virtual string FormatErrorMessage (string name)
{
- throw new NotImplementedException ();
+ return String.Format (ErrorMessageString, name);
}
-
+#if NET_4_0
public string ErrorMessage { get; set; }
public string ErrorMessageResourceName { get; set; }
public Type ErrorMessageResourceType { get; set; }
- protected string ErrorMessageString { get; private set; }
+#else
+ public string ErrorMessage {
+ get { return errorMessage; }
+
+ set {
+ if (errorMessage != null)
+ throw new InvalidOperationException ("This property can be set only once.");
+
+ if (String.IsNullOrEmpty (value))
+ throw new ArgumentException ("Value cannot be null or empty.", "value");
+
+ if (errorMessageResourceName != null || errorMessageResourceType != null)
+ throw new InvalidOperationException ("This property cannot be set because the attribute is already in the resource mode.");
+
+ errorMessage = value;
+ }
+ }
+
+ public string ErrorMessageResourceName {
+ get { return errorMessageResourceName; }
+
+ set {
+ if (errorMessageResourceName != null)
+ throw new InvalidOperationException ("This property can be set only once.");
+ if (String.IsNullOrEmpty (value))
+ throw new ArgumentException ("Value cannot be null or empty.", "value");
+
+ errorMessageResourceName = value;
+ if (errorMessageResourceType != null)
+ errorMessageString = GetStringFromResourceAccessor ();
+ }
+ }
+
+ public Type ErrorMessageResourceType {
+ get { return errorMessageResourceType; }
+ set {
+ errorMessageResourceType = value;
+ if (!String.IsNullOrEmpty (errorMessageResourceName))
+ errorMessageString = GetStringFromResourceAccessor ();
+ }
+ }
+#endif
+ protected string ErrorMessageString {
+ get {
+#if NET_4_0
+ return GetStringFromResourceAccessor ();
+#else
+ return errorMessageString;
+#endif
+ }
+ }
+#if NET_4_0
+ public virtual bool IsValid (object value)
+ {
+ throw new NotImplementedException ("IsValid(object value) has not been implemented by this class. The preferred entry point is GetValidationResult() and classes should override IsValid(object value, ValidationContext context).");
+ }
+
+ protected virtual ValidationResult IsValid (object value, ValidationContext validationContext)
+ {
+ // .NET emulation
+ if (validationContext == null)
+ throw new NullReferenceException (".NET emulation.");
+
+ if (!IsValid (value)) {
+ string memberName = validationContext.MemberName;
+ return new ValidationResult (FormatErrorMessage (validationContext.DisplayName), memberName != null ? new string[] { memberName } : new string[] {});
+ }
+
+ return ValidationResult.Success;
+ }
+#else
public abstract bool IsValid (object value);
+#endif
+
+#if NET_4_0
+ public ValidationResult GetValidationResult (object value, ValidationContext validationContext)
+ {
+ if (validationContext == null)
+ throw new ArgumentNullException ("validationContext");
+
+ ValidationResult ret = IsValid (value, validationContext);
+ if (ret != null && String.IsNullOrEmpty (ret.ErrorMessage))
+ ret.ErrorMessage = FormatErrorMessage (validationContext.DisplayName);
+
+ return ret;
+ }
+#endif
+ string GetStringFromResourceAccessor ()
+ {
+ string resourceName = ErrorMessageResourceName;
+ Type resourceType = ErrorMessageResourceType;
+ string errorMessage = ErrorMessage;
- [MonoTODO]
+ if (resourceName != null && errorMessage != null)
+ throw new InvalidOperationException ("Either ErrorMessage or ErrorMessageResourceName must be set, but not both.");
+
+ if (resourceType == null ^ resourceName == null)
+ throw new InvalidOperationException ("Both ErrorMessageResourceType and ErrorMessageResourceName must be set on this attribute.");
+
+ if (errorMessageAccessor != null)
+ return errorMessageAccessor ();
+
+ if (resourceType != null) {
+ PropertyInfo pi = resourceType.GetProperty (resourceName, BindingFlags.Public | BindingFlags.Static);
+ if (pi == null || !pi.CanRead)
+ throw new InvalidOperationException (
+ String.Format ("Resource type '{0}' does not have an accessible static property named '{1}'.",
+ resourceType, resourceName)
+ );
+
+ if (pi.PropertyType != typeof (string))
+ throw new InvalidOperationException (
+ String.Format ("The property '{0}' on resource type '{1}' is not a string type.",
+ resourceName, resourceType)
+ );
+
+ return pi.GetValue (null, null) as string;
+ }
+
+ if (errorMessage == null)
+ if (fallbackErrorMessage != null)
+ return fallbackErrorMessage;
+ else
+ return DEFAULT_ERROR_MESSAGE;
+
+ return errorMessage;
+ }
+#if NET_4_0
+ public void Validate (object value, ValidationContext validationContext)
+ {
+ if (validationContext == null)
+ throw new ArgumentNullException ("validationContext");
+
+ ValidationResult result = IsValid (value, validationContext);
+ if (result != null) {
+ string message = result.ErrorMessage;
+ if (message == null)
+ message = FormatErrorMessage (validationContext.DisplayName);
+
+ throw new ValidationException (message, this, value);
+ }
+ }
+#endif
public void Validate (object value, string name)
{
- throw new NotImplementedException ();
+ if (!IsValid (value))
+ throw new ValidationException (FormatErrorMessage (name), this, value);
}
}
}