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
 | 
						|
 | 
						|
  }
 | 
						|
} |