Пример #1
0
        /// <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);
            }
        }
Пример #2
0
        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;
 }