768 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			768 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| 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
 | |
| 
 | |
|   }
 | |
| } |