900 lines
29 KiB
VB.net
900 lines
29 KiB
VB.net
Imports System.Collections.Specialized
|
|
|
|
''' <summary>
|
|
''' Tracks the business rules broken within a business object.
|
|
''' </summary>
|
|
<Serializable()> _
|
|
Public Class BrokenRules
|
|
|
|
#Region " Rule structure "
|
|
|
|
''' <summary>
|
|
''' Stores details about a specific broken business rule.
|
|
''' </summary>
|
|
<Serializable()> _
|
|
Public Structure Rule
|
|
Private mRule As String
|
|
Private mDescription As String
|
|
Private mProperty As String
|
|
|
|
Friend Sub New(ByVal Rule As String, ByVal Description As String)
|
|
mRule = Rule
|
|
mDescription = Description
|
|
End Sub
|
|
|
|
Friend Sub New(ByVal Rule As String, ByVal Description As String, ByVal [Property] As String)
|
|
mRule = Rule
|
|
mDescription = Description
|
|
mProperty = [Property]
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Provides access to the name of the broken rule.
|
|
''' </summary>
|
|
''' <remarks>
|
|
''' This value is actually readonly, not readwrite. Any new
|
|
''' value set into this property is ignored. The property is only
|
|
''' readwrite because that is required to support data binding
|
|
''' within Web Forms.
|
|
''' </remarks>
|
|
''' <value>The name of the rule.</value>
|
|
Public Property Rule() As String
|
|
Get
|
|
Return mRule
|
|
End Get
|
|
Set(ByVal Value As String)
|
|
' the property must be read-write for Web Forms data binding
|
|
' to work, but we really don't want to allow the value to be
|
|
' changed dynamically so we ignore any attempt to set it
|
|
End Set
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Provides access to the description of the broken rule.
|
|
''' </summary>
|
|
''' <remarks>
|
|
''' This value is actually readonly, not readwrite. Any new
|
|
''' value set into this property is ignored. The property is only
|
|
''' readwrite because that is required to support data binding
|
|
''' within Web Forms.
|
|
''' </remarks>
|
|
''' <value>The description of the rule.</value>
|
|
Public Property Description() As String
|
|
Get
|
|
Return mDescription
|
|
End Get
|
|
Set(ByVal Value As String)
|
|
' the property must be read-write for Web Forms data binding
|
|
' to work, but we really don't want to allow the value to be
|
|
' changed dynamically so we ignore any attempt to set it
|
|
End Set
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Provides access to the property affected by the broken rule.
|
|
''' </summary>
|
|
''' <remarks>
|
|
''' This value is actually readonly, not readwrite. Any new
|
|
''' value set into this property is ignored. The property is only
|
|
''' readwrite because that is required to support data binding
|
|
''' within Web Forms.
|
|
''' </remarks>
|
|
''' <value>The property affected by the rule.</value>
|
|
Public Property [Property]() As String
|
|
Get
|
|
Return mProperty
|
|
End Get
|
|
Set(ByVal Value As String)
|
|
' the property must be read-write for Web Forms data binding
|
|
' to work, but we really don't want to allow the value to be
|
|
' changed dynamically so we ignore any attempt to set it
|
|
End Set
|
|
End Property
|
|
End Structure
|
|
|
|
#End Region
|
|
|
|
#Region " RulesCollection "
|
|
|
|
''' <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 RulesCollection
|
|
Inherits CSLA.Core.BindableCollectionBase
|
|
|
|
Private mLegal As Boolean = False
|
|
|
|
''' <summary>
|
|
''' Returns a <see cref="T:CSLA.BrokenRules.Rule" /> object
|
|
''' containing details about a specific broken business rule.
|
|
''' </summary>
|
|
''' <param name="Index"></param>
|
|
''' <returns></returns>
|
|
Default Public ReadOnly Property Item(ByVal Index As Integer) As Rule
|
|
Get
|
|
Return CType(list.Item(Index), Rule)
|
|
End Get
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Returns the first <see cref="T:CSLA.BrokenRules.Rule" /> object
|
|
''' corresponding to the specified property.
|
|
''' </summary>
|
|
''' <remarks>
|
|
''' <para>
|
|
''' When a rule is marked as broken, the business developer can provide
|
|
''' an optional Property parameter. This parameter is the name of the
|
|
''' Property on the object that is most affected by the rule. Data binding
|
|
''' may later use the IDataErrorInfo interface to query the object for
|
|
''' details about errors corresponding to specific properties, and this
|
|
''' value will be returned as a result of that query.
|
|
''' </para><para>
|
|
''' Code in a business object or UI can also use this value to retrieve
|
|
''' the first broken rule in <see cref="T:CSLA.BrokenRules" /> that corresponds
|
|
''' to a specfic Property on the object.
|
|
''' </para>
|
|
''' </remarks>
|
|
''' <param name="Property">The name of the property affected by the rule.</param>
|
|
Public ReadOnly Property RuleForProperty(ByVal [Property] As String) As Rule
|
|
Get
|
|
Dim item As Rule
|
|
|
|
For Each item In list
|
|
If item.Property = [Property] Then
|
|
Return item
|
|
End If
|
|
Next
|
|
Return New Rule()
|
|
End Get
|
|
End Property
|
|
|
|
Friend Sub New()
|
|
AllowEdit = False
|
|
AllowRemove = False
|
|
AllowNew = False
|
|
End Sub
|
|
|
|
Friend Sub Add(ByVal Rule As String, ByVal Description As String)
|
|
Remove(Rule)
|
|
mLegal = True
|
|
list.Add(New Rule(Rule, Description))
|
|
mLegal = False
|
|
End Sub
|
|
|
|
Friend Sub Add(ByVal Rule As String, ByVal Description As String, ByVal [Property] As String)
|
|
Remove(Rule)
|
|
mLegal = True
|
|
list.Add(New Rule(Rule, Description, [Property]))
|
|
mLegal = False
|
|
End Sub
|
|
|
|
Friend Sub Remove(ByVal Rule As String)
|
|
Dim index As Integer
|
|
|
|
' we loop through using a numeric counter because
|
|
' the base class Remove requires a numberic index
|
|
mLegal = True
|
|
For index = 0 To list.Count - 1
|
|
If CType(list.Item(index), Rule).Rule = Rule Then
|
|
list.Remove(list.Item(index))
|
|
Exit For
|
|
End If
|
|
Next
|
|
mLegal = False
|
|
End Sub
|
|
|
|
Friend Function Contains(ByVal Rule As String) As Boolean
|
|
Dim index As Integer
|
|
|
|
For index = 0 To list.Count - 1
|
|
If CType(list.Item(index), Rule).Rule = Rule Then
|
|
Return True
|
|
End If
|
|
Next
|
|
Return False
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Prevents clearing the collection.
|
|
''' </summary>
|
|
Protected Overrides Sub OnClear()
|
|
If Not mLegal Then
|
|
Throw New NotSupportedException("Clear is an invalid operation")
|
|
End If
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Prevents insertion of items into the collection.
|
|
''' </summary>
|
|
Protected Overrides Sub OnInsert(ByVal index As Integer, ByVal value As Object)
|
|
If Not mLegal Then
|
|
Throw New NotSupportedException("Insert is an invalid operation")
|
|
End If
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Prevents removal of items from the collection.
|
|
''' </summary>
|
|
Protected Overrides Sub OnRemove(ByVal index As Integer, ByVal value As Object)
|
|
If Not mLegal Then
|
|
Throw New NotSupportedException("Remove is an invalid operation")
|
|
End If
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Prevents changing items in the collection.
|
|
''' </summary>
|
|
Protected Overrides Sub OnSet(ByVal index As Integer, _
|
|
ByVal oldValue As Object, ByVal newValue As Object)
|
|
If Not mLegal Then
|
|
Throw New NotSupportedException("Changing an element is an invalid operation")
|
|
End If
|
|
End Sub
|
|
End Class
|
|
|
|
#End Region
|
|
|
|
Private mBrokenRules As New RulesCollection()
|
|
<NonSerialized(), NotUndoable()> _
|
|
Private mTarget As Object
|
|
|
|
#Region " Rule Manager "
|
|
|
|
''' <summary>
|
|
''' Sets the target object so the Rules Manager functionality
|
|
''' has a reference to the object containing the data to
|
|
''' be validated.
|
|
''' </summary>
|
|
''' <remarks>
|
|
''' The object here is typically your business object. In your
|
|
''' business class you'll implement a method to set up your
|
|
''' business rules. As you do so, you need to call this method
|
|
''' to give BrokenRules a reference to your business object
|
|
''' so it has access to your object's data.
|
|
''' </remarks>
|
|
''' <param name="target">A reference to the object containing
|
|
''' the data to be validated.</param>
|
|
Public Sub SetTargetObject(ByVal target As Object)
|
|
mTarget = target
|
|
End Sub
|
|
|
|
#Region " RuleHandler delegate "
|
|
|
|
''' <summary>
|
|
''' Delegate that defines the method signature for all rule handler methods.
|
|
''' </summary>
|
|
''' <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 True if the data is valid and
|
|
''' return False if the data is invalid.
|
|
''' </para>
|
|
''' </remarks>
|
|
Public Delegate Function RuleHandler(ByVal target As Object, ByVal e As RuleArgs) As Boolean
|
|
|
|
#End Region
|
|
|
|
#Region " RuleArgs class "
|
|
|
|
''' <summary>
|
|
''' Object providing extra information to methods that
|
|
''' implement business rules.
|
|
''' </summary>
|
|
Public Class RuleArgs
|
|
Private mPropertyName As String
|
|
Private mDescription As String
|
|
|
|
''' <summary>
|
|
''' The (optional) name of the property to be validated.
|
|
''' </summary>
|
|
Public ReadOnly Property PropertyName() As String
|
|
Get
|
|
Return mPropertyName
|
|
End Get
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Set by the rule handler method to describe the broken
|
|
''' rule.
|
|
''' </summary>
|
|
''' <remarks>
|
|
''' <para>
|
|
''' If the rule handler sets this property, this value will override
|
|
''' any description attribute value associated with the rule handler
|
|
''' method.
|
|
''' </para><para>
|
|
''' The description string returned via this property
|
|
''' is provided to the UI or other consumer
|
|
''' about which rules are broken. These descriptions are intended
|
|
''' for end-user display.
|
|
''' </para><para>
|
|
''' The description value is a .NET format string, and it can include
|
|
''' the following tokens in addition to literal text:
|
|
''' </para><para>
|
|
''' {0} - the RuleName value
|
|
''' </para><para>
|
|
''' {1} - the PropertyName value
|
|
''' </para><para>
|
|
''' {2} - the full type name of the target object
|
|
''' </para><para>
|
|
''' {3} - the ToString value of the target object
|
|
''' </para><para>
|
|
''' You can use these tokens in your description string and the
|
|
''' appropriate values will be substituted for the tokens at
|
|
''' runtime.
|
|
''' </para>
|
|
''' </remarks>
|
|
Public Property Description() As String
|
|
Get
|
|
Return mDescription
|
|
End Get
|
|
Set(ByVal Value As String)
|
|
mDescription = Value
|
|
End Set
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Creates an instance of RuleArgs.
|
|
''' </summary>
|
|
Public Sub New()
|
|
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Creates an instance of RuleArgs.
|
|
''' </summary>
|
|
''' <param name="propertyName">The name of the property to be validated.</param>
|
|
Public Sub New(ByVal propertyName As String)
|
|
mPropertyName = propertyName
|
|
End Sub
|
|
|
|
#Region " Empty "
|
|
|
|
Private Shared mEmptyArgs As New RuleArgs()
|
|
|
|
''' <summary>
|
|
''' Returns an empty RuleArgs object.
|
|
''' </summary>
|
|
Public Shared ReadOnly Property Empty() As RuleArgs
|
|
Get
|
|
Return mEmptyArgs
|
|
End Get
|
|
End Property
|
|
|
|
#End Region
|
|
|
|
End Class
|
|
|
|
#End Region
|
|
|
|
#Region " Description attribute "
|
|
|
|
''' <summary>
|
|
''' Defines the description of a business rule.
|
|
''' </summary>
|
|
''' <remarks>
|
|
''' <para>
|
|
''' The description in this attribute is used by BusinessRules
|
|
''' as information that is provided to the UI or other consumer
|
|
''' about which rules are broken. These descriptions are intended
|
|
''' for end-user display.
|
|
''' </para><para>
|
|
''' The description value is a .NET format string, and it can include
|
|
''' the following tokens in addition to literal text:
|
|
''' </para><para>
|
|
''' {0} - the RuleName value
|
|
''' </para><para>
|
|
''' {1} - the PropertyName value
|
|
''' </para><para>
|
|
''' {2} - the full type name of the target object
|
|
''' </para><para>
|
|
''' {3} - the ToString value of the target object
|
|
''' </para><para>
|
|
''' You can use these tokens in your description string and the
|
|
''' appropriate values will be substituted for the tokens at
|
|
''' runtime.
|
|
''' </para><para>
|
|
''' Instead of using this attribute, a rule handler method can
|
|
''' set the Description property of the RuleArgs parameter to
|
|
''' a description string. That approach can provide a more dynamic
|
|
''' way to generate descriptions of broken rules.
|
|
''' </para>
|
|
''' </remarks>
|
|
<AttributeUsage(AttributeTargets.Method)> _
|
|
Public Class DescriptionAttribute
|
|
Inherits Attribute
|
|
|
|
Private mText As String = ""
|
|
|
|
''' <summary>
|
|
''' Initializes the attribute with a description.
|
|
''' </summary>
|
|
Public Sub New(ByVal description As String)
|
|
mText = description
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Returns the description value of the attribute.
|
|
''' </summary>
|
|
Public Overrides Function ToString() As String
|
|
Return mText
|
|
End Function
|
|
|
|
End Class
|
|
|
|
#End Region
|
|
|
|
#Region " RuleMethod Class "
|
|
|
|
''' <summary>
|
|
''' Tracks all information for a rule.
|
|
''' </summary>
|
|
Private Class RuleMethod
|
|
Private mHandler As RuleHandler
|
|
Private mTarget As Object
|
|
Private mRuleName As String
|
|
Private mArgs As RuleArgs
|
|
Private mDescription As String
|
|
|
|
''' <summary>
|
|
''' Returns the name of the method implementing the rule
|
|
''' and the property, field or column name to which the
|
|
''' rule applies.
|
|
''' </summary>
|
|
Public Overrides Function ToString() As String
|
|
If RuleArgs.PropertyName Is Nothing Then
|
|
Return mHandler.Method.Name
|
|
|
|
Else
|
|
Return mHandler.Method.Name & "!" & RuleArgs.PropertyName
|
|
End If
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Returns the delegate to the method implementing the rule.
|
|
''' </summary>
|
|
Public ReadOnly Property Handler() As RuleHandler
|
|
Get
|
|
Return mHandler
|
|
End Get
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Returns the user-friendly name of the rule.
|
|
''' </summary>
|
|
Public ReadOnly Property RuleName() As String
|
|
Get
|
|
Return mRuleName
|
|
End Get
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Returns the name of the field, property or column
|
|
''' to which the rule applies.
|
|
''' </summary>
|
|
Public ReadOnly Property RuleArgs() As RuleArgs
|
|
Get
|
|
Return mArgs
|
|
End Get
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Returns the formatted description of the rule.
|
|
''' </summary>
|
|
Public ReadOnly Property Description() As String
|
|
Get
|
|
If Len(mArgs.Description) > 0 Then
|
|
Return String.Format(mArgs.Description, RuleName, RuleArgs.PropertyName, TypeName(mTarget), mTarget.ToString)
|
|
|
|
Else
|
|
Return String.Format(mDescription, RuleName, RuleArgs.PropertyName, TypeName(mTarget), mTarget.ToString)
|
|
End If
|
|
End Get
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Retrieves the description text from the Description
|
|
''' attribute on a RuleHandler method.
|
|
''' </summary>
|
|
Private Function GetDescription(ByVal handler As RuleHandler) As String
|
|
|
|
Dim attrib() As Object = handler.Method.GetCustomAttributes(GetType(DescriptionAttribute), False)
|
|
If attrib.Length > 0 Then
|
|
Return attrib(0).ToString
|
|
|
|
Else
|
|
Return "{2}.{0}:<no description>"
|
|
End If
|
|
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Creates and initializes the rule.
|
|
''' </summary>
|
|
''' <param name="target">Reference to the object containing the data to validate.</param>
|
|
''' <param name="handler">The address of the method implementing the rule.</param>
|
|
''' <param name="ruleName">The user-friendly name of the rule.</param>
|
|
''' <param name="ruleArgs">A RuleArgs object containing data related to the rule.</param>
|
|
Public Sub New(ByVal target As Object, ByVal handler As RuleHandler, ByVal ruleName As String, ByVal ruleArgs As RuleArgs)
|
|
|
|
mTarget = target
|
|
mHandler = handler
|
|
mDescription = GetDescription(handler)
|
|
mRuleName = ruleName
|
|
mArgs = ruleArgs
|
|
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Creates and initializes the rule.
|
|
''' </summary>
|
|
''' <param name="target">Reference to the object containing the data to validate.</param>
|
|
''' <param name="handler">The address of the method implementing the rule.</param>
|
|
''' <param name="ruleName">The user-friendly name of the rule.</param>
|
|
''' <param name="propertyName">The field, property or column to which the rule applies.</param>
|
|
Public Sub New(ByVal target As Object, ByVal handler As RuleHandler, ByVal ruleName As String, ByVal propertyName As String)
|
|
|
|
mTarget = target
|
|
mHandler = handler
|
|
mDescription = GetDescription(handler)
|
|
mRuleName = ruleName
|
|
mArgs = New RuleArgs(propertyName)
|
|
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Invokes the rule to validate the data.
|
|
''' </summary>
|
|
''' <returns>True if the data is valid, False if the data is invalid.</returns>
|
|
Public Function Invoke() As Boolean
|
|
Return mHandler.Invoke(mTarget, mArgs)
|
|
End Function
|
|
|
|
End Class
|
|
|
|
#End Region
|
|
|
|
#Region " RulesList property "
|
|
|
|
<NonSerialized(), NotUndoable()> _
|
|
Private mRulesList As HybridDictionary
|
|
|
|
Private ReadOnly Property RulesList() As HybridDictionary
|
|
Get
|
|
If mRulesList Is Nothing Then
|
|
mRulesList = New HybridDictionary()
|
|
End If
|
|
Return mRulesList
|
|
End Get
|
|
End Property
|
|
|
|
#End Region
|
|
|
|
#Region " Adding Rules "
|
|
|
|
''' <summary>
|
|
''' Returns the ArrayList containing rules for a rule name. If
|
|
''' no ArrayList exists one is created and returned.
|
|
''' </summary>
|
|
Private Function GetRulesForName(ByVal ruleName As String) As ArrayList
|
|
|
|
' get the ArrayList (if any) from the Hashtable
|
|
Dim list As ArrayList = CType(RulesList.Item(ruleName), ArrayList)
|
|
If list Is Nothing Then
|
|
' there is no list for this name - create one
|
|
list = New ArrayList()
|
|
RulesList.Add(ruleName, list)
|
|
End If
|
|
Return list
|
|
|
|
End Function
|
|
|
|
''' <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 ruleName is used to group all the rules that apply
|
|
''' to a specific field, property or concept. All rules applying
|
|
''' to the field or property should have the same rule name. When
|
|
''' rules are checked, they can be checked globally or for a
|
|
''' specific ruleName.
|
|
''' </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="ruleName">
|
|
''' A user-friendly identifier for the field/property
|
|
''' to which the rule applies.
|
|
''' </param>
|
|
Public Sub AddRule(ByVal handler As RuleHandler, ByVal ruleName As String)
|
|
|
|
' get the ArrayList (if any) from the Hashtable
|
|
Dim list As ArrayList = GetRulesForName(ruleName)
|
|
|
|
' we have the list, add our new rule
|
|
list.Add(New RuleMethod(mTarget, handler, ruleName, RuleArgs.Empty))
|
|
|
|
End Sub
|
|
|
|
''' <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 ruleName is used to group all the rules that apply
|
|
''' to a specific field, property or concept. All rules applying
|
|
''' to the field or property should have the same rule name. When
|
|
''' rules are checked, they can be checked globally or for a
|
|
''' specific ruleName.
|
|
''' </para>
|
|
''' </remarks>
|
|
''' <param name="handler">The method that implements the rule.</param>
|
|
''' <param name="ruleName">
|
|
''' A user-friendly identifier for the field/property
|
|
''' to which the rule applies.
|
|
''' </param>
|
|
''' <param name="ruleArgs">A RuleArgs object containing data
|
|
''' to be passed to the method implementing the rule.</param>
|
|
Public Sub AddRule(ByVal handler As RuleHandler, ByVal ruleName As String, ByVal ruleArgs As RuleArgs)
|
|
|
|
' get the ArrayList (if any) from the Hashtable
|
|
Dim list As ArrayList = GetRulesForName(ruleName)
|
|
|
|
' we have the list, add our new rule
|
|
list.Add(New RuleMethod(mTarget, handler, ruleName, ruleArgs))
|
|
|
|
End Sub
|
|
|
|
''' <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 ruleName is used to group all the rules that apply
|
|
''' to a specific field, property or concept. All rules applying
|
|
''' to the field or property should have the same rule name. When
|
|
''' rules are checked, they can be checked globally or for a
|
|
''' specific ruleName.
|
|
''' </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="ruleName">
|
|
''' A user-friendly identifier for the field/property
|
|
''' to which the rule applies.
|
|
''' </param>
|
|
''' <param name="propertyName">
|
|
''' The property name on the target object where the rule implementation can retrieve
|
|
''' the value to be validated.
|
|
''' </param>
|
|
Public Sub AddRule(ByVal handler As RuleHandler, ByVal ruleName As String, ByVal propertyName As String)
|
|
|
|
' get the ArrayList (if any) from the Hashtable
|
|
Dim list As ArrayList = GetRulesForName(ruleName)
|
|
|
|
' we have the list, add our new rule
|
|
list.Add(New RuleMethod(mTarget, handler, ruleName, propertyName))
|
|
|
|
End Sub
|
|
|
|
#End Region
|
|
|
|
#Region " Checking Rules "
|
|
|
|
''' <summary>
|
|
''' Checks all the rules for a specific ruleName.
|
|
''' </summary>
|
|
''' <param name="ruleName">The ruleName to be validated.</param>
|
|
Public Sub CheckRules(ByVal ruleName As String)
|
|
Dim list As ArrayList
|
|
|
|
' get the list of rules to check
|
|
list = CType(RulesList.Item(ruleName), ArrayList)
|
|
If list Is Nothing Then Exit Sub
|
|
|
|
' now check the rules
|
|
Dim rule As RuleMethod
|
|
For Each rule In list
|
|
If rule.Invoke() Then
|
|
UnBreakRule(rule)
|
|
Else
|
|
BreakRule(rule)
|
|
End If
|
|
Next
|
|
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Checks all the rules for a target object.
|
|
''' </summary>
|
|
Public Sub CheckRules()
|
|
|
|
' get the rules for each rule name
|
|
Dim de As DictionaryEntry
|
|
For Each de In RulesList
|
|
|
|
Dim list As ArrayList
|
|
|
|
list = CType(de.Value, ArrayList)
|
|
|
|
' now check the rules
|
|
Dim rule As RuleMethod
|
|
For Each rule In list
|
|
If rule.Invoke() Then
|
|
UnBreakRule(rule)
|
|
Else
|
|
BreakRule(rule)
|
|
End If
|
|
Next
|
|
Next
|
|
|
|
End Sub
|
|
|
|
Private Sub UnBreakRule(ByVal rule As RuleMethod)
|
|
If rule.RuleArgs.PropertyName Is Nothing Then
|
|
Assert(rule.ToString, "", False)
|
|
Else
|
|
Assert(rule.ToString, "", rule.RuleArgs.PropertyName, False)
|
|
End If
|
|
End Sub
|
|
|
|
Private Sub BreakRule(ByVal rule As RuleMethod)
|
|
If rule.RuleArgs.PropertyName Is Nothing Then
|
|
Assert(rule.ToString, rule.Description, True)
|
|
Else
|
|
Assert(rule.ToString, rule.Description, rule.RuleArgs.PropertyName, True)
|
|
End If
|
|
End Sub
|
|
|
|
#End Region
|
|
|
|
#End Region ' Rule Manager
|
|
|
|
#Region " Assert methods "
|
|
|
|
''' <summary>
|
|
''' This method is called by business logic within a business class to
|
|
''' indicate whether a business rule is broken.
|
|
''' </summary>
|
|
''' <remarks>
|
|
''' Rules are identified by their names. The description field is merely a
|
|
''' comment that is used for display to the end user. When a rule is marked as
|
|
''' broken, it is recorded under the rule name value. To mark the rule as not
|
|
''' broken, the same rule name must be used.
|
|
''' </remarks>
|
|
''' <param name="Rule">The name of the business rule.</param>
|
|
''' <param name="Description">The description of the business rule.</param>
|
|
''' <param name="IsBroken">True if the value is broken, False if it is not broken.</param>
|
|
Public Sub Assert(ByVal Rule As String, ByVal Description As String, ByVal IsBroken As Boolean)
|
|
If IsBroken Then
|
|
mBrokenRules.Add(Rule, Description)
|
|
Else
|
|
mBrokenRules.Remove(Rule)
|
|
End If
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' This method is called by business logic within a business class to
|
|
''' indicate whether a business rule is broken.
|
|
''' </summary>
|
|
''' <remarks>
|
|
''' Rules are identified by their names. The description field is merely a
|
|
''' comment that is used for display to the end user. When a rule is marked as
|
|
''' broken, it is recorded under the rule name value. To mark the rule as not
|
|
''' broken, the same rule name must be used.
|
|
''' </remarks>
|
|
''' <param name="Rule">The name of the business rule.</param>
|
|
''' <param name="Description">The description of the business rule.</param>
|
|
''' <param name="Property">The property affected by the business rule.</param>
|
|
''' <param name="IsBroken">True if the value is broken, False if it is not broken.</param>
|
|
Public Sub Assert(ByVal Rule As String, ByVal Description As String, ByVal [Property] As String, ByVal IsBroken As Boolean)
|
|
If IsBroken Then
|
|
mBrokenRules.Add(Rule, Description, [Property])
|
|
Else
|
|
mBrokenRules.Remove(Rule)
|
|
End If
|
|
End Sub
|
|
|
|
#End Region
|
|
|
|
#Region " Status retrieval "
|
|
|
|
''' <summary>
|
|
''' Returns a value indicating whether there are any broken rules
|
|
''' at this time. If there are broken rules, the business object
|
|
''' is assumed to be invalid and False is returned. If there are no
|
|
''' broken business rules True is returned.
|
|
''' </summary>
|
|
''' <returns>A value indicating whether any rules are broken.</returns>
|
|
Public ReadOnly Property IsValid() As Boolean
|
|
Get
|
|
Return mBrokenRules.Count = 0
|
|
End Get
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Returns a value indicating whether a particular business rule
|
|
''' is currently broken.
|
|
''' </summary>
|
|
''' <param name="Rule">The name of the rule to check.</param>
|
|
''' <returns>A value indicating whether the rule is currently broken.</returns>
|
|
Public Function IsBroken(ByVal Rule As String) As Boolean
|
|
Return mBrokenRules.Contains(Rule)
|
|
End Function
|
|
|
|
''' <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 Function GetBrokenRules() As RulesCollection
|
|
Return mBrokenRules
|
|
End Function
|
|
|
|
|
|
''' <summary>
|
|
''' Returns the text of all broken rule descriptions, each
|
|
''' separated by cr/lf.
|
|
''' </summary>
|
|
''' <returns>The text of all broken rule descriptions.</returns>
|
|
Public Overrides Function ToString() As String
|
|
Dim obj As New System.Text.StringBuilder
|
|
Dim item As Rule
|
|
Dim first As Boolean = True
|
|
|
|
For Each item In mBrokenRules
|
|
If first Then
|
|
first = False
|
|
Else
|
|
obj.Append("|") 'Modified by John to be pipe delimited for separation and localization in UI level
|
|
End If
|
|
obj.Append(item.Description)
|
|
Next
|
|
Return obj.ToString
|
|
End Function
|
|
|
|
#End Region
|
|
|
|
End Class
|