Esempio n. 1
0
        /// <summary>
        /// Invokes an operation method.
        /// </summary>
        /// <typeparam name="TT">The task return type.</typeparam>
        /// <param name="method">The method.</param>
        /// <param name="args">The arguments.</param>
        /// <param name="returnType">The real return type.</param>
        /// <returns></returns>
        protected virtual async Task <TT> InvokeOperationAsync <TT>(MethodInfo method, object[] args, Type returnType)
        {
            // build arguments
            Dictionary <string, object> argsPayload = new Dictionary <string, object>();

            ParameterInfo[] argsMethod = method.GetParameters();

            for (int i = 0; i < args.Length; i++)
            {
                argsPayload[argsMethod[i].Name] = args[i];
            }

            // create request
            RpcRequest req = new RpcRequest(_contractAttr.Name != null ? _contractAttr.Name : _typeInfo.Name, method.Name, argsPayload);

            // serialize
            byte[]    requestBody = new ProtobufRpcSerializer().SerializeRequest(req);
            RpcHeader header      = new RpcHeader(RpcHeader.HEADER_VERSION, ProtobufRpcSerializer.SerializerName, RpcMessageType.Single);

            // create headers
            IDictionary <string, object> headers = new Dictionary <string, object>()
            {
                { RpcHeader.HEADER_NAME, header.ToString() }
            };

            // ask or send
            if (method.GetCustomAttribute <RpcOperationAttribute>().NoReply)
            {
                // send operation
                await _channel.SendAsync(requestBody, headers);

                return(default(TT));
            }
            else
            {
                Envelope res = await _channel.AskAsync(requestBody, _configuration.Timeout, headers);

                // transform response
                byte[] responseBody = res.Body;

                // try and get response header
                if (!res.Headers.TryGetValue(RpcHeader.HEADER_NAME, out object resHeaderData))
                {
                    throw new InvalidOperationException("The response envelope is not a valid RPC message");
                }

                RpcHeader resHeader = new RpcHeader(Encoding.UTF8.GetString(resHeaderData as byte[]));

                // deserialize response
                if (!RpcSerializer.Serializers.TryGetValue(resHeader.Serializer, out IRpcSerializer deserializer))
                {
                    throw new NotSupportedException("The response serializer is not supported");
                }

                // deserialize
                RpcResponse resPayload = null;

                if (method.ReturnType == typeof(Task))
                {
                    // deserialize
                    resPayload = deserializer.DeserializeResponse(responseBody, typeof(void));

                    // return result
                    if (resPayload.IsSuccess)
                    {
                        return((TT)(object)true);
                    }
                }
                else
                {
                    // deserialize
                    Type taskType = method.ReturnType.GetGenericArguments()[0];
                    resPayload = deserializer.DeserializeResponse(responseBody, taskType);

                    // return result
                    if (resPayload.IsSuccess)
                    {
                        return((TT)resPayload.Data);
                    }
                }

                // throw error
                throw new RpcException(resPayload.Error);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Takes the parsed header and envelope and applies correct type handler.
        /// </summary>
        /// <param name="header">The header.</param>
        /// <param name="envelope">The envelope.</param>
        /// <returns></returns>
        private async Task ApplyAsync(RpcHeader header, Envelope envelope)
        {
            if (header.Type == RpcMessageType.Single)
            {
                // find serializer for this request
                RpcRequest     req        = null;
                IRpcSerializer serializer = null;

                if (!RpcSerializer.Serializers.TryGetValue(header.Serializer, out serializer))
                {
                    throw new NotSupportedException("The serializer is not supported by RPC");
                }

                // deserialize into a request
                RpcResponse res = null;

                try {
                    req = serializer.DeserializeRequest(envelope.Body, (i, o) => RpcArgument.FromMember(GetMember(i, o)));
                } catch (KeyNotFoundException) {
                    res = new RpcResponse("InterfaceNotFound", "The interface or operation could not be found", null);
                } catch (Exception ex) {
                    res = new RpcResponse("ArgumentInvalid", string.Format("The request format is invalid: {0}", ex.Message), null);
                }

                // apply single request
                MemberInfo memberInfo = null;

                try {
                    if (req != null)
                    {
                        memberInfo = GetMember(req.Interface, req.Operation);
                    }
                } catch (KeyNotFoundException) {
                    res = new RpcResponse("OperationNotFound", "The interface or operation could not be found", null);
                }

                // get operation information
                RpcOperationAttribute opAttr = null;

                if (memberInfo != null)
                {
                    Type         interfaceType   = GetInterface(req.Interface);
                    MemberInfo[] interfaceMember = interfaceType.GetMember(req.Operation);
                    opAttr = interfaceMember[0].GetCustomAttribute <RpcOperationAttribute>();
                }

                // get if no reply is enabled
                bool noReply = opAttr != null && opAttr.NoReply;

                // check if they have a response ID if no reply isn't enabled
                if (!noReply && envelope.ID == Guid.Empty)
                {
                    res = new RpcResponse("InvalidOperation", "The envelope does not specify a correlation ID", null);
                }

                // apply request if we don't have a response already, typically an error
                if (res == null)
                {
                    // setup context
                    RpcContext.Current = new RpcContext()
                    {
                        Envelope = envelope
                    };

                    // apply request
                    res = await ApplyRequestAsync(req, memberInfo).ConfigureAwait(false);

                    // destroy context
                    RpcContext.Current = null;
                }

                // send response unless no-reply
                if (!noReply)
                {
                    // serialize response
                    byte[] resBody = serializer.SerializeResponse(res);

                    // send reply
                    string rpcHeader = new RpcHeader(RpcHeader.HEADER_VERSION, serializer.Name, RpcMessageType.Single).ToString();

                    Dictionary <string, object> headers = new Dictionary <string, object>(StringComparer.CurrentCultureIgnoreCase)
                    {
                        { RpcHeader.HEADER_NAME, rpcHeader },
                        { RpcHeader.HEADER_NAME_LEGACY, rpcHeader }
                    };

                    // reply
                    await envelope.ReplyAsync(resBody, headers).ConfigureAwait(false);
                }

                // throw exceptions
            }
            else
            {
                throw new NotImplementedException("Batched RPC is not supported currently");
            }
        }