Bug in ServicedComponent.Dispose?
From: Will (Will_at_discussions.microsoft.com)
Date: 06/23/04
- Next message: Stan: "Is it ok not to re-register a serviced component in COM+ when interface changes?"
- Previous message: Michael: "Having trouble with COM+ Object Pool and Windows2003 Server"
- Next in thread: Stan: "Re: Bug in ServicedComponent.Dispose?"
- Reply: Stan: "Re: Bug in ServicedComponent.Dispose?"
- Messages sorted by: [ date ] [ thread ]
Date: Wed, 23 Jun 2004 05:27:02 -0700
I'm having a problem with a Serviced Component Try Finally Dispose pattern.
When running in a server application, disposing the object after it has called SetAbort throws:
[COMException (0x8004e003): You made a method call on a COM+ component that has a transaction that has already aborted or in the process of aborting.]
I understand that when the object calls SetAbort, it is indicating that it is done and COM+ will deactivate the object.
However, an IDisposible component should be disposed by the client that created it. That's just a good practice, right?
This problem only occurs if the object is in a server application and it is not the object that started the transaction (I think).
To reproduce the problem, create three projects.
One class library project containing this code (library must have a strong name):
<EnterpriseServices.Transaction(EnterpriseServices.TransactionOption.Required, Timeout:=0)> _
Public Class ServicedComponentTestObject2
Inherits EnterpriseServices.ServicedComponent
Public Function Test() As Boolean
Dim result As Boolean
Try
If MsgBox("Throw exception in ServicedComponentTestObject2?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
Throw New Exception("Exception from ServicedComponentTestObject2")
Else
EnterpriseServices.ContextUtil.SetComplete()
result = True
End If
Catch ex As Exception
EnterpriseServices.ContextUtil.SetAbort()
Throw ex
End Try
Return result
End Function
End Class
Another class library project containing this code (library must have a strong name and a reference to the previous library):
<EnterpriseServices.Transaction(EnterpriseServices.TransactionOption.Required, Timeout:=0)> _
Public Class ServicedComponentTestObject
Inherits EnterpriseServices.ServicedComponent
Public Function Test() As Boolean
Dim result As Boolean
Try
Dim test2 As ServicedComponentTestObject2
test2 = New ServicedComponentTestObject2
Try
result = test2.Test()
If result Then
If MsgBox("Throw exception in ServicedComponentTestObject1?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
Throw New Exception("Exception from ServicedComponentTestObject")
Else
result = True
End If
End If
Finally
Try
EnterpriseServices.ServicedComponent.DisposeObject(test2)
Catch ex As Exception
MsgBox(String.Concat("Failed to dispose of ServicedComponentTestObject2 object: ", vbCrLf, vbCrLf, ex.ToString))
End Try
End Try
Catch ex As Exception
EnterpriseServices.ContextUtil.SetAbort()
Throw ex
End Try
Return result
End Function
End Class
And a command-line utility containing this code and referencing the library above:
Module ServicedComponentTestApp
Sub Main()
Try
Dim test As ServicedComponentTest.ServicedComponentTestObject
test = New ServicedComponentTest.ServicedComponentTestObject
Try
If test.Test() Then
MsgBox("Success")
End If
Finally
Try
EnterpriseServices.ServicedComponent.DisposeObject(test)
Catch ex As Exception
MsgBox(String.Concat("Failed to dispose of ServicedComponentTestObject object: ", vbCrLf, vbCrLf, ex.ToString))
End Try
End Try
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
End Module
Run the command line app and the two class libraries will register themselves in two COM+ packages. When prompted click Yes to the "Throw exception in ServicedComponentTestObject2" prompt. Note that the exception is returned to ServicedComponentTestObject and ServicedComponentTestObject successfully disposes of the ServicedComponentTestObject2 object. Now change the package containing ServicedComponentTestObject2 to a service application (NOTE you will probably need to disable access checks) and rerun the app. Now when you answer yes to the "Throw exception in ServicedComponentTestObject2" prompt and ServicedComponentTestObject tries to dispose of ServicedComponentTestObject2, the DisposeObject method throws:
[COMException (0x8004e003): You made a method call on a COM+ component that has a transaction that has already aborted or in the process of aborting.]
Note that there is not difference in behavior between DisposeObject and Dispose.
While the error is technically correct, shouldn't the client be able to dispose of the object? Using a try finally dispose pattern for an IDisposible object seems to be good programming but depending on how the component is served, the dispose may or may not work. This isn't good encapsulation because the client must know how the component is and whether it called SetAbort.
Is this a bug or am I missing something?
- Next message: Stan: "Is it ok not to re-register a serviced component in COM+ when interface changes?"
- Previous message: Michael: "Having trouble with COM+ Object Pool and Windows2003 Server"
- Next in thread: Stan: "Re: Bug in ServicedComponent.Dispose?"
- Reply: Stan: "Re: Bug in ServicedComponent.Dispose?"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|