Custom Exceptions and .NET Remoting
Even though Remoting supports "High Type Fidelity", transferring custom Exceptions over Remoting boundaries
comes with its very own challenge: using [Serializable] is not enough
because the base class (System.Exception or
System.ApplicationException) already implements ISerializable. If you
want to pass your custom Exceptions over Remoting
boundaries, you therefore have to override GetObjectData() and provide a
custom constructor for deserialization. And don't forget to call
MyBase.GetObjectData() (or base.GetObjectData() in C#)!
Please also note that your custom Exception has to be deployed to a
shared DLL which is copied to, and referenced from, your client and
server applications. It doesn't suffice to simply copy and paste the
source code to your client and server project!
Any custom Exception you develop should be based on the following
skeleton:
Imports System
Imports System.Runtime.Serialization
<Serializable()> _
Public Class MyException
Inherits System.ApplicationException
Public Sub New(ByVal message As String)
MyBase.New(message)
End Sub
Public Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
MyBase.New(info, context)
End Sub
Public Overrides Sub GetObjectData(ByVal info As SerializationInfo, ByVal context As StreamingContext)
MyBase.GetObjectData(info, context)
End Sub
End Class
If you want to transfer custom information with your Exception, you
have to add them to the SerializationInfo-object on the call to
GetObjectData() and to take them from this object in the secondary
constructor:
<Serializable()> _
Public Class ConcurrencyException
Inherits System.ApplicationException
Private _databaseTable As String
Public Sub New(ByVal message As String, ByVal databaseTable As String)
MyBase.New(message)
_databaseTable = databaseTable
End Sub
Public Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
MyBase.New(info, context)
_databaseTable = info.GetString("_databaseTable")
End Sub
Public Overrides Sub GetObjectData(ByVal info As SerializationInfo, ByVal context As StreamingContext)
MyBase.GetObjectData(info, context)
info.AddValue("_databaseTable", _databaseTable)
End Sub
Public ReadOnly Property DatabaseTable() As String
Get
Return _databaseTable
End Get
End Property
End Class
If you wouldn't override GetObjectData() and/or don't provide the
additional constructor Public Sub New(info, context), you would
instead end up with a very different exception in your Catch-block:
The constructor to deserialize an object of type General.ConcurrencyException was not found.
This Exception simply indicates that the client-side of the Remoting
framework has not been able to correctly de-serialize your custom
Exception (called General.ConcurrencyException in this sample).
|