private void WriteMetadata(IRpcHttpContext ctx, Stream outputStream) { var md = ReflectionHelper.GetRpcServiceInfo(impls); ctx.WriteOutput(outputStream, md); }
private void ProcessNormalRequest(IRpcHttpContext ctx, Stream outputStream) { RpcError error = new RpcError("rpc server error.", null); if (ctx.Request.ContentLength64 > ByteSize.FromMbs(10).TotalBytes) { error.Message = "request data is limited in 10Mb"; } else { var requestMeta = ctx.Request.Headers["meta"]; if (requestMeta != null) { //get request metadata IRpcHeadSerializer headSerializer; if (!iocContainer.TryResolve(out headSerializer)) { headSerializer = iocContainer.Resolve <IRpcHeadSerializer>("default"); } RpcHead head = null; bool deserialize_head_error_obtained = false; bool deserialize_body_error_obtained = false; try { head = headSerializer.Deserialize(requestMeta); } catch (Exception ex) { deserialize_head_error_obtained = true; error.Message = "error on deserialize rpc head metadata. " + ex.Message; error.StackTrace = ex.StackTrace; } if (head != null) { RpcHead.SetCurrent(head); Type itfType = itfTypes.FirstOrDefault(x => x.Namespace == head.Namespace && x.Name == head.TypeName); if (itfType != null) { var itfMethod = (MethodInfo)ReflectionHelper.ResolveMethod(itfType, head.MethodMDToken); if (itfMethod != null) { var parmTypes = itfMethod.GetParameters().Select(x => x.ParameterType).ToArray(); var pramNames = itfMethod.GetParameters().Select(x => x.Name).ToArray(); bool error_generated = false; IRpcService rpcService = null; //deserialize arguments IRpcDataSerializer serializer; if (!iocContainer.TryResolve(out serializer)) { serializer = iocContainer.Resolve <IRpcDataSerializer>("default"); } object[] args = null; if (head.EventOp) { FixupEventHandlerType(parmTypes); } try { args = serializer.Deserialize(ctx.Request.InputStream, parmTypes, pramNames); } catch (Exception ex) { deserialize_body_error_obtained = true; error.Message = "error on deserialize rpc request data. " + ex.Message; error.StackTrace = ex.StackTrace; } if (!deserialize_body_error_obtained) { object impl = null; object returnVal = null; //find a instance if (!this.instances.TryGetValue(head.InstanceId, out impl)) { //resolve the implimentation of the interface impl = iocContainer.Resolve(itfType); } var implInternal = impl; if (impl != null && !typeof(ThunkImplementation).IsAssignableFrom(impl.GetType())) { //thunk impl is for event remote handle, if no this thunk, server can not known which client handler will call impl = this.instances[head.InstanceId] = thunkImplFactory.GetProxy(itfType, impl, head.InstanceId, this); } //process a call for getting user infomation if user code support authroize rpcService = impl as IRpcService; var abstractRpcService = implInternal as RpcService; if (abstractRpcService != null) { abstractRpcService.exceptionHandler = this.ExceptionHandler; abstractRpcService.authorizeHandler = this.AuthroizeHandler; } RpcIdentity identity = rpcService != null?rpcService.Authroize(head.Token) : AuthroizeHandler.Authroize(head.Token); var principal = new RpcPrincipal(identity); Thread.CurrentPrincipal = principal; if (abstractRpcService != null) { abstractRpcService.User = principal; } var rpcAdministration = implInternal as RpcServiceAdministration; if (rpcAdministration != null) { rpcAdministration.Server = this; } Type instanceType = impl.GetType(); try { Console.WriteLine("[rpc call] {0}.{1}.{2}", head.Namespace, head.TypeName, head.MethodName); if (!RpcMethodHelper.IsAuthoirzied(itfType, itfMethod, instanceType)) { error_generated = true; error = new RpcError("access denied.", null); ctx.Response.StatusCode = 401; } else { //execute the call if (head.EventOp) { //Debugger.Break(); var op = head.GetEventOp(); //create a method as the event proxy EventInfo e = TypeHelper.GetEventInfo(itfType, op.EventName); var hanlderName = itfType.Name + "_" + op.EventName; //thunkHandler is a proxy method will call DelegateHelper. var thunkHandler = instanceType.GetMethod(hanlderName); var clientHandlerId = (int)args[0]; /*event callback id of client*/ //event register/unregister if (op.EventKind == RpcEventKind.Add) { EventHub.AddEventHandler(e, impl, head.InstanceId, thunkHandler, clientHandlerId); } else { EventHub.RemoveEventHandler(e, impl, head.InstanceId, thunkHandler, clientHandlerId); BlockingQueue <RpcEvent> messages; if (this.eventMessages.TryGetValue(head.InstanceId, out messages)) { //null for close the ws connection //Console.WriteLine("send null RpcEvent for close the ws connection on instance " + head.InstanceId); messages.Enqueue(null); } } } else { MethodInfo implMethod = RpcMethodHelper.FindImplMethod(itfType, itfMethod, instanceType); returnVal = RpcMethodHelper.Invoke(itfType, itfMethod, impl, implMethod, head.EventOp, head.Timeout, head.Token, args); } //dispose resouces like stream foreach (IDisposable item in args.OfType <IDisposable>()) { try { item.Dispose(); } catch { } } } } catch (TargetInvocationException ex) { error_generated = true; if (rpcService != null) { try { error = rpcService.HandleException(head, ex.InnerException); } catch (Exception ex2) { //do not use exceptionHandler here, it may cause a deal loop //because the rpcService backend ex handler is exceptionHandler by default error = RpcError.FromException(ex2); } } else { error = this.ExceptionHandler.HandleException(head, ex.InnerException); } } catch (Exception ex) { error_generated = true; if (rpcService != null) { try { error = rpcService.HandleException(head, ex); } catch (Exception ex2) { //do not use exceptionHandler here, it may cause a deal loop //because the rpcService backend ex handler is exceptionHandler by default error = RpcError.FromException(ex2); } } else { error = this.ExceptionHandler.HandleException(head, ex); } } if (!error_generated) { try { if (itfMethod.ReturnType != typeof(void)) { if (typeof(Task).IsAssignableFrom(itfMethod.ReturnType)) { if (itfMethod.ReturnType.IsGenericType) { serializer.Serialize(outputStream, new Type[] { itfMethod.ReturnType.GenericTypeArguments[0] }, new object[] { returnVal }, new string[] { "p0" }); } else { //no need handle task without a result. } } else { serializer.Serialize(outputStream, new Type[] { itfMethod.ReturnType }, new object[] { returnVal }, new string[] { "p0" }); } IDisposable value = returnVal as IDisposable; if (value != null) { try { value.Dispose(); } catch { } } IDisposable inst = impl as IDisposable; if (inst != null) { try { inst.Dispose(); } catch { } } } return; } catch (Exception ex) { Console.WriteLine("error on writting response, " + ex.Message); return; // connection is broken. nothing to do. } } } } else { error.Message = "invalid rpc request metadata, unknown method under the interface."; } } else { error.Message = "invalid rpc request metadata, unknown interface."; } } else if (!deserialize_head_error_obtained) { error.Message = "invalid rpc request metadata, deserialize failed."; } } else { error.Message = "invalid rpc request metadata"; } } Console.WriteLine(error.Message); Console.WriteLine(error.StackTrace); if (ctx.Response.StatusCode == 200) { ctx.Response.StatusCode = 500; ctx.Response.StatusDescription = "Internal Server Error"; } ctx.WriteOutput(outputStream, error); }