/// <summary> /// Registers a service implementation with the RpcServer, it will be used to process received calls. /// </summary> /// <typeparam name="TService"> /// The type of the service can be specified explicitly, this allows the name of the service to be discovered /// even when the type does not have attributes. /// </typeparam> /// <param name="service"></param> public void RegisterService <TService>(TService service) { var rpcService = new RpcServiceDescriptor(typeof(TService)); if (mServices.ContainsKey(rpcService.Name)) { throw new ArgumentException(String.Format("A service with name '{0}' has already been registered", rpcService.Name)); } var serviceInstance = new ServiceInstance { Descriptor = rpcService, Instance = service }; foreach (var method in rpcService.Methods) { serviceInstance.MethodThunks.Add(method.Name, (MethodDelegate)ServiceThunkBuilder.BuildThunk(method)); } mServices.Add(rpcService.Name, serviceInstance); }
public Type Build(Type serviceType) { if (!serviceType.IsInterface) { throw new ArgumentException(String.Format("Type '{0}' being used to create a proxy must be an interface", serviceType.FullName)); } var service = new RpcServiceDescriptor(serviceType); TypeBuilder tb = mModuleBuilder.DefineType(serviceType.Name + "Proxy", TypeAttributes.Public, typeof(Proxy), new[] { serviceType }); ConstructorBuilder ctor = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { typeof(RpcClient) }); ILGenerator ctorIlGen = ctor.GetILGenerator(); ctorIlGen.Emit(OpCodes.Ldarg_0); ctorIlGen.Emit(OpCodes.Ldarg_1); ctorIlGen.Emit(OpCodes.Ldstr, service.Name); ctorIlGen.Emit(OpCodes.Call, typeof(Proxy).GetConstructor(new[] { typeof(RpcClient), typeof(string) })); ctorIlGen.Emit(OpCodes.Ret); foreach (var method in service.Methods) { MethodBuilder mb = tb.DefineMethod(method.SyncCallMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.ReturnType, method.ParameterTypes); ILGenerator methodIlGen = mb.GetILGenerator(); methodIlGen.Emit(OpCodes.Ldarg_0); methodIlGen.Emit(OpCodes.Ldstr, method.Name); EmitParameters(methodIlGen, method.ParameterTypes); if (method.ReturnType == typeof(void)) { methodIlGen.Emit(OpCodes.Call, mCallWithoutResultHelperMethodInfo); } else { methodIlGen.Emit(OpCodes.Call, mBlockingCallHelperMethodInfo); EmitReturn(methodIlGen, method.ReturnType); } methodIlGen.Emit(OpCodes.Ret); if (method.HasAsyncDeclarations) { MethodBuilder mbBegin = tb.DefineMethod(method.AsyncBeginCallMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, typeof(IAsyncResult), method.ParameterTypes.Concat(new[] { typeof(AsyncCallback), typeof(object) }).ToArray()); ILGenerator beginIlGen = mbBegin.GetILGenerator(); beginIlGen.Emit(OpCodes.Ldarg_0); beginIlGen.Emit(OpCodes.Ldstr, method.Name); EmitParameters(beginIlGen, method.ParameterTypes); beginIlGen.Emit(OpCodes.Ldarg, (short)(method.ParameterTypes.Length + 1)); //callback beginIlGen.Emit(OpCodes.Ldarg, (short)(method.ParameterTypes.Length + 2)); //state beginIlGen.Emit(OpCodes.Call, mBeginAsyncCallHelperMethodInfo); beginIlGen.Emit(OpCodes.Ret); MethodBuilder mbEnd = tb.DefineMethod(method.AsyncEndCallMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.ReturnType, new[] { typeof(IAsyncResult) }); ILGenerator endIlGen = mbEnd.GetILGenerator(); endIlGen.Emit(OpCodes.Ldarg_0); endIlGen.Emit(OpCodes.Ldstr, method.Name); endIlGen.Emit(OpCodes.Ldarg_1); endIlGen.Emit(OpCodes.Call, mEndAsyncCallHelperMethodInfo); if (method.ReturnType == typeof(void)) { endIlGen.Emit(OpCodes.Pop); } else { EmitReturn(endIlGen, method.ReturnType); } endIlGen.Emit(OpCodes.Ret); } } return(tb.CreateType()); }