Hi,
I have a quite large tree of business objects. Sometimes when I call Save() on the root object, I get the IsValid == false because some object in the tree is invalid or maybe more. I want to know if there is a pattern or guideline on how to quickly find the object that is invalid other than scrolling down the tree looking for the IsValid in the debug visualizer.
Thanks,
George B
You know, I very much see where you're coming from with your post as I've had to really scour the object graph in debug to figure out exactly why something wasn't valid. I don't know of any inherent way to do so, but it would probably not be unreasonable to provide this sort of support in your company's business base if you find this scenario happening very often where you're spending lots of time hunting for invalid objects.
I'm sure you could likely use reflection to hop through the object graph when the root's IsValid is false.
Obviously multiple objects could potentially be invalid too.
If anyone is interested, I wrote a helper class that can examine
an object graph and output combine error message. Feel free to modify it
and adapt it to your needs.
Imports System.ComponentModel
Public Class
CSLABusinessObjectErrorTextExaminer
Private
Sub New()
End
Sub
''' <summary>
''' Get
text for errors if object is invalid
''' </summary>
''' <returns>Error text
for invalid object</returns>
''' <remarks></remarks>
Public
Shared Function
GetErrorInformation(ByVal target As Object) As String
Dim inspectedObjects As
New Collections.Generic.List(Of String)
Return GetErrorInformation(target, inspectedObjects)
End
Function
''' <summary>
''' Get
text for errors for one object based on IDataErrorInfo interface
''' </summary>
''' <param name="target">Object to get error text for</param>
''' <param name="inspectedObjects">List of hash codes of objects that are inspected.
'''
This is necessary to avoid infinite recursion.
''' </param>
''' <returns>Text for
errors for one object based on IDataErrorInfo interface</returns>
''' <remarks></remarks>
Private
Shared Function
GetErrorInformation(ByVal target As Object, ByVal inspectedObjects As
Collections.Generic.List(Of String)) As String
Dim returnValue As New Text.StringBuilder()
Dim targetID As String = String.Empty
If target IsNot Nothing Then
targetID = target.GetType.ToString & ":"
& target.GetHashCode().ToString
End If
If target IsNot Nothing AndAlso Not inspectedObjects.Contains(targetID) Then
inspectedObjects.Add(targetID)
If TypeOf
target Is IBindingList Then
' check error messages for each row in the list
For oneItem As Integer = 0 To CType(target, IBindingList).Count - 1
If TypeOf CType(target, IBindingList)(oneItem) Is Csla.Core.BusinessBase Then
Dim itemError As
String = GetErrorInformation(CType(target, IBindingList)(oneItem), inspectedObjects)
' if we do not have this message already, add it
If itemError.Length > 0 AndAlso Not
returnValue.ToString.Contains(itemError) Then
returnValue.Append(itemError)
returnValue.Append(Environment.NewLine)
End If
End If
Next
Else
If TypeOf
target Is Csla.Core.BusinessBase Then
' run through broken rules collection for this object
For Each
oneBrokenRule As Csla.Validation.BrokenRule In CType(target,
Csla.Core.BusinessBase).BrokenRulesCollection
' if we do not have this message already, add it
If Not
returnValue.ToString.Contains(oneBrokenRule.Description) Then
returnValue.Append(oneBrokenRule.Description)
returnValue.Append(Environment.NewLine)
End If
Next
' get list of properties for this object
Dim properties() As
System.Reflection.PropertyInfo = target.GetType.GetProperties()
For Each
oneProperty As System.Reflection.PropertyInfo In properties
' get object that sits on this property
If Not
oneProperty.PropertyType.IsPrimitive AndAlso
oneProperty.GetIndexParameters().Length = 0 Then
Dim
propTarget As Object
= oneProperty.GetValue(target, Nothing)
' call this procedure resursively to get error for
property based object
Dim propErrorText As
String = GetErrorInformation(propTarget,
inspectedObjects)
' if we do not have this message already, add it
If propErrorText.Length > 0 AndAlso Not
returnValue.ToString.Contains(propErrorText) Then
returnValue.Append(propErrorText)
returnValue.Append(Environment.NewLine)
End If
End If
Next
End If
End If
End If
' strip out duplicate carriage returns before returning the
value.
Return
returnValue.ToString.Replace(Environment.NewLine & Environment.NewLine,
Environment.NewLine)
End
Function
End Class
Sergey Barskiy
Senior Consultant
office: 678.405.0687 |
mobile: 404.388.1899
Microsoft Worldwide Partner of the Year | Custom
Development Solutions, Technical Innovation
From: skagen00
[mailto:cslanet@lhotka.net]
Sent: Monday, April 14, 2008 8:56 AM
To: Sergey Barskiy
Subject: Re: [CSLA .NET] Design question... How to identify
IsValid==false in a large tree of BOs
You know, I very much see where you're coming from with your post as I've
had to really scour the object graph in debug to figure out exactly why
something wasn't valid. I don't know of any inherent way to do so, but it would
probably not be unreasonable to provide this sort of support in your company's
business base if you find this scenario happening very often where you're
spending lots of time hunting for invalid objects.
I'm sure you could likely use reflection to hop through the object graph
when the root's IsValid is false.
Obviously multiple objects could potentially be invalid too.
Hi,
Thanks for your ideas... I'll check the solutions and I'll post my results...
Regards,
George B
Copyright (c) Marimer LLC