public static I CreateInstance(string instanceId, Connection connection, SendReceiveOptions options) { lock (cacheLocker) { var key = new CachedRPCKey(instanceId, connection, typeof(I)); if (cachedInstances.ContainsKey(key)) { return((I)cachedInstances[key]); } //Create the instance var res = (I)Activator.CreateInstance(Type, instanceId, connection, options, typeof(I), Client.DefaultRPCTimeout); Dictionary <string, FieldInfo> eventFields = new Dictionary <string, FieldInfo>(); foreach (var ev in typeof(I).GetEvents()) { eventFields.Add(ev.Name, Type.GetField(ev.Name, BindingFlags.NonPublic | BindingFlags.Instance)); } //Add the packet handler to deal with incoming event firing connection.AppendIncomingPacketHandler <RemoteCallWrapper>(typeof(I).Name + "-RPC-LISTENER-" + instanceId, (header, internalConnection, eventCallWrapper) => { try { //Let's do some basic checks on the data we've been sent if (eventCallWrapper == null || !eventFields.ContainsKey(eventCallWrapper.name)) { return; } var del = eventFields[eventCallWrapper.name].GetValue(res) as Delegate; var sender = eventCallWrapper.args[0].UntypedValue; var args = eventCallWrapper.args[1].UntypedValue; del.DynamicInvoke(sender, args); } catch (Exception) { } }); connection.AppendIncomingPacketHandler <string>(typeof(I).Name + "-RPC-DISPOSE-" + instanceId, (header, internalConnection, eventCallWrapper) => { (res as IRPCProxy).Dispose(); }); cachedInstances[key] = res; return(res); } }
/// <summary> /// Causes the provided <see cref="IRPCProxy"/> instance to be disposed /// </summary> /// <param name="clientObject">The <see cref="IRPCProxy"/> to dispose</param> public static void DestroyRPCClient(IRPCProxy clientObject) { if (!clientObject.IsDisposed) { clientObject.GetType().GetField("isDisposed", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(clientObject, true); var connection = clientObject.ServerConnection; if (connection.ConnectionInfo.ConnectionState != ConnectionState.Shutdown) { string packetTypeRequest = clientObject.ImplementedInterface.Name + "-REMOVE-REFERENCE-" + clientObject.ServerInstanceID; RemoteCallWrapper wrapper = new RemoteCallWrapper(); wrapper.args = new List <RPCArgumentBase>(); wrapper.name = null; wrapper.instanceId = clientObject.ServerInstanceID; //Tell the server that we are no longer listenning try { connection.SendObject <RemoteCallWrapper>(packetTypeRequest, wrapper); } catch (Exception) { } //Next remove the event packet handler try { connection.RemoveIncomingPacketHandler(clientObject.ImplementedInterface.Name + "-RPC-LISTENER-" + clientObject.ServerInstanceID); } catch (Exception) { } //Next remove the server side dispose handler try { connection.RemoveIncomingPacketHandler(clientObject.ImplementedInterface.Name + "-RPC-DISPOSE-" + clientObject.ServerInstanceID); } catch (Exception) { } } //Finally remove the object from the cache. This guarentees that if we try to get the instance again at some time in the future //we won't end up with a disposed RPC object lock (cacheLocker) { var cacheKey = new CachedRPCKey(clientObject.ServerInstanceID, clientObject.ServerConnection, clientObject.ImplementedInterface); try { cachedInstances.Remove(cacheKey); } catch (Exception) { } } } }