Search code examples
c#.netvb.netcom+

Disposal of Shared members in a ServicedComponent with ActivationOption.Server


For several reasons I need to create a COM+ component in .Net Framework 4. The intent is to host the component in its own process (dllhost.exe), hence the usage of ActivationOption.Server.

My component code needs to persist data between object activations, which is maintained by a worker thread. This worker thread and its data are held in static (shared) members of my base class. The shared data is independent of the caller, its security context, transactions, etc. Also, the worker thread performs background processing on the data.

I need to clean up the data and orderly terminate the worker thread when the dllhost process is disposed. Since there are no static (shared) destructors, I don't know how to do it. Is there anything I could implement while inheriting ServicedComponent? Any other ideas? Thank you.

Here's some code to start:

Imports System.EnterpriseServices

<Assembly: ApplicationName("MySender")> 
<Assembly: ApplicationActivation(ActivationOption.Server)> 

<ClassInterface(ClassInterfaceType.None), ProgId("MySender.Sender")> _
<Transaction(EnterpriseServices.TransactionOption.NotSupported)> _
Public Class Sender

    Inherits ServicedComponent
    Implements SomeLib.IMsgSender

    Shared worker As myWorker
    Shared sync As New Object

    Public Sub MyInstanceMethod(msg as string) Implements SomeLib.IMsgSender.SendMessage

        SyncLock sync
            If worker Is Nothing Then
                worker = New myWorker
                worker.StartThread()
            End If
        End SyncLock

        worker.Process(msg)

    End Sub

    'Something like this does not exist!'
    Shared Sub Dispose() 

        SyncLock sync
            If worker IsNot Nothing Then
                worker.StopThread()
            End If
        End SyncLock

    End Sub

End Class

Solution

  • The AppDomain.ProcessExit event will fire before unloading the domain. If the code to run doesn't take too long, it could be used like this:

    Imports System.EnterpriseServices
    
    <Assembly: ApplicationName("MySender")> 
    <Assembly: ApplicationActivation(ActivationOption.Server)>
    
    <ClassInterface(ClassInterfaceType.None), ProgId("MySender.Sender")> _
    <Transaction(EnterpriseServices.TransactionOption.NotSupported)> _
    Public Class Sender
    
        Shared Sub New
    
            AddHandler AppDomain.CurrentDomain.ProcessExit, AddressOf MyDisposalCode
    
        End Sub
    
        '....
    
        Shared Sub MyDisposalCode(sender as Object, e as EventArgs)
    
            'My disposal code
    
        End Sub
    
    End Class
    

    It's important to notice that .Net will enforce a 2 second timeout on this code.