Ejemplo n.º 1
0
        /// <summary>
        /// Handles invokations on the proxy.
        /// </summary>
        /// <param name="targetMethod">The target method.</param>
        /// <param name="args">The arguments.</param>
        /// <returns></returns>
        protected override object Invoke(MethodInfo targetMethod, object[] args)
        {
            // get operation attribute
            RpcOperationAttribute attr = targetMethod.GetCustomAttribute <RpcOperationAttribute>();

            if (attr == null)
            {
                throw new InvalidOperationException("The interface member must be decorated with an operation attribute");
            }

            // check encryption requirement
            if ((_contractAttr.RequireEncryption || attr.RequireEncryption) && !_channel.IsEncrypted)
            {
                throw new SecurityException("The contract or operation requires an encrypted channel");
            }

            // generate generic method
            Type     genericType    = typeof(bool);
            Type     memberType     = targetMethod.ReturnType;
            TypeInfo memberTypeInfo = memberType.GetTypeInfo();

            //TODO: add support for sync methods
            if (memberType != typeof(Task) && memberTypeInfo.BaseType != typeof(Task))
            {
                throw new InvalidOperationException("The interface member must return an awaitable task");
            }

            if (memberTypeInfo.IsGenericType)
            {
                if (attr.NoReply)
                {
                    throw new InvalidOperationException("The method result cannot be retrieved with no reply on");
                }

                genericType = memberTypeInfo.GetGenericArguments()[0];
            }

            // invoke
            return(_invokeMethodInfo.MakeGenericMethod(genericType).Invoke(this, new object[] { targetMethod, args, targetMethod.ReturnType }));
        }
Ejemplo 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");
            }
        }