Example #1
0
        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, mName);
                    if (mMethods.ContainsKey(method.Name))
                    {
                        mMethods[method.Name].Merge(method);
                    }
                    else
                    {
                        mMethods.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);
                }
            }
        }
Example #2
0
        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);
                }
            }
        }
Example #3
0
        public void Merge(RpcMethodDescriptor method)
        {
            Debug.Assert(method.mName == mName && method.mServiceName == mServiceName);

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

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

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

            mReturnType           = mReturnType ?? method.mReturnType;
            mParameterTypes       = mParameterTypes ?? method.mParameterTypes;
            mSyncMethodInfo       = mSyncMethodInfo ?? method.mSyncMethodInfo;
            mAsyncBeginMethodInfo = mAsyncBeginMethodInfo ?? method.mAsyncBeginMethodInfo;
            mAsyncEndMethodInfo   = mAsyncEndMethodInfo ?? method.mAsyncEndMethodInfo;
        }
Example #4
0
        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)));
        }