Bug in ServicedComponent.Dispose?

Tech-Archive recommends: Fix windows errors by optimizing your registry

From: Will (Will_at_discussions.microsoft.com)
Date: 06/23/04


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?



Relevant Pages

  • Re: Bug in ServicedComponent.Dispose?
    ... > I'm having a problem with a Serviced Component Try Finally Dispose ... ServicedComponentTestObject2 object: ", vbCrLf, vbCrLf, ex.ToString)) ... > Run the command line app and the two class libraries will register ...
    (microsoft.public.dotnet.framework.component_services)
  • Re: using AJAX when class instances get disposed after load
    ... ajax doesn't change the request/response nature of websites. ... client code making a server call, ... the consumer controls themselves get disposed ... but now I'm faced with trying to decide when to dispose them ...
    (microsoft.public.dotnet.framework.aspnet)
  • CCW and Dispose
    ... The problem is how I should manage the lifetime of the server. ... The client has to explicitly call Dispose ... The problem with Dispose is when the clients terminate unexpectedly ... remains on the module and the exe server never exits. ...
    (microsoft.public.dotnet.framework.interop)
  • Dont how to release server when using C# COM object
    ... The problem is how I should manage the lifetime of the server. ... The client has to explicitly call Dispose ... The problem with Dispose is when the clients terminate unexpectedly ... remains on the module and the exe server never exits. ...
    (microsoft.public.dotnet.framework.interop)
  • Re: ADAM - The Server is not operational
    ... i had a look at what reflector gives me for the dispose method of the ... DirectoryEntry. ... Unless there is some magic happening whereby connections are reused under ... the limit is around 300 concurrent connections to the ADAM server ...
    (microsoft.public.windows.server.active_directory)