/// <summary> /// Private method for simplifying the remote procedure call. I don't want to write this in IL!! /// </summary> /// <param name="clientObject"></param> /// <param name="functionToCall"></param> /// <param name="args"></param> /// <returns></returns> public static object RemoteCallClient(IRPCProxy clientObject, string functionToCall, object[] args) { if (!clientObject.IsDisposed) { var connection = clientObject.ServerConnection; RemoteCallWrapper wrapper = new RemoteCallWrapper(); wrapper.args = (from arg in args select RPCArgumentBase.CreateDynamic(arg)).ToList(); wrapper.name = functionToCall; wrapper.instanceId = clientObject.ServerInstanceID; var guid = ShortGuid.NewGuid(); string packetTypeRequest = clientObject.ImplementedInterface.Name + "-RPC-CALL-" + wrapper.instanceId; string packetTypeResponse = packetTypeRequest + "-" + guid; SendReceiveOptions options = clientObject.SendReceiveOptions; clientObject.RPCTimeout = 500000; if (options != null) { wrapper = connection.SendReceiveObject <RemoteCallWrapper, RemoteCallWrapper>(packetTypeRequest, packetTypeResponse, clientObject.RPCTimeout, wrapper, options, options); } else { wrapper = connection.SendReceiveObject <RemoteCallWrapper, RemoteCallWrapper>(packetTypeRequest, packetTypeResponse, clientObject.RPCTimeout, wrapper); } if (wrapper.Exception != null) { throw new RPCException(wrapper.Exception); } for (int i = 0; i < args.Length; i++) { args[i] = wrapper.args[i].UntypedValue; } if (wrapper.result != null) { return(wrapper.result.UntypedValue); } else { return(null); } } else { throw new ObjectDisposedException("clientObject", "RPC object has already been disposed of and cannot be reused"); } }
private static EventHandler <A> GenerateEvent <A>(Connection clientConnection, string instanceId, Type interfaceType, string eventName) where A : EventArgs { return(new EventHandler <A>((sender, args) => { var packetType = interfaceType.Name + "-RPC-LISTENER-" + instanceId; RemoteCallWrapper callWrapper = new RemoteCallWrapper(); callWrapper.name = eventName; callWrapper.instanceId = instanceId; callWrapper.args = new List <RPCArgumentBase>() { RPCArgumentBase.CreateDynamic(sender), RPCArgumentBase.CreateDynamic(args) }; clientConnection.SendObject(packetType, callWrapper); })); }
/// <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) { } } } }
private static void RPCDisconnectHandler <T, I>(PacketHeader header, Connection connection, RemoteCallWrapper wrapper) where T : I { lock (locker) { if (!RPCObjectsById.ContainsKey(wrapper.instanceId)) { return; } var rpcObject = RPCObjectsById[wrapper.instanceId]; rpcObject.RemoveClientSubscription(connection); } }
private static void RunRPCFunctionHandler <T, I>(PacketHeader header, Connection connection, RemoteCallWrapper wrapper) where T : I { I instance = default(I); MethodInfo funcRef = typeof(I).GetMethod(wrapper.name); try { lock (locker) { instance = (I)(RPCObjectsById[wrapper.instanceId].RPCObject); } } catch (Exception) { wrapper.result = null; wrapper.Exception = "SERVER SIDE EXCEPTION\n\n" + "Invalid instanceID" + "\n\nEND SERVER SIDE EXCEPTION\n\n"; connection.SendObject(header.PacketType, wrapper); return; } object[] args = null; if (wrapper.args == null) { args = new object[0]; } else { args = (from arg in wrapper.args select arg.UntypedValue).ToArray(); } try { wrapper.result = RPCArgumentBase.CreateDynamic(funcRef.Invoke(instance, args)); wrapper.args = (from arg in args select RPCArgumentBase.CreateDynamic(arg)).ToList(); } catch (Exception e) { wrapper.result = null; if (e.InnerException != null) { e = e.InnerException; } wrapper.Exception = "SERVER SIDE EXCEPTION\n\n" + e.ToString() + "\n\nEND SERVER SIDE EXCEPTION\n\n"; } string returnPacketType = header.GetOption(PacketHeaderStringItems.RequestedReturnPacketType); connection.SendObject(returnPacketType, wrapper); }