private void ProcessHandlerCall(BinaryReader reader, byte ifaceOrdinal, object context) { HandlerData handlerData; if (!_handlersData.TryGetValue(ifaceOrdinal, out handlerData)) { Type ifaceType = RpcInterface.GetRpcInterface(ifaceOrdinal); if (ifaceType == null) { throw new ProtocolViolationException("Unknown RPC interface ordinal received: " + ifaceOrdinal); } MethodInfo mi = RpcInterface.GetOrderedMethods(ifaceType)[reader.ReadByte()].MethodInfo; throw new ProtocolViolationException("RPC call received for " + ifaceType.FullName + "." + mi.Name + " which does not have a handler registered."); } byte methodOrdinal = reader.ReadByte(); RpcMethodInfo rpcMethodInfo = handlerData.InterfaceMethods[methodOrdinal]; MethodInfo methodInfo = rpcMethodInfo.MethodInfo; byte callId = 0; if (rpcMethodInfo.HasReturnType) { callId = reader.ReadByte(); } var paramsInfo = methodInfo.GetParameters(); var paramValues = new object[paramsInfo.Length]; for (int i = 0, n = paramValues.Length; i < n; ++i) { paramValues[i] = BinarySerializer.DeserializeParameter(reader, paramsInfo[i]); } var callContext = new HandlerCallContext { HandlerType = handlerData.RpcInterfaceType, Handler = handlerData.Handler, Method = methodInfo, CallId = callId, Context = context, }; if (OnBeforeHandlerCall != null) { OnBeforeHandlerCall(callContext); } callContext.Result = methodInfo.Invoke(handlerData.Handler, paramValues); if (callContext.Result != null && OnDataOut != null) { Type resultFutureType = callContext.Result.GetType(); var stream = new MemoryStream(64); var writer = new BinaryWriter(stream); var header = (byte)(ResponseTypeFlag | callId); writer.Write((byte)header); resultFutureType.GetMethod("Serialize", BindingFlags.NonPublic | BindingFlags.Instance) .Invoke(callContext.Result, new object[] { writer }); OnDataOut(stream.ToArray(), 0, (int)stream.Length); } if (OnAfterHandlerCall != null) { OnAfterHandlerCall(callContext); } }
// The generated code for the proxy type is like this: // // public class IBlahServiceRpcProxy : IBlahService // { // public ICallInterceptor Interceptor; // public object Context; // // public int Blah(int param1, string param2) // { // object argsArray = Interceptor.GetArgsArray(2); // argsArray[0] = param1; // argsArray[1] = param2; // return (int) Interceptor.MethodCall(0, Context, argsArray); // } // } private static Type CreateDynamicProxyType(ModuleBuilder moduleBuilder, Type type, HashSet <Type> checkedTypes) { TypeBuilder tb = moduleBuilder.DefineType(type.Name + "RpcProxy", TypeAttributes.Public); tb.AddInterfaceImplementation(type); FieldBuilder interceptorFi = tb.DefineField("Interceptor", typeof(ICallInterceptor), FieldAttributes.Public); FieldBuilder contextFi = tb.DefineField("Context", typeof(object), FieldAttributes.Public); RpcMethodInfo[] methods = GetOrderedMethods(type); MethodInfo beginCall = typeof(ICallInterceptor).GetMethod("BeginCall"); MethodInfo genericPushArg = typeof(ICallInterceptor).GetMethod("PushArg"); MethodInfo completeCall = typeof(ICallInterceptor).GetMethod("CompleteCall"); var genericPushArgMethods = new Dictionary <Type, MethodInfo>(); for (int ord = 0; ord < methods.Length; ++ord) { RpcMethodInfo rpcMethodInfo = methods[ord]; BinarySerializer.UpdateParameterCaches(rpcMethodInfo, checkedTypes); MethodInfo methodInfo = rpcMethodInfo.MethodInfo; ParameterInfo[] paramInfo = rpcMethodInfo.ParameterTypes; var paramTypes = new Type[paramInfo.Length]; for (int i = 0, n = paramInfo.Length; i < n; ++i) { paramTypes[i] = paramInfo[i].ParameterType; if (!genericPushArgMethods.ContainsKey(paramTypes[i])) { genericPushArgMethods[paramTypes[i]] = genericPushArg.MakeGenericMethod(paramTypes[i]); } } MethodBuilder mtb = tb.DefineMethod( methodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, methodInfo.ReturnType, paramTypes); ILGenerator gen = mtb.GetILGenerator(); // Interceptor.BeginCall(3, Context); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldfld, interceptorFi); gen.Emit(OpCodes.Ldc_I4, ord); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldfld, contextFi); gen.Emit(OpCodes.Callvirt, beginCall); // Call PushArg for each argument for (int i = 0, n = paramInfo.Length; i < n; ++i) { Type paramType = paramInfo[i].ParameterType; MethodInfo pushArgMi = genericPushArgMethods[paramType]; // Interceptor.PushArg(arg_i); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldfld, interceptorFi); gen.Emit(OpCodes.Ldarg, i + 1); gen.Emit(OpCodes.Callvirt, pushArgMi); } // return Interceptor.CompleteCall(); gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldfld, interceptorFi); gen.Emit(OpCodes.Callvirt, completeCall); if (mtb.ReturnType == typeof(void)) { gen.Emit(OpCodes.Pop); } else { gen.Emit(OpCodes.Castclass, mtb.ReturnType); } gen.Emit(OpCodes.Ret); } return(tb.CreateType()); }