Commit for development environment setup
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Csla.Validation
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores details about a specific broken business rule.
|
||||
/// </summary>
|
||||
[Serializable()]
|
||||
public class BrokenRule
|
||||
{
|
||||
private string _ruleName;
|
||||
private string _description;
|
||||
private string _property;
|
||||
private RuleSeverity _severity;
|
||||
|
||||
internal BrokenRule(IRuleMethod rule)
|
||||
{
|
||||
_ruleName = rule.RuleName;
|
||||
_description = rule.RuleArgs.Description;
|
||||
_property = rule.RuleArgs.PropertyName;
|
||||
_severity = rule.RuleArgs.Severity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to the name of the broken rule.
|
||||
/// </summary>
|
||||
/// <value>The name of the rule.</value>
|
||||
public string RuleName
|
||||
{
|
||||
get { return _ruleName; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to the description of the broken rule.
|
||||
/// </summary>
|
||||
/// <value>The description of the rule.</value>
|
||||
public string Description
|
||||
{
|
||||
get { return _description; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to the property affected by the broken rule.
|
||||
/// </summary>
|
||||
/// <value>The property affected by the rule.</value>
|
||||
public string Property
|
||||
{
|
||||
get { return _property; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the severity of the broken rule.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
/// <returns></returns>
|
||||
/// <remarks></remarks>
|
||||
public RuleSeverity Severity
|
||||
{
|
||||
get { return _severity; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,255 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Csla.Validation
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of currently broken rules.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This collection is readonly and can be safely made available
|
||||
/// to code outside the business object such as the UI. This allows
|
||||
/// external code, such as a UI, to display the list of broken rules
|
||||
/// to the user.
|
||||
/// </remarks>
|
||||
[Serializable()]
|
||||
public class BrokenRulesCollection : Core.ReadOnlyBindingList<BrokenRule>
|
||||
{
|
||||
|
||||
private int _errorCount;
|
||||
private int _warningCount;
|
||||
private int _infoCount;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of broken rules in
|
||||
/// the collection that have a severity
|
||||
/// of Error.
|
||||
/// </summary>
|
||||
/// <value>An integer value.</value>
|
||||
public int ErrorCount
|
||||
{
|
||||
get { return _errorCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of broken rules in
|
||||
/// the collection that have a severity
|
||||
/// of Warning.
|
||||
/// </summary>
|
||||
/// <value>An integer value.</value>
|
||||
public int WarningCount
|
||||
{
|
||||
get { return _warningCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of broken rules in
|
||||
/// the collection that have a severity
|
||||
/// of Information.
|
||||
/// </summary>
|
||||
/// <value>An integer value.</value>
|
||||
public int InformationCount
|
||||
{
|
||||
get { return _infoCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first <see cref="BrokenRule" /> object
|
||||
/// corresponding to the specified property.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Code in a business object or UI can also use this value to retrieve
|
||||
/// the first broken rule in <see cref="BrokenRulesCollection" /> that corresponds
|
||||
/// to a specfic property on the object.
|
||||
/// </remarks>
|
||||
/// <param name="property">The name of the property affected by the rule.</param>
|
||||
/// <returns>
|
||||
/// The first BrokenRule object corresponding to the specified property, or null if
|
||||
/// there are no rules defined for the property.
|
||||
/// </returns>
|
||||
public BrokenRule GetFirstBrokenRule(string property)
|
||||
{
|
||||
return GetFirstMessage(property, RuleSeverity.Error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first <see cref="BrokenRule" /> object
|
||||
/// corresponding to the specified property.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Code in a business object or UI can also use this value to retrieve
|
||||
/// the first broken rule in <see cref="BrokenRulesCollection" /> that corresponds
|
||||
/// to a specfic property.
|
||||
/// </remarks>
|
||||
/// <param name="property">The name of the property affected by the rule.</param>
|
||||
/// <returns>
|
||||
/// The first BrokenRule object corresponding to the specified property, or Nothing
|
||||
/// (null in C#) if there are no rules defined for the property.
|
||||
/// </returns>
|
||||
public BrokenRule GetFirstMessage(string property)
|
||||
{
|
||||
foreach (BrokenRule item in this)
|
||||
if (item.Property == property)
|
||||
return item;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first <see cref="BrokenRule"/> object
|
||||
/// corresponding to the specified property
|
||||
/// and severity.
|
||||
/// </summary>
|
||||
/// <param name="property">The name of the property affected by the rule.</param>
|
||||
/// <param name="severity">The severity of broken rule to return.</param>
|
||||
/// <returns>
|
||||
/// The first BrokenRule object corresponding to the specified property, or Nothing
|
||||
/// (null in C#) if there are no rules defined for the property.
|
||||
/// </returns>
|
||||
public BrokenRule GetFirstMessage(string property, RuleSeverity severity)
|
||||
{
|
||||
foreach (BrokenRule item in this)
|
||||
if (item.Property == property && item.Severity == severity)
|
||||
return item;
|
||||
return null;
|
||||
}
|
||||
|
||||
internal BrokenRulesCollection()
|
||||
{
|
||||
// limit creation to this assembly
|
||||
}
|
||||
|
||||
internal void Add(IRuleMethod rule)
|
||||
{
|
||||
Remove(rule);
|
||||
IsReadOnly = false;
|
||||
BrokenRule item = new BrokenRule(rule);
|
||||
IncrementCount(item);
|
||||
Add(item);
|
||||
IsReadOnly = true;
|
||||
}
|
||||
|
||||
internal void Remove(IRuleMethod rule)
|
||||
{
|
||||
// we loop through using a numeric counter because
|
||||
// removing items within a foreach isn't reliable
|
||||
IsReadOnly = false;
|
||||
for (int index = 0; index < Count; index++)
|
||||
if (this[index].RuleName == rule.RuleName)
|
||||
{
|
||||
DecrementCount(this[index]);
|
||||
RemoveAt(index);
|
||||
break;
|
||||
}
|
||||
IsReadOnly = true;
|
||||
}
|
||||
|
||||
private void IncrementCount(BrokenRule item)
|
||||
{
|
||||
switch (item.Severity)
|
||||
{
|
||||
case RuleSeverity.Error:
|
||||
_errorCount += 1;
|
||||
break;
|
||||
case RuleSeverity.Warning:
|
||||
_warningCount += 1;
|
||||
break;
|
||||
case RuleSeverity.Information:
|
||||
_infoCount += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void DecrementCount(BrokenRule item)
|
||||
{
|
||||
switch (item.Severity)
|
||||
{
|
||||
case RuleSeverity.Error:
|
||||
_errorCount -= 1;
|
||||
break;
|
||||
case RuleSeverity.Warning:
|
||||
_warningCount -= 1;
|
||||
break;
|
||||
case RuleSeverity.Information:
|
||||
_infoCount -= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the text of all broken rule descriptions, each
|
||||
/// separated by a <see cref="Environment.NewLine" />.
|
||||
/// </summary>
|
||||
/// <returns>The text of all broken rule descriptions.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
System.Text.StringBuilder result = new System.Text.StringBuilder();
|
||||
bool first = true;
|
||||
foreach (BrokenRule item in this)
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
result.Append(Environment.NewLine);
|
||||
result.Append(item.Description);
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the text of all broken rule descriptions, each
|
||||
/// separated by a <see cref="Environment.NewLine" />.
|
||||
/// </summary>
|
||||
/// <param name="severity">The severity of rules to
|
||||
/// include in the result.</param>
|
||||
/// <returns>The text of all broken rule descriptions
|
||||
/// matching the specified severtiy.</returns>
|
||||
public string ToString(RuleSeverity severity)
|
||||
{
|
||||
System.Text.StringBuilder result = new System.Text.StringBuilder();
|
||||
bool first = true;
|
||||
foreach (BrokenRule item in this)
|
||||
{
|
||||
if (item.Severity == severity)
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
result.Append(Environment.NewLine);
|
||||
result.Append(item.Description);
|
||||
}
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string array containing all broken
|
||||
/// rule descriptions.
|
||||
/// </summary>
|
||||
/// <returns>The text of all broken rule descriptions
|
||||
/// matching the specified severtiy.</returns>
|
||||
public string[] ToArray()
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
foreach (BrokenRule item in this)
|
||||
result.Add(item.Description);
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string array containing all broken
|
||||
/// rule descriptions.
|
||||
/// </summary>
|
||||
/// <param name="severity">The severity of rules
|
||||
/// to include in the result.</param>
|
||||
/// <returns>The text of all broken rule descriptions
|
||||
/// matching the specified severtiy.</returns>
|
||||
public string[] ToArray(RuleSeverity severity)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
foreach (BrokenRule item in this)
|
||||
if (item.Severity == severity)
|
||||
result.Add(item.Description);
|
||||
return result.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,491 @@
|
||||
using System;
|
||||
using Csla.Properties;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Csla.Validation
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements common business rules.
|
||||
/// </summary>
|
||||
public static class CommonRules
|
||||
{
|
||||
|
||||
#region StringRequired
|
||||
|
||||
/// <summary>
|
||||
/// Rule ensuring a string value contains one or more
|
||||
/// characters.
|
||||
/// </summary>
|
||||
/// <param name="target">Object containing the data to validate</param>
|
||||
/// <param name="e">Arguments parameter specifying the name of the string
|
||||
/// property to validate</param>
|
||||
/// <returns><see langword="false" /> if the rule is broken</returns>
|
||||
/// <remarks>
|
||||
/// This implementation uses late binding, and will only work
|
||||
/// against string property values.
|
||||
/// </remarks>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
|
||||
public static bool StringRequired(object target, RuleArgs e)
|
||||
{
|
||||
string value = (string)Utilities.CallByName(
|
||||
target, e.PropertyName, CallType.Get);
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
e.Description = string.Format(Resources.StringRequiredRule, e.PropertyName);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region StringMaxLength
|
||||
|
||||
/// <summary>
|
||||
/// Rule ensuring a string value doesn't exceed
|
||||
/// a specified length.
|
||||
/// </summary>
|
||||
/// <param name="target">Object containing the data to validate</param>
|
||||
/// <param name="e">Arguments parameter specifying the name of the string
|
||||
/// property to validate</param>
|
||||
/// <returns><see langword="false" /> if the rule is broken</returns>
|
||||
/// <remarks>
|
||||
/// This implementation uses late binding, and will only work
|
||||
/// against string property values.
|
||||
/// </remarks>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
|
||||
public static bool StringMaxLength(
|
||||
object target, RuleArgs e)
|
||||
{
|
||||
int max = ((MaxLengthRuleArgs)e).MaxLength;
|
||||
string value = (string)Utilities.CallByName(
|
||||
target, e.PropertyName, CallType.Get);
|
||||
if (!String.IsNullOrEmpty(value) && (value.Length > max))
|
||||
{
|
||||
e.Description = String.Format(
|
||||
Resources.StringMaxLengthRule,
|
||||
e.PropertyName, max.ToString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom <see cref="RuleArgs" /> object required by the
|
||||
/// <see cref="StringMaxLength" /> rule method.
|
||||
/// </summary>
|
||||
public class MaxLengthRuleArgs : RuleArgs
|
||||
{
|
||||
private int _maxLength;
|
||||
|
||||
/// <summary>
|
||||
/// Get the max length for the string.
|
||||
/// </summary>
|
||||
public int MaxLength
|
||||
{
|
||||
get { return _maxLength; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new object.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property to validate.</param>
|
||||
/// <param name="maxLength">Max length of characters allowed.</param>
|
||||
public MaxLengthRuleArgs(
|
||||
string propertyName, int maxLength)
|
||||
: base(propertyName)
|
||||
{
|
||||
_maxLength = maxLength;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a string representation of the object.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return base.ToString() + "?maxLength=" + _maxLength.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IntegerMaxValue
|
||||
|
||||
/// <summary>
|
||||
/// Rule ensuring an integer value doesn't exceed
|
||||
/// a specified value.
|
||||
/// </summary>
|
||||
/// <param name="target">Object containing the data to validate.</param>
|
||||
/// <param name="e">Arguments parameter specifying the name of the
|
||||
/// property to validate.</param>
|
||||
/// <returns><see langword="false"/> if the rule is broken.</returns>
|
||||
public static bool IntegerMaxValue(object target, RuleArgs e)
|
||||
{
|
||||
int max = ((IntegerMaxValueRuleArgs)e).MaxValue;
|
||||
int value = (int)Utilities.CallByName(target, e.PropertyName, CallType.Get);
|
||||
if (value > max)
|
||||
{
|
||||
e.Description = String.Format(Resources.MaxValueRule,
|
||||
e.PropertyName, max.ToString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom <see cref="RuleArgs" /> object required by the
|
||||
/// <see cref="IntegerMaxValue" /> rule method.
|
||||
/// </summary>
|
||||
public class IntegerMaxValueRuleArgs : RuleArgs
|
||||
{
|
||||
private int _maxValue;
|
||||
|
||||
/// <summary>
|
||||
/// Get the max value for the property.
|
||||
/// </summary>
|
||||
public int MaxValue
|
||||
{
|
||||
get { return _maxValue; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new object.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property.</param>
|
||||
/// <param name="maxValue">Maximum allowed value for the property.</param>
|
||||
public IntegerMaxValueRuleArgs(string propertyName, int maxValue)
|
||||
: base(propertyName)
|
||||
{
|
||||
_maxValue = maxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a string representation of the object.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return base.ToString() + "?maxValue=" + _maxValue.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IntegerMinValue
|
||||
|
||||
/// <summary>
|
||||
/// Rule ensuring an integer value doesn't go below
|
||||
/// a specified value.
|
||||
/// </summary>
|
||||
/// <param name="target">Object containing the data to validate.</param>
|
||||
/// <param name="e">Arguments parameter specifying the name of the
|
||||
/// property to validate.</param>
|
||||
/// <returns><see langword="false"/> if the rule is broken.</returns>
|
||||
public static bool IntegerMinValue(object target, RuleArgs e)
|
||||
{
|
||||
int min = ((IntegerMinValueRuleArgs)e).MinValue;
|
||||
int value = (int)Utilities.CallByName(target, e.PropertyName, CallType.Get);
|
||||
if (value < min)
|
||||
{
|
||||
e.Description = String.Format(Resources.MinValueRule,
|
||||
e.PropertyName, min.ToString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom <see cref="RuleArgs" /> object required by the
|
||||
/// <see cref="IntegerMinValue" /> rule method.
|
||||
/// </summary>
|
||||
public class IntegerMinValueRuleArgs : RuleArgs
|
||||
{
|
||||
private int _minValue;
|
||||
|
||||
/// <summary>
|
||||
/// Get the min value for the property.
|
||||
/// </summary>
|
||||
public int MinValue
|
||||
{
|
||||
get { return _minValue; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new object.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property.</param>
|
||||
/// <param name="minValue">Minimum allowed value for the property.</param>
|
||||
public IntegerMinValueRuleArgs(string propertyName, int minValue)
|
||||
: base(propertyName)
|
||||
{
|
||||
_minValue = minValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a string representation of the object.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return base.ToString() + "?minValue=" + _minValue.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MaxValue
|
||||
|
||||
/// <summary>
|
||||
/// Rule ensuring that a numeric value
|
||||
/// doesn't exceed a specified maximum.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the property to validate.</typeparam>
|
||||
/// <param name="target">Object containing value to validate.</param>
|
||||
/// <param name="e">Arguments variable specifying the
|
||||
/// name of the property to validate, along with the max
|
||||
/// allowed value.</param>
|
||||
public static bool MaxValue<T>(object target, RuleArgs e) where T : IComparable
|
||||
{
|
||||
PropertyInfo pi = target.GetType().GetProperty(e.PropertyName);
|
||||
T value = (T)pi.GetValue(target, null);
|
||||
T max = ((MaxValueRuleArgs<T>)e).MaxValue;
|
||||
|
||||
int result = value.CompareTo(max);
|
||||
if (result >= 1)
|
||||
{
|
||||
e.Description = string.Format(Resources.MaxValueRule,
|
||||
e.PropertyName, max.ToString());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom <see cref="RuleArgs" /> object required by the
|
||||
/// <see cref="MaxValue" /> rule method.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the property to validate.</typeparam>
|
||||
public class MaxValueRuleArgs<T> : RuleArgs
|
||||
{
|
||||
T _maxValue = default(T);
|
||||
|
||||
/// <summary>
|
||||
/// Get the max value for the property.
|
||||
/// </summary>
|
||||
public T MaxValue
|
||||
{
|
||||
get { return _maxValue; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new object.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property.</param>
|
||||
/// <param name="maxValue">Maximum allowed value for the property.</param>
|
||||
public MaxValueRuleArgs(string propertyName, T maxValue)
|
||||
: base(propertyName)
|
||||
{
|
||||
_maxValue = maxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representation of the object.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return base.ToString() + "?maxValue=" + _maxValue.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MinValue
|
||||
|
||||
/// <summary>
|
||||
/// Rule ensuring that a numeric value
|
||||
/// doesn't exceed a specified minimum.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the property to validate.</typeparam>
|
||||
/// <param name="target">Object containing value to validate.</param>
|
||||
/// <param name="e">Arguments variable specifying the
|
||||
/// name of the property to validate, along with the min
|
||||
/// allowed value.</param>
|
||||
public static bool MinValue<T>(object target, RuleArgs e) where T : IComparable
|
||||
{
|
||||
PropertyInfo pi = target.GetType().GetProperty(e.PropertyName);
|
||||
T value = (T)pi.GetValue(target, null);
|
||||
T min = ((MinValueRuleArgs<T>)e).MinValue;
|
||||
|
||||
int result = value.CompareTo(min);
|
||||
if (result <= -1)
|
||||
{
|
||||
e.Description = string.Format(Resources.MinValueRule,
|
||||
e.PropertyName, min.ToString());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom <see cref="RuleArgs" /> object required by the
|
||||
/// <see cref="MinValue" /> rule method.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the property to validate.</typeparam>
|
||||
public class MinValueRuleArgs<T> : RuleArgs
|
||||
{
|
||||
T _minValue = default(T);
|
||||
|
||||
/// <summary>
|
||||
/// Get the min value for the property.
|
||||
/// </summary>
|
||||
public T MinValue
|
||||
{
|
||||
get { return _minValue; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new object.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property.</param>
|
||||
/// <param name="minValue">Minimum allowed value for the property.</param>
|
||||
public MinValueRuleArgs(string propertyName, T minValue)
|
||||
: base(propertyName)
|
||||
{
|
||||
_minValue = minValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representation of the object.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return base.ToString() + "?minValue=" + _minValue.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RegEx
|
||||
|
||||
/// <summary>
|
||||
/// Rule that checks to make sure a value
|
||||
/// matches a given regex pattern.
|
||||
/// </summary>
|
||||
/// <param name="target">Object containing the data to validate</param>
|
||||
/// <param name="e">RegExRuleArgs parameter specifying the name of the
|
||||
/// property to validate and the regex pattern.</param>
|
||||
/// <returns>False if the rule is broken</returns>
|
||||
/// <remarks>
|
||||
/// This implementation uses late binding.
|
||||
/// </remarks>
|
||||
public static bool RegExMatch(object target, RuleArgs e)
|
||||
{
|
||||
Regex rx = ((RegExRuleArgs)e).RegEx;
|
||||
if (!rx.IsMatch(Utilities.CallByName(target, e.PropertyName, CallType.Get).ToString()))
|
||||
{
|
||||
e.Description = String.Format(Resources.RegExMatchRule, e.PropertyName);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of built-in regex patterns.
|
||||
/// </summary>
|
||||
public enum RegExPatterns
|
||||
{
|
||||
/// <summary>
|
||||
/// US Social Security number pattern.
|
||||
/// </summary>
|
||||
SSN,
|
||||
/// <summary>
|
||||
/// Email address pattern.
|
||||
/// </summary>
|
||||
Email
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom <see cref="RuleArgs" /> object required by the
|
||||
/// <see cref="RegExMatch" /> rule method.
|
||||
/// </summary>
|
||||
public class RegExRuleArgs : RuleArgs
|
||||
{
|
||||
Regex _regEx;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="RegEx"/> object used to validate
|
||||
/// the property.
|
||||
/// </summary>
|
||||
public Regex RegEx
|
||||
{
|
||||
get { return _regEx; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new object.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property to validate.</param>
|
||||
/// <param name="pattern">Built-in regex pattern to use.</param>
|
||||
public RegExRuleArgs(string propertyName, RegExPatterns pattern)
|
||||
:
|
||||
base(propertyName)
|
||||
{
|
||||
_regEx = new Regex(GetPattern(pattern));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new object.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property to validate.</param>
|
||||
/// <param name="pattern">Custom regex pattern to use.</param>
|
||||
public RegExRuleArgs(string propertyName, string pattern)
|
||||
:
|
||||
base(propertyName)
|
||||
{
|
||||
_regEx = new Regex(pattern);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new object.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property to validate.</param>
|
||||
/// <param name="regEx"><see cref="RegEx"/> object to use.</param>
|
||||
public RegExRuleArgs(string propertyName, System.Text.RegularExpressions.Regex regEx)
|
||||
:
|
||||
base(propertyName)
|
||||
{
|
||||
_regEx = regEx;
|
||||
}
|
||||
|
||||
/// <summary>f
|
||||
/// Returns a string representation of the object.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return base.ToString() + "?regex=" + _regEx.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the specified built-in regex pattern.
|
||||
/// </summary>
|
||||
/// <param name="pattern">Pattern to return.</param>
|
||||
public static string GetPattern(RegExPatterns pattern)
|
||||
{
|
||||
switch (pattern)
|
||||
{
|
||||
case RegExPatterns.SSN:
|
||||
return @"^\d{3}-\d{2}-\d{4}$";
|
||||
case RegExPatterns.Email:
|
||||
return @"^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$";
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
|
||||
namespace Csla.Validation
|
||||
{
|
||||
/// <summary>
|
||||
/// Tracks all information for a rule.
|
||||
/// </summary>
|
||||
internal interface IRuleMethod
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the priority of the rule method.
|
||||
/// </summary>
|
||||
/// <value>The priority value.</value>
|
||||
/// <remarks>
|
||||
/// Priorities are processed in descending
|
||||
/// order, so priority 0 is processed
|
||||
/// before priority 1, etc.</remarks>
|
||||
int Priority { get;}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the rule.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The rule's name must be unique and is used
|
||||
/// to identify a broken rule in the BrokenRules
|
||||
/// collection.
|
||||
/// </remarks>
|
||||
string RuleName { get;}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of the field, property or column
|
||||
/// to which the rule applies.
|
||||
/// </summary>
|
||||
RuleArgs RuleArgs { get;}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the rule to validate the data.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the data is valid,
|
||||
/// <see langword="false" /> if the data is invalid.
|
||||
/// </returns>
|
||||
bool Invoke(object target);
|
||||
}
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
|
||||
namespace Csla.Validation
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Object providing extra information to methods that
|
||||
/// implement business rules.
|
||||
/// </summary>
|
||||
public class RuleArgs
|
||||
{
|
||||
private string _propertyName;
|
||||
private string _description;
|
||||
private RuleSeverity _severity = RuleSeverity.Error;
|
||||
private bool _stopProcessing;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the property to be validated.
|
||||
/// </summary>
|
||||
public string PropertyName
|
||||
{
|
||||
get { return _propertyName; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set by the rule handler method to describe the broken
|
||||
/// rule.
|
||||
/// </summary>
|
||||
/// <value>A human-readable description of
|
||||
/// the broken rule.</value>
|
||||
/// <remarks>
|
||||
/// Setting this property only has an effect if
|
||||
/// the rule method returns <see langword="false" />.
|
||||
/// </remarks>
|
||||
public string Description
|
||||
{
|
||||
get { return _description; }
|
||||
set { _description = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the severity of the broken rule.
|
||||
/// </summary>
|
||||
/// <value>The severity of the broken rule.</value>
|
||||
/// <remarks>
|
||||
/// Setting this property only has an effect if
|
||||
/// the rule method returns <see langword="false" />.
|
||||
/// </remarks>
|
||||
public RuleSeverity Severity
|
||||
{
|
||||
get { return _severity; }
|
||||
set { _severity = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this
|
||||
/// broken rule should stop the processing of subsequent
|
||||
/// rules for this property.
|
||||
/// </summary>
|
||||
/// <value><see langword="true" /> if no further
|
||||
/// rules should be process for this property.</value>
|
||||
/// <remarks>
|
||||
/// Setting this property only has an effect if
|
||||
/// the rule method returns <see langword="false" />.
|
||||
/// </remarks>
|
||||
public bool StopProcessing
|
||||
{
|
||||
get { return _stopProcessing; }
|
||||
set { _stopProcessing = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of RuleArgs.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">The name of the property to be validated.</param>
|
||||
public RuleArgs(string propertyName)
|
||||
{
|
||||
_propertyName = propertyName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a string representation of the object.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return _propertyName;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
|
||||
namespace Csla.Validation
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Delegate that defines the method signature for all rule handler methods.
|
||||
/// </summary>
|
||||
/// <param name="target">
|
||||
/// Object containing the data to be validated.
|
||||
/// </param>
|
||||
/// <param name="e">
|
||||
/// Parameter used to pass information to and from
|
||||
/// the rule method.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the rule was satisfied.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// When implementing a rule handler, you must conform to the method signature
|
||||
/// defined by this delegate. You should also apply the Description attribute
|
||||
/// to your method to provide a meaningful description for your rule.
|
||||
/// </para><para>
|
||||
/// The method implementing the rule must return
|
||||
/// <see langword="true"/> if the data is valid and
|
||||
/// return <see langword="false"/> if the data is invalid.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public delegate bool RuleHandler(object target, RuleArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Delegate that defines the method signature for all rule handler methods.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the target object.</typeparam>
|
||||
/// <typeparam name="R">Type of the arguments parameter.</typeparam>
|
||||
/// <param name="target">
|
||||
/// Object containing the data to be validated.
|
||||
/// </param>
|
||||
/// <param name="e">
|
||||
/// Parameter used to pass information to and from
|
||||
/// the rule method.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the rule was satisfied.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// When implementing a rule handler, you must conform to the method signature
|
||||
/// defined by this delegate. You should also apply the Description attribute
|
||||
/// to your method to provide a meaningful description for your rule.
|
||||
/// </para><para>
|
||||
/// The method implementing the rule must return
|
||||
/// <see langword="true"/> if the data is valid and
|
||||
/// return <see langword="false"/> if the data is invalid.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public delegate bool RuleHandler<T, R>(T target, R e) where R : RuleArgs;
|
||||
|
||||
}
|
@@ -0,0 +1,247 @@
|
||||
using System;
|
||||
|
||||
namespace Csla.Validation
|
||||
{
|
||||
/// <summary>
|
||||
/// Tracks all information for a rule.
|
||||
/// </summary>
|
||||
internal class RuleMethod : IRuleMethod, IComparable, IComparable<IRuleMethod>
|
||||
{
|
||||
private RuleHandler _handler;
|
||||
private string _ruleName = String.Empty;
|
||||
private RuleArgs _args;
|
||||
private int _priority;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of the method implementing the rule
|
||||
/// and the property, field or column name to which the
|
||||
/// rule applies.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return _ruleName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the priority of the rule method.
|
||||
/// </summary>
|
||||
/// <value>The priority value</value>
|
||||
/// <remarks>
|
||||
/// Priorities are processed in descending
|
||||
/// order, so priority 0 is processed
|
||||
/// before priority 1, etc.
|
||||
/// </remarks>
|
||||
public int Priority
|
||||
{
|
||||
get { return _priority; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the rule.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The rule's name must be unique and is used
|
||||
/// to identify a broken rule in the BrokenRules
|
||||
/// collection.
|
||||
/// </remarks>
|
||||
public string RuleName
|
||||
{
|
||||
get { return _ruleName; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of the field, property or column
|
||||
/// to which the rule applies.
|
||||
/// </summary>
|
||||
public RuleArgs RuleArgs
|
||||
{
|
||||
get { return _args; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and initializes the rule.
|
||||
/// </summary>
|
||||
/// <param name="handler">The address of the method implementing the rule.</param>
|
||||
/// <param name="args">A RuleArgs object.</param>
|
||||
public RuleMethod(RuleHandler handler, RuleArgs args)
|
||||
{
|
||||
_handler = handler;
|
||||
_args = args;
|
||||
_ruleName = string.Format(@"rule://{0}/{1}", _handler.Method.Name, _args.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and initializes the rule.
|
||||
/// </summary>
|
||||
/// <param name="handler">The address of the method implementing the rule.</param>
|
||||
/// <param name="args">A RuleArgs object.</param>
|
||||
/// <param name="priority">
|
||||
/// Priority for processing the rule (smaller numbers have higher priority, default=0).
|
||||
/// </param>
|
||||
public RuleMethod(RuleHandler handler, RuleArgs args, int priority)
|
||||
: this(handler, args)
|
||||
{
|
||||
_priority = priority;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the rule to validate the data.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the data is valid,
|
||||
/// <see langword="false" /> if the data is invalid.
|
||||
/// </returns>
|
||||
public bool Invoke(object target)
|
||||
{
|
||||
return _handler.Invoke(target, _args);
|
||||
}
|
||||
|
||||
#region IComparable
|
||||
|
||||
int IComparable.CompareTo(object obj)
|
||||
{
|
||||
return Priority.CompareTo(((IRuleMethod)obj).Priority);
|
||||
}
|
||||
|
||||
int IComparable<IRuleMethod>.CompareTo(IRuleMethod other)
|
||||
{
|
||||
return Priority.CompareTo(other.Priority);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Tracks all information for a rule.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the target object.</typeparam>
|
||||
/// <typeparam name="R">Type of the arguments parameter.</typeparam>
|
||||
internal class RuleMethod<T, R>
|
||||
: IRuleMethod, IComparable, IComparable<IRuleMethod>
|
||||
where R : RuleArgs
|
||||
{
|
||||
private RuleHandler<T, R> _handler;
|
||||
private string _ruleName = string.Empty;
|
||||
private R _args;
|
||||
private int _priority;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of the method implementing the rule
|
||||
/// and the property, field or column name to which the
|
||||
/// rule applies.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return _ruleName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the priority of the rule method.
|
||||
/// </summary>
|
||||
/// <value>The priority value</value>
|
||||
/// <remarks>
|
||||
/// Priorities are processed in descending
|
||||
/// order, so priority 0 is processed
|
||||
/// before priority 1, etc.
|
||||
/// </remarks>
|
||||
public int Priority
|
||||
{
|
||||
get { return _priority; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the rule.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The rule's name must be unique and is used
|
||||
/// to identify a broken rule in the BrokenRules
|
||||
/// collection.
|
||||
/// </remarks>
|
||||
public string RuleName
|
||||
{
|
||||
get {return _ruleName;}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of the field, property or column
|
||||
/// to which the rule applies.
|
||||
/// </summary>
|
||||
RuleArgs IRuleMethod.RuleArgs
|
||||
{
|
||||
get {return this.RuleArgs;}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of the field, property or column
|
||||
/// to which the rule applies.
|
||||
/// </summary>
|
||||
public R RuleArgs
|
||||
{
|
||||
get { return _args; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and initializes the rule.
|
||||
/// </summary>
|
||||
/// <param name="handler">The address of the method implementing the rule.</param>
|
||||
/// <param name="args">A RuleArgs object.</param>
|
||||
public RuleMethod(RuleHandler<T, R> handler, R args)
|
||||
{
|
||||
_handler = handler;
|
||||
_args = args;
|
||||
_ruleName = string.Format(@"rule://{0}/{1}", _handler.Method.Name, _args.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and initializes the rule.
|
||||
/// </summary>
|
||||
/// <param name="handler">The address of the method implementing the rule.</param>
|
||||
/// <param name="args">A RuleArgs object.</param>
|
||||
/// <param name="priority">
|
||||
/// Priority for processing the rule (smaller numbers have higher priority, default=0).
|
||||
/// </param>
|
||||
public RuleMethod(RuleHandler<T, R> handler, R args, int priority)
|
||||
: this(handler, args)
|
||||
{
|
||||
_priority = priority;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the rule to validate the data.
|
||||
/// </summary>
|
||||
/// <returns>True if the data is valid, False if the data is invalid.</returns>
|
||||
bool IRuleMethod.Invoke(object target)
|
||||
{
|
||||
return this.Invoke((T)target);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the rule to validate the data.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the data is valid,
|
||||
/// <see langword="false" /> if the data is invalid.
|
||||
/// </returns>
|
||||
public bool Invoke(T target)
|
||||
{
|
||||
return _handler.Invoke(target, _args);
|
||||
}
|
||||
|
||||
#region IComparable
|
||||
|
||||
int IComparable.CompareTo(object obj)
|
||||
{
|
||||
return Priority.CompareTo(((IRuleMethod)obj).Priority);
|
||||
}
|
||||
|
||||
int IComparable<IRuleMethod>.CompareTo(IRuleMethod other)
|
||||
{
|
||||
return Priority.CompareTo(other.Priority);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
|
||||
namespace Csla.Validation
|
||||
{
|
||||
/// <summary>
|
||||
/// Values for validation rule severities.
|
||||
/// </summary>
|
||||
public enum RuleSeverity
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a serious
|
||||
/// business rule violation that
|
||||
/// should cause an object to
|
||||
/// be considered invalid.
|
||||
/// </summary>
|
||||
Error,
|
||||
|
||||
/// <summary>
|
||||
/// Represents a business rule
|
||||
/// violation that should be
|
||||
/// displayed to the user, but which
|
||||
/// should not make an object be
|
||||
/// invalid.
|
||||
/// </summary>
|
||||
Warning,
|
||||
|
||||
/// <summary>
|
||||
/// Represents a business rule
|
||||
/// result that should be displayed
|
||||
/// to the user, but which is less
|
||||
/// severe than a warning.
|
||||
/// </summary>
|
||||
Information
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Csla.Validation
|
||||
{
|
||||
internal class RulesList
|
||||
{
|
||||
private List<IRuleMethod> _list = new List<IRuleMethod>();
|
||||
private bool _sorted;
|
||||
private List<string> _dependantProperties;
|
||||
|
||||
public void Add(IRuleMethod item)
|
||||
{
|
||||
_list.Add(item);
|
||||
_sorted = false;
|
||||
}
|
||||
|
||||
public List<IRuleMethod> GetList(bool applySort)
|
||||
{
|
||||
if (applySort && !_sorted)
|
||||
{
|
||||
lock (_list)
|
||||
{
|
||||
if (applySort && !_sorted)
|
||||
{
|
||||
_list.Sort();
|
||||
_sorted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _list;
|
||||
}
|
||||
|
||||
public List<string> GetDependancyList(bool create)
|
||||
{
|
||||
if (_dependantProperties == null && create)
|
||||
_dependantProperties = new List<string>();
|
||||
return _dependantProperties;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Csla.Validation
|
||||
{
|
||||
/// <summary>
|
||||
/// Maintains a list of all the per-type
|
||||
/// <see cref="ValidationRulesManager"/> objects
|
||||
/// loaded in memory.
|
||||
/// </summary>
|
||||
internal static class SharedValidationRules
|
||||
{
|
||||
private static Dictionary<Type, ValidationRulesManager> _managers =
|
||||
new Dictionary<Type, ValidationRulesManager>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ValidationRulesManager"/> for the
|
||||
/// specified object type, optionally creating a new instance
|
||||
/// of the object if necessary.
|
||||
/// </summary>
|
||||
/// <param name="objectType">
|
||||
/// Type of business object for which the rules apply.
|
||||
/// </param>
|
||||
/// <param name="create">Indicates whether to create
|
||||
/// a new instance of the object if one doesn't exist.</param>
|
||||
internal static ValidationRulesManager GetManager(Type objectType, bool create)
|
||||
{
|
||||
ValidationRulesManager result = null;
|
||||
if (!_managers.TryGetValue(objectType, out result) && create)
|
||||
{
|
||||
lock (_managers)
|
||||
{
|
||||
result = new ValidationRulesManager();
|
||||
_managers.Add(objectType, result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a set of rules
|
||||
/// have been created for a given <see cref="Type" />.
|
||||
/// </summary>
|
||||
/// <param name="objectType">
|
||||
/// Type of business object for which the rules apply.
|
||||
/// </param>
|
||||
/// <returns><see langword="true" /> if rules exist for the type.</returns>
|
||||
public static bool RulesExistFor(Type objectType)
|
||||
{
|
||||
return _managers.ContainsKey(objectType);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
|
||||
namespace Csla.Validation
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Exception class indicating that there was a validation
|
||||
/// problem with a business object.
|
||||
/// </summary>
|
||||
[Serializable()]
|
||||
public class ValidationException : Exception
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object.
|
||||
/// </summary>
|
||||
public ValidationException()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object.
|
||||
/// </summary>
|
||||
/// <param name="message">Message describing the exception.</param>
|
||||
public ValidationException(string message)
|
||||
: base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object.
|
||||
/// </summary>
|
||||
/// <param name="message">Message describing the exception.</param>
|
||||
/// <param name="innerException">Inner exception object.</param>
|
||||
public ValidationException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object for serialization.
|
||||
/// </summary>
|
||||
/// <param name="context">Serialization context.</param>
|
||||
/// <param name="info">Serialization info.</param>
|
||||
protected ValidationException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,768 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Csla.Validation
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the business rules broken within a business object.
|
||||
/// </summary>
|
||||
[Serializable()]
|
||||
public class ValidationRules
|
||||
{
|
||||
// list of broken rules for this business object.
|
||||
private BrokenRulesCollection _brokenRules;
|
||||
// threshold for short-circuiting to kick in
|
||||
private int _processThroughPriority;
|
||||
// reference to current business object
|
||||
[NonSerialized()]
|
||||
private object _target;
|
||||
// reference to per-instance rules manager for this object
|
||||
[NonSerialized()]
|
||||
private ValidationRulesManager _instanceRules;
|
||||
// reference to per-type rules manager for this object
|
||||
[NonSerialized()]
|
||||
private ValidationRulesManager _typeRules;
|
||||
// reference to the active set of rules for this object
|
||||
[NonSerialized()]
|
||||
private ValidationRulesManager _rulesToCheck;
|
||||
|
||||
internal ValidationRules(object businessObject)
|
||||
{
|
||||
SetTarget(businessObject);
|
||||
}
|
||||
|
||||
internal void SetTarget(object businessObject)
|
||||
{
|
||||
_target = businessObject;
|
||||
}
|
||||
|
||||
private BrokenRulesCollection BrokenRulesList
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_brokenRules == null)
|
||||
_brokenRules = new BrokenRulesCollection();
|
||||
return _brokenRules;
|
||||
}
|
||||
}
|
||||
|
||||
private ValidationRulesManager GetInstanceRules(bool createObject)
|
||||
{
|
||||
if (_instanceRules == null)
|
||||
if (createObject)
|
||||
_instanceRules = new ValidationRulesManager();
|
||||
return _instanceRules;
|
||||
}
|
||||
|
||||
private ValidationRulesManager GetTypeRules(bool createObject)
|
||||
{
|
||||
if (_typeRules == null)
|
||||
_typeRules = SharedValidationRules.GetManager(_target.GetType(), createObject);
|
||||
return _typeRules;
|
||||
}
|
||||
|
||||
private ValidationRulesManager RulesToCheck
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_rulesToCheck == null)
|
||||
{
|
||||
ValidationRulesManager instanceRules = GetInstanceRules(false);
|
||||
ValidationRulesManager typeRules = GetTypeRules(false);
|
||||
if (instanceRules == null)
|
||||
{
|
||||
if (typeRules == null)
|
||||
_rulesToCheck = null;
|
||||
else
|
||||
_rulesToCheck = typeRules;
|
||||
}
|
||||
else if (typeRules == null)
|
||||
_rulesToCheck = instanceRules;
|
||||
else
|
||||
{
|
||||
// both have values - consolidate into instance rules
|
||||
_rulesToCheck = instanceRules;
|
||||
foreach (KeyValuePair<string, RulesList> de in typeRules.RulesDictionary)
|
||||
{
|
||||
RulesList rules = _rulesToCheck.GetRulesForProperty(de.Key, true);
|
||||
List<IRuleMethod> instanceList = rules.GetList(false);
|
||||
instanceList.AddRange(de.Value.GetList(false));
|
||||
List<string> dependancy = de.Value.GetDependancyList(false);
|
||||
if (dependancy != null)
|
||||
rules.GetDependancyList(true).AddRange(dependancy);
|
||||
}
|
||||
}
|
||||
}
|
||||
return _rulesToCheck;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an array containing the text descriptions of all
|
||||
/// validation rules associated with this object.
|
||||
/// </summary>
|
||||
/// <returns>String array.</returns>
|
||||
/// <remarks></remarks>
|
||||
public string[] GetRuleDescriptions()
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
ValidationRulesManager rules = RulesToCheck;
|
||||
if (rules != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, RulesList> de in rules.RulesDictionary)
|
||||
{
|
||||
List<IRuleMethod> list = de.Value.GetList(false);
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
IRuleMethod rule = list[i];
|
||||
result.Add(rule.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
#region Short-Circuiting
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the priority through which
|
||||
/// CheckRules should process before short-circuiting
|
||||
/// processing on broken rules.
|
||||
/// </summary>
|
||||
/// <value>Defaults to 0.</value>
|
||||
/// <remarks>
|
||||
/// All rules for each property are processed by CheckRules
|
||||
/// though this priority. Rules with lower priorities are
|
||||
/// only processed if no previous rule has been marked as
|
||||
/// broken.
|
||||
/// </remarks>
|
||||
public int ProcessThroughPriority
|
||||
{
|
||||
get { return _processThroughPriority; }
|
||||
set { _processThroughPriority = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Adding Instance Rules
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </para><para>
|
||||
/// The propertyName may be used by the method that implements the rule
|
||||
/// in order to retrieve the value to be validated. If the rule
|
||||
/// implementation is inside the target object then it probably has
|
||||
/// direct access to all data. However, if the rule implementation
|
||||
/// is outside the target object then it will need to use reflection
|
||||
/// or CallByName to dynamically invoke this property to retrieve
|
||||
/// the value to be validated.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="propertyName">
|
||||
/// The property name on the target object where the rule implementation can retrieve
|
||||
/// the value to be validated.
|
||||
/// </param>
|
||||
public void AddInstanceRule(RuleHandler handler, string propertyName)
|
||||
{
|
||||
GetInstanceRules(true).AddRule(handler, new RuleArgs(propertyName), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </para><para>
|
||||
/// The propertyName may be used by the method that implements the rule
|
||||
/// in order to retrieve the value to be validated. If the rule
|
||||
/// implementation is inside the target object then it probably has
|
||||
/// direct access to all data. However, if the rule implementation
|
||||
/// is outside the target object then it will need to use reflection
|
||||
/// or CallByName to dynamically invoke this property to retrieve
|
||||
/// the value to be validated.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="propertyName">
|
||||
/// The property name on the target object where the rule implementation can retrieve
|
||||
/// the value to be validated.
|
||||
/// </param>
|
||||
/// <param name="priority">
|
||||
/// The priority of the rule, where lower numbers are processed first.
|
||||
/// </param>
|
||||
public void AddInstanceRule(RuleHandler handler, string propertyName, int priority)
|
||||
{
|
||||
GetInstanceRules(true).AddRule(handler, new RuleArgs(propertyName), priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </para><para>
|
||||
/// The propertyName may be used by the method that implements the rule
|
||||
/// in order to retrieve the value to be validated. If the rule
|
||||
/// implementation is inside the target object then it probably has
|
||||
/// direct access to all data. However, if the rule implementation
|
||||
/// is outside the target object then it will need to use reflection
|
||||
/// or CallByName to dynamically invoke this property to retrieve
|
||||
/// the value to be validated.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="propertyName">
|
||||
/// The property name on the target object where the rule implementation can retrieve
|
||||
/// the value to be validated.
|
||||
/// </param>
|
||||
/// <typeparam name="T">Type of the business object to be validated.</typeparam>
|
||||
public void AddInstanceRule<T>(RuleHandler<T, RuleArgs> handler, string propertyName)
|
||||
{
|
||||
GetInstanceRules(true).AddRule<T, RuleArgs>(handler, new RuleArgs(propertyName), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </para><para>
|
||||
/// The propertyName may be used by the method that implements the rule
|
||||
/// in order to retrieve the value to be validated. If the rule
|
||||
/// implementation is inside the target object then it probably has
|
||||
/// direct access to all data. However, if the rule implementation
|
||||
/// is outside the target object then it will need to use reflection
|
||||
/// or CallByName to dynamically invoke this property to retrieve
|
||||
/// the value to be validated.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="propertyName">
|
||||
/// The property name on the target object where the rule implementation can retrieve
|
||||
/// the value to be validated.
|
||||
/// </param>
|
||||
/// <param name="priority">
|
||||
/// The priority of the rule, where lower numbers are processed first.
|
||||
/// </param>
|
||||
/// <typeparam name="T">Type of the business object to be validated.</typeparam>
|
||||
public void AddInstanceRule<T>(RuleHandler<T, RuleArgs> handler, string propertyName, int priority)
|
||||
{
|
||||
GetInstanceRules(true).AddRule<T, RuleArgs>(handler, new RuleArgs(propertyName), priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </remarks>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="args">
|
||||
/// A RuleArgs object specifying the property name and other arguments
|
||||
/// passed to the rule method
|
||||
/// </param>
|
||||
public void AddInstanceRule(RuleHandler handler, RuleArgs args)
|
||||
{
|
||||
GetInstanceRules(true).AddRule(handler, args, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </remarks>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="args">
|
||||
/// A RuleArgs object specifying the property name and other arguments
|
||||
/// passed to the rule method
|
||||
/// </param>
|
||||
/// <param name="priority">
|
||||
/// The priority of the rule, where lower numbers are processed first.
|
||||
/// </param>
|
||||
public void AddInstanceRule(RuleHandler handler, RuleArgs args, int priority)
|
||||
{
|
||||
GetInstanceRules(true).AddRule(handler, args, priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">Type of the target object.</typeparam>
|
||||
/// <typeparam name="R">Type of the arguments parameter.</typeparam>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="args">
|
||||
/// A RuleArgs object specifying the property name and other arguments
|
||||
/// passed to the rule method
|
||||
/// </param>
|
||||
public void AddInstanceRule<T, R>(RuleHandler<T, R> handler, R args) where R : RuleArgs
|
||||
{
|
||||
GetInstanceRules(true).AddRule(handler, args, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">Type of the target object.</typeparam>
|
||||
/// <typeparam name="R">Type of the arguments parameter.</typeparam>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="args">
|
||||
/// A RuleArgs object specifying the property name and other arguments
|
||||
/// passed to the rule method
|
||||
/// </param>
|
||||
/// <param name="priority">
|
||||
/// The priority of the rule, where lower numbers are processed first.
|
||||
/// </param>
|
||||
public void AddInstanceRule<T, R>(RuleHandler<T, R> handler, R args, int priority) where R : RuleArgs
|
||||
{
|
||||
GetInstanceRules(true).AddRule(handler, args, priority);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Adding Per-Type Rules
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </para><para>
|
||||
/// The propertyName may be used by the method that implements the rule
|
||||
/// in order to retrieve the value to be validated. If the rule
|
||||
/// implementation is inside the target object then it probably has
|
||||
/// direct access to all data. However, if the rule implementation
|
||||
/// is outside the target object then it will need to use reflection
|
||||
/// or CallByName to dynamically invoke this property to retrieve
|
||||
/// the value to be validated.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="propertyName">
|
||||
/// The property name on the target object where the rule implementation can retrieve
|
||||
/// the value to be validated.
|
||||
/// </param>
|
||||
public void AddRule(RuleHandler handler, string propertyName)
|
||||
{
|
||||
ValidateHandler(handler);
|
||||
GetTypeRules(true).AddRule(handler, new RuleArgs(propertyName), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </para><para>
|
||||
/// The propertyName may be used by the method that implements the rule
|
||||
/// in order to retrieve the value to be validated. If the rule
|
||||
/// implementation is inside the target object then it probably has
|
||||
/// direct access to all data. However, if the rule implementation
|
||||
/// is outside the target object then it will need to use reflection
|
||||
/// or CallByName to dynamically invoke this property to retrieve
|
||||
/// the value to be validated.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="propertyName">
|
||||
/// The property name on the target object where the rule implementation can retrieve
|
||||
/// the value to be validated.
|
||||
/// </param>
|
||||
/// <param name="priority">
|
||||
/// The priority of the rule, where lower numbers are processed first.
|
||||
/// </param>
|
||||
public void AddRule(RuleHandler handler, string propertyName, int priority)
|
||||
{
|
||||
ValidateHandler(handler);
|
||||
GetTypeRules(true).AddRule(handler, new RuleArgs(propertyName), priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </para><para>
|
||||
/// The propertyName may be used by the method that implements the rule
|
||||
/// in order to retrieve the value to be validated. If the rule
|
||||
/// implementation is inside the target object then it probably has
|
||||
/// direct access to all data. However, if the rule implementation
|
||||
/// is outside the target object then it will need to use reflection
|
||||
/// or CallByName to dynamically invoke this property to retrieve
|
||||
/// the value to be validated.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="propertyName">
|
||||
/// The property name on the target object where the rule implementation can retrieve
|
||||
/// the value to be validated.
|
||||
/// </param>
|
||||
public void AddRule<T>(RuleHandler<T, RuleArgs> handler, string propertyName)
|
||||
{
|
||||
ValidateHandler(handler);
|
||||
GetTypeRules(true).AddRule<T, RuleArgs>(handler, new RuleArgs(propertyName), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </para><para>
|
||||
/// The propertyName may be used by the method that implements the rule
|
||||
/// in order to retrieve the value to be validated. If the rule
|
||||
/// implementation is inside the target object then it probably has
|
||||
/// direct access to all data. However, if the rule implementation
|
||||
/// is outside the target object then it will need to use reflection
|
||||
/// or CallByName to dynamically invoke this property to retrieve
|
||||
/// the value to be validated.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="propertyName">
|
||||
/// The property name on the target object where the rule implementation can retrieve
|
||||
/// the value to be validated.
|
||||
/// </param>
|
||||
/// <param name="priority">
|
||||
/// The priority of the rule, where lower numbers are processed first.
|
||||
/// </param>
|
||||
public void AddRule<T>(RuleHandler<T, RuleArgs> handler, string propertyName, int priority)
|
||||
{
|
||||
ValidateHandler(handler);
|
||||
GetTypeRules(true).AddRule<T, RuleArgs>(handler, new RuleArgs(propertyName), priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </remarks>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="args">
|
||||
/// A RuleArgs object specifying the property name and other arguments
|
||||
/// passed to the rule method
|
||||
/// </param>
|
||||
public void AddRule(RuleHandler handler, RuleArgs args)
|
||||
{
|
||||
ValidateHandler(handler);
|
||||
GetTypeRules(true).AddRule(handler, args, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </remarks>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="args">
|
||||
/// A RuleArgs object specifying the property name and other arguments
|
||||
/// passed to the rule method
|
||||
/// </param>
|
||||
/// <param name="priority">
|
||||
/// The priority of the rule, where lower numbers are processed first.
|
||||
/// </param>
|
||||
public void AddRule(RuleHandler handler, RuleArgs args, int priority)
|
||||
{
|
||||
ValidateHandler(handler);
|
||||
GetTypeRules(true).AddRule(handler, args, priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">Type of the target object.</typeparam>
|
||||
/// <typeparam name="R">Type of the arguments parameter.</typeparam>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="args">
|
||||
/// A RuleArgs object specifying the property name and other arguments
|
||||
/// passed to the rule method
|
||||
/// </param>
|
||||
public void AddRule<T, R>(RuleHandler<T, R> handler, R args) where R : RuleArgs
|
||||
{
|
||||
ValidateHandler(handler);
|
||||
GetTypeRules(true).AddRule(handler, args, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the list of rules to be enforced.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A rule is implemented by a method which conforms to the
|
||||
/// method signature defined by the RuleHandler delegate.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">Type of the target object.</typeparam>
|
||||
/// <typeparam name="R">Type of the arguments parameter.</typeparam>
|
||||
/// <param name="handler">The method that implements the rule.</param>
|
||||
/// <param name="args">
|
||||
/// A RuleArgs object specifying the property name and other arguments
|
||||
/// passed to the rule method
|
||||
/// </param>
|
||||
/// <param name="priority">
|
||||
/// The priority of the rule, where lower numbers are processed first.
|
||||
/// </param>
|
||||
public void AddRule<T, R>(RuleHandler<T, R> handler, R args, int priority) where R : RuleArgs
|
||||
{
|
||||
ValidateHandler(handler);
|
||||
GetTypeRules(true).AddRule(handler, args, priority);
|
||||
}
|
||||
|
||||
private bool ValidateHandler(RuleHandler handler)
|
||||
{
|
||||
return ValidateHandler(handler.Method);
|
||||
}
|
||||
|
||||
private bool ValidateHandler<T, R>(RuleHandler<T, R> handler) where R : RuleArgs
|
||||
{
|
||||
return ValidateHandler(handler.Method);
|
||||
}
|
||||
|
||||
private bool ValidateHandler(System.Reflection.MethodInfo method)
|
||||
{
|
||||
if (!method.IsStatic && method.DeclaringType.Equals(_target.GetType()))
|
||||
throw new InvalidOperationException(
|
||||
string.Format("{0}: {1}",
|
||||
Properties.Resources.InvalidRuleMethodException, method.Name));
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Adding per-type dependancies
|
||||
|
||||
/// <summary>
|
||||
/// Adds a property to the list of dependencies for
|
||||
/// the specified property
|
||||
/// </summary>
|
||||
/// <param name="propertyName">
|
||||
/// The name of the property.
|
||||
/// </param>
|
||||
/// <param name="dependantPropertyName">
|
||||
/// The name of the depandent property.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When rules are checked for propertyName, they will
|
||||
/// also be checked for any dependant properties associated
|
||||
/// with that property.
|
||||
/// </remarks>
|
||||
public void AddDependantProperty(string propertyName, string dependantPropertyName)
|
||||
{
|
||||
GetTypeRules(true).AddDependantProperty(propertyName, dependantPropertyName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a property to the list of dependencies for
|
||||
/// the specified property
|
||||
/// </summary>
|
||||
/// <param name="propertyName">
|
||||
/// The name of the property.
|
||||
/// </param>
|
||||
/// <param name="dependantPropertyName">
|
||||
/// The name of the depandent property.
|
||||
/// </param>
|
||||
/// <param name="isBidirectional">
|
||||
/// If <see langword="true"/> then a
|
||||
/// reverse dependancy is also established
|
||||
/// from dependantPropertyName to propertyName.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When rules are checked for propertyName, they will
|
||||
/// also be checked for any dependant properties associated
|
||||
/// with that property. If isBidirectional is
|
||||
/// <see langword="true"/> then an additional association
|
||||
/// is set up so when rules are checked for
|
||||
/// dependantPropertyName the rules for propertyName
|
||||
/// will also be checked.
|
||||
/// </remarks>
|
||||
public void AddDependantProperty(string propertyName, string dependantPropertyName, bool isBidirectional)
|
||||
{
|
||||
|
||||
ValidationRulesManager mgr = GetTypeRules(true);
|
||||
mgr.AddDependantProperty(propertyName, dependantPropertyName);
|
||||
if (isBidirectional)
|
||||
{
|
||||
mgr.AddDependantProperty(dependantPropertyName, propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Checking Rules
|
||||
|
||||
/// <summary>
|
||||
/// Invokes all rule methods associated with
|
||||
/// the specified property and any
|
||||
/// dependant properties.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">The name of the property to validate.</param>
|
||||
public void CheckRules(string propertyName)
|
||||
{
|
||||
// get the rules dictionary
|
||||
ValidationRulesManager rules = RulesToCheck;
|
||||
if (rules != null)
|
||||
{
|
||||
// get the rules list for this property
|
||||
RulesList rulesList = rules.GetRulesForProperty(propertyName, false);
|
||||
if (rulesList != null)
|
||||
{
|
||||
// get the actual list of rules (sorted by priority)
|
||||
List<IRuleMethod> list = rulesList.GetList(true);
|
||||
if (list != null)
|
||||
CheckRules(list);
|
||||
List<string> dependancies = rulesList.GetDependancyList(false);
|
||||
if (dependancies != null)
|
||||
{
|
||||
for (int i = 0; i < dependancies.Count; i++)
|
||||
{
|
||||
string dependantProperty = dependancies[i];
|
||||
CheckRules(rules, dependantProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckRules(ValidationRulesManager rules, string propertyName)
|
||||
{
|
||||
// get the rules list for this property
|
||||
RulesList rulesList = rules.GetRulesForProperty(propertyName, false);
|
||||
if (rulesList != null)
|
||||
{
|
||||
// get the actual list of rules (sorted by priority)
|
||||
List<IRuleMethod> list = rulesList.GetList(true);
|
||||
if (list != null)
|
||||
CheckRules(list);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes all rule methods for all properties
|
||||
/// in the object.
|
||||
/// </summary>
|
||||
public void CheckRules()
|
||||
{
|
||||
ValidationRulesManager rules = RulesToCheck;
|
||||
if (rules != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, RulesList> de in rules.RulesDictionary)
|
||||
CheckRules(de.Value.GetList(true));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a list
|
||||
/// containing IRuleMethod objects, this
|
||||
/// method executes all those rule methods.
|
||||
/// </summary>
|
||||
private void CheckRules(List<IRuleMethod> list)
|
||||
{
|
||||
bool previousRuleBroken = false;
|
||||
bool shortCircuited = false;
|
||||
|
||||
for (int index = 0; index < list.Count; index++)
|
||||
{
|
||||
IRuleMethod rule = list[index];
|
||||
// see if short-circuiting should kick in
|
||||
if (!shortCircuited && (previousRuleBroken && rule.Priority > _processThroughPriority))
|
||||
shortCircuited = true;
|
||||
|
||||
if (shortCircuited)
|
||||
{
|
||||
// we're short-circuited, so just remove
|
||||
// all remaining broken rule entries
|
||||
BrokenRulesList.Remove(rule);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we're not short-circuited, so check rule
|
||||
if (rule.Invoke(_target))
|
||||
{
|
||||
// the rule is not broken
|
||||
BrokenRulesList.Remove(rule);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the rule is broken
|
||||
BrokenRulesList.Add(rule);
|
||||
if (rule.RuleArgs.Severity == RuleSeverity.Error)
|
||||
previousRuleBroken = true;
|
||||
}
|
||||
if (rule.RuleArgs.StopProcessing)
|
||||
shortCircuited = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Status Retrieval
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether there are any broken rules
|
||||
/// at this time.
|
||||
/// </summary>
|
||||
/// <returns>A value indicating whether any rules are broken.</returns>
|
||||
internal bool IsValid
|
||||
{
|
||||
get { return BrokenRulesList.ErrorCount == 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a reference to the readonly collection of broken
|
||||
/// business rules.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The reference returned points to the actual collection object.
|
||||
/// This means that as rules are marked broken or unbroken over time,
|
||||
/// the underlying data will change. Because of this, the UI developer
|
||||
/// can bind a display directly to this collection to get a dynamic
|
||||
/// display of the broken rules at all times.
|
||||
/// </remarks>
|
||||
/// <returns>A reference to the collection of broken rules.</returns>
|
||||
public BrokenRulesCollection GetBrokenRules()
|
||||
{
|
||||
return BrokenRulesList;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Csla.Validation
|
||||
{
|
||||
/// <summary>
|
||||
/// Maintains rule methods for a business object
|
||||
/// or business object type.
|
||||
/// </summary>
|
||||
internal class ValidationRulesManager
|
||||
{
|
||||
private Dictionary<string, RulesList> _rulesList;
|
||||
|
||||
internal Dictionary<string, RulesList> RulesDictionary
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_rulesList == null)
|
||||
_rulesList = new Dictionary<string, RulesList>();
|
||||
return _rulesList;
|
||||
}
|
||||
}
|
||||
|
||||
internal RulesList GetRulesForProperty(
|
||||
string propertyName,
|
||||
bool createList)
|
||||
{
|
||||
// get the list (if any) from the dictionary
|
||||
RulesList list = null;
|
||||
if (RulesDictionary.ContainsKey(propertyName))
|
||||
list = RulesDictionary[propertyName];
|
||||
|
||||
if (createList && list == null)
|
||||
{
|
||||
// there is no list for this name - create one
|
||||
list = new RulesList();
|
||||
RulesDictionary.Add(propertyName, list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
#region Adding Rules
|
||||
|
||||
public void AddRule(RuleHandler handler, RuleArgs args, int priority)
|
||||
{
|
||||
// get the list of rules for the property
|
||||
List<IRuleMethod> list = GetRulesForProperty(args.PropertyName, true).GetList(false);
|
||||
|
||||
// we have the list, add out new rule
|
||||
list.Add(new RuleMethod(handler, args, priority));
|
||||
}
|
||||
|
||||
public void AddRule<T, R>(RuleHandler<T, R> handler, R args, int priority) where R : RuleArgs
|
||||
{
|
||||
// get the list of rules for the property
|
||||
List<IRuleMethod> list = GetRulesForProperty(args.PropertyName, true).GetList(false);
|
||||
|
||||
// we have the list, add out new rule
|
||||
list.Add(new RuleMethod<T, R>(handler, args, priority));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Adding Dependencies
|
||||
|
||||
/// <summary>
|
||||
/// Adds a property to the list of dependencies for
|
||||
/// the specified property
|
||||
/// </summary>
|
||||
/// <param name="propertyName">
|
||||
/// The name of the property.
|
||||
/// </param>
|
||||
/// <param name="dependantPropertyName">
|
||||
/// The name of the dependant property.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// When rules are checked for propertyName, they will
|
||||
/// also be checked for any dependant properties associated
|
||||
/// with that property.
|
||||
/// </remarks>
|
||||
public void AddDependantProperty(string propertyName, string dependantPropertyName)
|
||||
{
|
||||
// get the list of rules for the property
|
||||
List<string> list = GetRulesForProperty(propertyName, true).GetDependancyList(true);
|
||||
|
||||
// we have the list, add the dependency
|
||||
list.Add(dependantPropertyName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user