Control Exceptions: VB: Intercept Exceptions: Listing 1
The Data property of System.Exception lets you add key value pairs that contain additional information you think will be useful to your debugging and maintenance. The exception call stack will include the ExceptionFactory methods, but you can also make the stack report the location of a failure by assuming the exception is thrown outside the ExceptionFactory class and allowing helper functions to state explicitly how many stack frames to ignore. For example, CheckCast ignores itself by passing a value of 1.
Public NotInheritable Class ExceptionFactory
Private Sub New()
End Sub
Public Shared Function CreateInvalidCastException( _
ByVal guid As Guid, _
ByVal id As ExceptionId, _
ByVal skipFrames As Int32, _
ByVal className As String, _
ByVal variableName As String, _
ByVal ParamArray dataItems() _
As KeyValuePair(Of String, Object)) _
As Exception
Return CreateException( _
Of System.InvalidCastException)( _
guid, id, skipFrames, _
New KeyValuePair(Of String, Object _
)() {New KeyValuePair(Of String, Object)( _
"ClassName", className)}, _
New KeyValuePair(Of String, _
Object)() {New KeyValuePair(Of String, _
Object)("VariableName", variableName)}, _
dataItems)
End Function
' Other exceptions as desired
Private Shared Function CreateException _
(Of T As {New, System.Exception}) _
(ByVal guid As Guid, _
ByVal id As ExceptionId, _
ByVal skipFrames As Int32, _
ByVal dataPairs As KeyValuePair( _
Of String, Object)(), ByVal _
ParamArray dataItems() As Object) _
As Exception
' Exceptions happen to have a public constructor,
' so we can use the new constraint.
Dim ex As New T
Dim methodBase = FindCallingMethod(skipFrames)
ex.Data.Add("Class", methodBase.DeclaringType)
ex.Data.Add("Method", methodBase.Name)
ex.Data.Add("Correlation", guid)
ex.Data.Add("MessageId", id)
ex.Data.Add("MessageIdName", id.ToString)
If dataPairs IsNot Nothing Then
For Each dataPair In dataPairs
ex.Data.Add(dataPair.Key, dataPair.Value)
Next
End If
Return ex
End Function
Private Shared Function FindCallingMethod( _
ByVal skipFrames As Int32) As Reflection.MethodBase
Dim frames = New Diagnostics.StackTrace( _
).GetFrames()
Dim framePosition = PositionFirstFrameNotInClass( _
frames)
Return frames(framePosition + _
skipFrames).GetMethod()
End Function
Private Shared Function _
PositionFirstFrameNotInClass( _
ByVal frames As StackFrame()) As Int32
Dim framePos As Int32 = 1
' We know this frame is in the class
Do While True
If frames(framePos).GetMethod.DeclaringType _
IsNot GetType(ExceptionFactory) Then
Return framePos
End If
framePos += 1
Loop
Return -1
End Function
End Class
Public Enum ExceptionId
None
TryCastFailed
NotAuthorizedToAdd
NotAuthorizedToEdit
MustOverrideMember
ApparentRecursion
SearchValueNotConverted
DataIsMissing
End Enum