/// <summary> /// Invokes the method with the specified parameters. /// </summary> /// <param name="metaData">Method name and parameter type names.</param> /// <param name="parameters">Parameters for the method call</param> /// <returns>An array of objects containing the return value (index 0) and the parameters used to call /// the method, including any marked as "ref" or "out"</returns> protected override object[] InvokeMethod(string metaData, params object[] parameters) { //prevent call to invoke method on more than one thread at a time lock (_syncRoot) { var useCrypto = null != _zkCrypto; var mdata = metaData.Split('|'); //write the message type _binWriter.Write((int)MessageType.MethodInvocation); //find the matching server side method ident var ident = -1; for (int index = 0; index < _syncInfo.MethodInfos.Length; index++) { var si = _syncInfo.MethodInfos[index]; //first of all the method names must match if (si.MethodName == mdata[0]) { //second of all the parameter types and -count must match if (mdata.Length - 1 == si.ParameterTypes.Length) { var matchingParameterTypes = true; for (int i = 0; i < si.ParameterTypes.Length; i++) { if (!mdata[i + 1].Equals(si.ParameterTypes[i])) { matchingParameterTypes = false; break; } } if (matchingParameterTypes) { ident = si.MethodIdent; break; } } } } if (ident < 0) { throw new Exception(string.Format("Cannot match method '{0}' to its server side equivalent", mdata[0])); } //write service key index _binWriter.Write(_syncInfo.ServiceKeyIndex); //write the method ident to the server _binWriter.Write(ident); //if encrypted, wrap up key index and params and send len then enc bytes if (useCrypto) { byte[] callData; using (var ms = new MemoryStream()) using (var bw = new BinaryWriter(ms)) { //send the parameters _parameterTransferHelper.SendParameters(_syncInfo.UseCompression, _syncInfo.CompressionThreshold, bw, parameters); callData = ms.ToArray(); } _logger.Debug("Unencrypted data sent to server: {0}", Convert.ToBase64String(callData)); var encData = _zkCrypto.Encrypt(callData); _binWriter.Write(encData.Length); _binWriter.Write(encData); _logger.Debug("Encrypted data sent to server: {0}", Convert.ToBase64String(encData)); } else { //send the parameters _parameterTransferHelper.SendParameters(_syncInfo.UseCompression, _syncInfo.CompressionThreshold, _binWriter, parameters); } _binWriter.Flush(); _stream.Flush(); // Read the result of the invocation. MessageType messageType = (MessageType)_binReader.ReadInt32(); if (messageType == MessageType.UnknownMethod) { throw new Exception("Unknown method."); } object[] outParams; if (useCrypto) { var len = _binReader.ReadInt32(); var encData = _binReader.ReadBytes(len); _logger.Debug("Encrypted data received from server: {0}", Convert.ToBase64String(encData)); var data = _zkCrypto.Decrypt(encData); _logger.Debug("Decrypted data received from server: {0}", Convert.ToBase64String(data)); using (var ms = new MemoryStream(data)) using (var br = new BinaryReader(ms)) { outParams = _parameterTransferHelper.ReceiveParameters(br); } } else { outParams = _parameterTransferHelper.ReceiveParameters(_binReader); } MethodSyncInfo methodSyncInfo = _syncInfo.MethodInfos[ident]; var returnType = methodSyncInfo.MethodReturnType.ToType(); if (IsTaskType(returnType) && outParams.Length > 0) { if (returnType.IsGenericType) { MethodInfo methodInfo = typeof(Task).GetMethod(nameof(Task.FromResult)) .MakeGenericMethod(new[] { returnType.GenericTypeArguments[0] }); outParams[0] = methodInfo.Invoke(null, new[] { outParams[0] }); } else { outParams[0] = Task.CompletedTask; } } if (messageType == MessageType.ThrowException) { throw (Exception)outParams[0]; } return(outParams); } }
private void ProcessInvocation(ZkSession session, BinaryReader binReader, BinaryWriter binWriter, Stopwatch sw) { //read service instance key var cat = "unknown"; var stat = "MethodInvocation"; int invokedServiceKey = binReader.ReadInt32(); ServiceInstance invokedInstance; if (_services.TryGetValue(invokedServiceKey, out invokedInstance)) { cat = invokedInstance.InterfaceType.Name; //read the method identifier int methodHashCode = binReader.ReadInt32(); if (invokedInstance.InterfaceMethods.ContainsKey(methodHashCode)) { MethodInfo method; invokedInstance.InterfaceMethods.TryGetValue(methodHashCode, out method); stat = method.Name; bool[] isByRef; invokedInstance.MethodParametersByRef.TryGetValue(methodHashCode, out isByRef); //read parameter data object[] parameters; if (_requireZk) { var len = binReader.ReadInt32(); var encData = binReader.ReadBytes(len); _log.Debug("Encrypted data received from server: {0}", Convert.ToBase64String(encData)); var data = session.Crypto.Decrypt(encData); _log.Debug("Decrypted data received from server: {0}", Convert.ToBase64String(data)); using (var ms = new MemoryStream(data)) using (var br = new BinaryReader(ms)) { parameters = _parameterTransferHelper.ReceiveParameters(br); } } else { parameters = _parameterTransferHelper.ReceiveParameters(binReader); } //invoke the method object[] returnParameters; var returnMessageType = MessageType.ReturnValues; try { object returnValue = method.Invoke(invokedInstance.SingletonInstance, parameters); if (returnValue is Task task) { task.GetAwaiter().GetResult(); var prop = task.GetType().GetProperty("Result"); returnValue = prop?.GetValue(task); } //the result to the client is the return value (null if void) and the input parameters returnParameters = new object[1 + parameters.Length]; returnParameters[0] = returnValue; for (int i = 0; i < parameters.Length; i++) { returnParameters[i + 1] = isByRef[i] ? parameters[i] : null; } } catch (Exception ex) { //an exception was caught. Rethrow it client side returnParameters = new object[] { ex }; returnMessageType = MessageType.ThrowException; } //send the result back to the client // (1) write the message type binWriter.Write((int)returnMessageType); // (2) write the return parameters if (_requireZk) { byte[] data; using (var ms = new MemoryStream()) using (var bw = new BinaryWriter(ms)) { _parameterTransferHelper.SendParameters( invokedInstance.ServiceSyncInfo.UseCompression, invokedInstance.ServiceSyncInfo.CompressionThreshold, bw, returnParameters); data = ms.ToArray(); } _log.Debug("Unencrypted data sent server: {0}", Convert.ToBase64String(data)); var encData = session.Crypto.Encrypt(data); _log.Debug("Encrypted data sent server: {0}", Convert.ToBase64String(encData)); binWriter.Write(encData.Length); binWriter.Write(encData); } else { _parameterTransferHelper.SendParameters( invokedInstance.ServiceSyncInfo.UseCompression, invokedInstance.ServiceSyncInfo.CompressionThreshold, binWriter, returnParameters); } } else { binWriter.Write((int)MessageType.UnknownMethod); } } else { binWriter.Write((int)MessageType.UnknownMethod); } //flush binWriter.Flush(); _stats.Log(cat, stat, sw.ElapsedMilliseconds); }
private object[] RunInAndOut(params object[] obj) { var pth = new ParameterTransferHelper(); object[] result = null; using (var ms = new MemoryStream()) using (var writer = new BinaryWriter(ms)) using (var reader = new BinaryReader(ms)) { pth.SendParameters(false, 0, writer, obj); ms.Position = 0; result = pth.ReceiveParameters(reader); } return result; }