[en] Events keep firing after host is disposed (solved)

Topics: Technical Support
Feb 29, 2012 at 9:27 AM
Edited Feb 29, 2012 at 9:29 AM

Good morning to everyone.

My test environment contains a windows service and a taskbar application. The service exposes a singleton which fires an event every 5 seconds (using a timer), the problem is that even if i unregister the component and dispose the host the client keeps receiving events...

//Server Start
var protocolSetup = new IpcBinaryServerProtocolSetup("TaskBarClient");
host = new ZyanComponentHost("Agent", protocolSetup);
host.RegisterComponent<ITrayServer>"ITrayServer", () => _TrayServer, 
ActivationType.Singleton, null);

//Server Stop
host.UnregisterComponent("ITrayServer");
var components = host.GetRegisteredComponents(); //Just a check, nothing is registered
host.Dispose();
//Contract
public interface ITrayServer
{
     string Test();
     event Action<string> Notify;
}
Notice that _TrayServer is not yet disposed, only unregistered from host.

Coordinator
Feb 29, 2012 at 7:58 PM
Edited Feb 29, 2012 at 7:59 PM

Hi gmav,

that's right: as long as your TrayServer's timer is not disposed of, it will keep on firing events.

Unregistering the component and even disposing of ZyanComponentHost doesn't shut down the communication infrastructure itself (.NET Remoting channel that works behind the scenes).

If you want your server to stop delivering events, you should either stop the timer, or clear all subscriptions.

Feb 29, 2012 at 8:18 PM

Ok got it, thanks yallie

Coordinator
Mar 1, 2012 at 6:47 AM
Edited Mar 1, 2012 at 6:59 AM

@yallie: You were faster :)

Hi gmav,

this behavior feels like a bug, but it´s correct. When the host is disposed, the registered underlying remoting channel is unregistered properly. StopListening is invoked on the server channel, so the channel stops listening for client requests. But the IPC channel is not killed at this time, even if it doesn´t accept any new client requests. The channel is still in use by a alive object. This object cannot receive and handle new method calls, but it can still send responses. The Notify callback invocation is such a response.

Abrupt cutting off all wires may lead to an inconsitent system. 

Your issue can be solved easily with lifetime control features of Zyan. If I understood everything right, you don´t want to dispose your TrayServer component but notification of clients should be stopped, when the host is disposed. This can be done inside a cleap-up handler. Such a clean-up handler can be specified on the RegisterComponent method. 

Example:

 

host.RegisterComponent<ITrayServer>("ITrayServer", 
                                    () => trayServer, 
                                    ActivationType.Singleton, 
                                    instance => ((TrayServer)instance).DisconnectNotificationClients()); // <-- Clean-up handler

 

Code of the TrayServer.DisconnectNotificationClients Method:

 

public void DisconnectNotificationClients()
{
    if (Notify != null)
        Notify = null;
}

 

Note that this method isn´t part of the ITrayServer interface and so it is not visible to clients.

There is another thing you must do, that my suggested solution works. Don´t call UnregisterComponent before host.Dispose(). Unregistering a component means removal of the component from the component catalog. Zyan has no control over the component anymore if you unregister it, and so your clean-up handler is never called.

Another approach is to implement IDisposable in your component. Zyan automaticly calls the Dispose method, when the host is dispose.

If you want to manually start clean-up for a specified component, you should use the CleanUpComponentInstance method of the ComponentCatalog. Remember that component lifetime isn´t controlled by ZyanComponentHost. It´s controlled by ComponentCatalog. By default, the ComponentCatalog is created by ZyanComponentHost and the DisposeWithHost property is set to true. But there are scenarios where you may want to decouple catalog and host. Imagine a ComponentCatalog instance that is published by many different host (with different protocols).