private void InitMethodsFromType(Type type, bool isAttributedMethodsOnly)
        {
            foreach (var methodInfo in type.GetMethods())
            {
                RpcMethodAttribute methodAttr = GetMethodAttribute(methodInfo);
                if (methodAttr != null || !isAttributedMethodsOnly)
                {
                    RpcMethodDescriptor method = new RpcMethodDescriptor(methodInfo, methodAttr, name);
                    if (methods.ContainsKey(method.Name))
                    {
                        methods[method.Name].Merge(method);
                    }
                    else
                    {
                        methods.Add(method.Name, method);
                    }
                }
            }

            //for classes checking the public methods is enough, but for an interface we must check the other
            //interfaces implemented too
            if (type.IsInterface)
            {
                foreach (var interfaceType in type.GetInterfaces())
                {
                    InitMethodsFromType(interfaceType, isAttributedMethodsOnly);
                }
            }
        }
        public void InvokeMethod(object service, string methodName, List <RpcMessage.Parameter> parameters, RpcMessage resultMessage)
        {
            RpcMethodDescriptor method = GetMethod(methodName);

            if (method != null)
            {
                method.Invoke(service, parameters, resultMessage);
            }
            else
            {
                //return an error message to the client if it is expecting a result, otherwise we fail silently
                if (resultMessage != null)
                {
                    resultMessage.ResultMessage.IsFailed     = true;
                    resultMessage.ResultMessage.ErrorMessage = String.Format("Unknown method '{1}' in service '{0}'",
                                                                             Name, methodName);
                }
            }
        }
        public void Merge(RpcMethodDescriptor method)
        {
            Debug.Assert(method.name == name && method.serviceName == serviceName);

            if (returnType != null && method.returnType != null && returnType != method.returnType)
            {
                throw new ArgumentException(
                          String.Format("Invalid declarations for method '{0}', the return types are not consistent.", name));
            }

            if (parameterTypes != null && method.parameterTypes != null &&
                !parameterTypes.SequenceEqual(method.parameterTypes))
            {
                throw new ArgumentException(
                          String.Format("Invalid declarations for method '{0}', the parameter types are not consistent.", name));
            }

            if (syncMethodInfo != null && method.syncMethodInfo != null)
            {
                throw new ArgumentException(
                          String.Format("Invalid declarations for method '{0}', more than one synchronous call found.", name));
            }
            if (asyncBeginMethodInfo != null && method.asyncBeginMethodInfo != null)
            {
                throw new ArgumentException(
                          String.Format("Invalid declarations for method '{0}', more than one begin async call found.", name));
            }
            if (asyncEndMethodInfo != null && method.asyncEndMethodInfo != null)
            {
                throw new ArgumentException(
                          String.Format("Invalid declarations for method '{0}', more than one end async call found.", name));
            }

            returnType           = returnType ?? method.returnType;
            parameterTypes       = parameterTypes ?? method.parameterTypes;
            syncMethodInfo       = syncMethodInfo ?? method.syncMethodInfo;
            asyncBeginMethodInfo = asyncBeginMethodInfo ?? method.asyncBeginMethodInfo;
            asyncEndMethodInfo   = asyncEndMethodInfo ?? method.asyncEndMethodInfo;
        }
        public void Merge(RpcMethodDescriptor method)
        {
            Debug.Assert(method.name == name && method.serviceName == serviceName);

            if (returnType != null && method.returnType != null && returnType != method.returnType)
                throw new ArgumentException(
                    String.Format("Invalid declarations for method '{0}', the return types are not consistent.", name));

            if (parameterTypes != null && method.parameterTypes != null
                && !parameterTypes.SequenceEqual(method.parameterTypes))
                throw new ArgumentException(
                    String.Format("Invalid declarations for method '{0}', the parameter types are not consistent.", name));

            if (syncMethodInfo != null && method.syncMethodInfo != null)
                throw new ArgumentException(
                    String.Format("Invalid declarations for method '{0}', more than one synchronous call found.", name));
            if (asyncBeginMethodInfo != null && method.asyncBeginMethodInfo != null)
                throw new ArgumentException(
                    String.Format("Invalid declarations for method '{0}', more than one begin async call found.", name));
            if (asyncEndMethodInfo != null && method.asyncEndMethodInfo != null)
                throw new ArgumentException(
                    String.Format("Invalid declarations for method '{0}', more than one end async call found.", name));

            returnType = returnType ?? method.returnType;
            parameterTypes = parameterTypes ?? method.parameterTypes;
            syncMethodInfo = syncMethodInfo ?? method.syncMethodInfo;
            asyncBeginMethodInfo = asyncBeginMethodInfo ?? method.asyncBeginMethodInfo;
            asyncEndMethodInfo = asyncEndMethodInfo ?? method.asyncEndMethodInfo;
        }
        private void InitMethodsFromType(Type type, bool isAttributedMethodsOnly)
        {
            foreach (var methodInfo in type.GetMethods())
            {
                RpcMethodAttribute methodAttr = GetMethodAttribute(methodInfo);
                if (methodAttr != null || !isAttributedMethodsOnly)
                {
                    RpcMethodDescriptor method = new RpcMethodDescriptor(methodInfo, methodAttr, name);
                    if (methods.ContainsKey(method.Name))
                    {
                        methods[method.Name].Merge(method);
                    }
                    else
                    {
                        methods.Add(method.Name, method);
                    }
                }
            }

            //for classes checking the public methods is enough, but for an interface we must check the other
            //interfaces implemented too
            if (type.IsInterface)
            {
                foreach (var interfaceType in type.GetInterfaces())
                    InitMethodsFromType(interfaceType, isAttributedMethodsOnly);
            }
        }
        public static Delegate BuildThunk(RpcMethodDescriptor method)
        {
            var dynMethod = new DynamicMethod("ServiceThunk", typeof(void),
                                              new[] { typeof(object), typeof(IList <RpcMessage.Parameter>), typeof(RpcMessage.Result) },
                                              typeof(ServiceThunkBuilder).Module);

            ILGenerator ilGen = dynMethod.GetILGenerator();

            //verify number of parameters
            ilGen.Emit(OpCodes.Ldarg_1);                              //push IList<RpcMessage.Parameter>
            ilGen.Emit(OpCodes.Ldc_I4, method.ParameterTypes.Length); //push number of expected parameters
            ilGen.Emit(OpCodes.Ldarg_2);                              //push RpcMessage.Result
            ilGen.Emit(OpCodes.Call, typeof(ServiceThunkHelpers).GetMethod("VerifyParameterCount"));
            Label paramVerifyLabel = ilGen.DefineLabel();

            ilGen.Emit(OpCodes.Brtrue, paramVerifyLabel);
            ilGen.Emit(OpCodes.Ret);
            ilGen.MarkLabel(paramVerifyLabel);

            //load the RpcMessage.Result to the stack, for the call to set the result
            if (method.ReturnType != typeof(void))
            {
                ilGen.Emit(OpCodes.Ldarg_2);
            }
            //load the service instance to the stack, for the call to the service instance
            ilGen.Emit(OpCodes.Ldarg_0);

            //load the service call parameters to the stack, if they are the wrong type then an error is stored
            //in the result message and we return early
            MethodInfo paramIndexer = typeof(IList <RpcMessage.Parameter>).GetProperty("Item").GetGetMethod();

            for (int i = 0; i < method.ParameterTypes.Length; ++i)
            {
                Type paramType = method.ParameterTypes[i];

                //get RpcMessage.Parameter by calling IList indexer
                ilGen.Emit(OpCodes.Ldarg_1);
                ilGen.Emit(OpCodes.Ldc_I4, i);
                ilGen.Emit(OpCodes.Callvirt, paramIndexer);

                ilGen.Emit(OpCodes.Ldarg_2);                              //push RpcMessage.Result
                LocalBuilder paramLocal = ilGen.DeclareLocal(paramType);
                ilGen.Emit(OpCodes.Ldloca, (short)paramLocal.LocalIndex); //push ref to result local
                EmitParameter(ilGen, paramType);

                Label continueLabel = ilGen.DefineLabel();
                ilGen.Emit(OpCodes.Brtrue, continueLabel); //success, continue with next parameter

                //failed, stack cleanup
                for (int j = 0; j < i; ++j)
                {
                    ilGen.Emit(OpCodes.Pop); //pop previous parameters
                }
                ilGen.Emit(OpCodes.Pop);     //pop service instance
                if (method.ReturnType != typeof(void))
                {
                    ilGen.Emit(OpCodes.Pop); //pop RpcMessage.Result
                }
                ilGen.Emit(OpCodes.Ret);

                ilGen.MarkLabel(continueLabel);

                //now push the actual parameter ready for the actual call
                ilGen.Emit(OpCodes.Ldloc, paramLocal.LocalIndex);
            }

            //now call the actual service instance method
            ilGen.Emit(OpCodes.Callvirt, method.SyncCallMethod);

            //get the return value, storing it in the result message. We know the type, no need for any error
            //checking
            if (method.ReturnType != typeof(void))
            {
                //check if result is null
                ilGen.Emit(OpCodes.Ldarg_2);
                ilGen.Emit(OpCodes.Ldnull);
                Label nullReturnLabel = ilGen.DefineLabel();
                ilGen.Emit(OpCodes.Beq, nullReturnLabel);

                //convert return value to a message and store it in the result message
                ThunkHelpers.EmitParameterToMessage(ilGen, method.ReturnType);
                ilGen.Emit(OpCodes.Call, typeof(RpcMessage.Result).GetProperty("CallResult").GetSetMethod());
                ilGen.Emit(OpCodes.Ret);

                ilGen.MarkLabel(nullReturnLabel);
                ilGen.Emit(OpCodes.Pop); //pop return value
                ilGen.Emit(OpCodes.Pop); //pop result message
            }

            ilGen.Emit(OpCodes.Ret);

            return(dynMethod.CreateDelegate(typeof(RpcServer.MethodDelegate)));
        }