I created a duplex service (NetTcpBinding) like this example: I used the publish-subscribe pattern, and for each connection request from a new client, it creates a new instance of the service (containing a different callback). In this example, the callback is invoked through events and delegates.
Now I would like to change this example: suppose we do not want to respond immediately to client’s request, that is, suppose we want to invoke the callback method after a certain time interval. In this case I need to maintain a reference to the method of the callback… But what happens if in the meantime some client disconnects? The service instance is destroyed and we lose even the callback…
I wrote this example:
MySingletonTableis the data structure that stores the references to the methods of the callbacks;-
SampleServiceis not a service, but simulates the instance of a service;public delegate void ProcessingHandler(string item, double price, double change); public class MySingletonTable { private static volatile MySingletonTable m_Instance; private static object syncRoot = new object(); private static Dictionary<string, ProcessingHandler> pointersToHandlers; private MySingletonTable() { pointersToHandlers = new Dictionary<string, ProcessingHandler>(); } // Return the singleton instance of this class. public static MySingletonTable Instance { get { if (m_Instance == null) { lock (syncRoot) { if (m_Instance == null) m_Instance = new MySingletonTable(); } } return m_Instance; } } /// The number of the entries in the table. public int Count { get { lock (syncRoot) { return pointersToHandlers.Count; } } } // Add an handler. public void Add(string id, ProcessingHandler handler) { lock (syncRoot) { if (!pointersToHandlers.ContainsKey(id)) pointersToHandlers.Add(id, handler); } } // Get an handler from the table. public ProcessingHandler GetHandler(string id) { ProcessingHandler handler = null; lock (syncRoot) { if (pointersToHandlers.ContainsKey(id)) handler = pointersToHandlers[id]; } return handler; } // Remove the specified handler. public bool Remove(string id) { lock (syncRoot) { return pointersToHandlers.Remove(id); } } } // This class simulates the service. public class SampleService { private static int counter = 0; private int service_i = ++counter; MySingletonTable reference = MySingletonTable.Instance; public SampleService(string id) { reference.Add(id, PriceChange); } private void PriceChange(string item, double price, double change) { // call the callback // ... Console.WriteLine("service_i {0}: {1} {2} {3}", service_i, item, price, change); } } class Program { static void Main(string[] args) { SampleService s1 = new SampleService("abc"); SampleService s2 = new SampleService("def"); MySingletonTable table = MySingletonTable.Instance; ProcessingHandler handler = null; handler = table.GetHandler("abc"); handler("item one", 10, 20); handler = table.GetHandler("def"); handler("item two", 30, 40); Console.ReadLine(); } }
Obviously I can not explicitly destroy the two service instances simulated in this example. What would happen, however, if s1 and s2 were two instances of a service related to two different clients?
If your delegate is stored in pointersToHandlers, then this will be holding onto your object so it is never going to be garbage collected, or as you call it, ‘destroyed’. Effectively, you also have a memory leak right now.
You will need to remove the delegate from the list when clients disconnect (or whenever you are expecting the object to be destroyed). Not sure why you are not using events, but that is another question. Even if you do use events, you will still need to disconnect once you are done so that you dont end up with this situation.