private async Task ExecuteRpcAction(ApiCallContext <RequestContext <IScenePeer> > ctx, Func <T, RequestContext <IScenePeer>, IDependencyResolver, Task> action) { using (var scope = _scene.DependencyResolver.CreateChild(Constants.ApiRequestTag, ctx.Builder)) { var controller = scope.Resolve <T>(); try { if (controller == null) { throw new InvalidOperationException("The controller could not be found. Make sure it has been properly registered in the dependency manager."); } //controller.Request = ctx; controller.CancellationToken = ctx.Context.CancellationToken; controller.Peer = ctx.Context.RemotePeer; await action(controller, ctx.Context, scope); } catch (ClientException) { throw; } catch (Exception ex) { scope.Resolve <ILogger>().Log(LogLevel.Error, ctx.Route, $"An exception occurred while executing action '{ctx.Route}' in controller '{typeof(T).Name}'.", ex); throw; } } }
private async Task ExecuteRouteAction(ApiCallContext <Packet <IScenePeerClient> > ctx, Func <T, Packet <IScenePeerClient>, IDependencyResolver, Task> action) { using (var scope = _scene.DependencyResolver.CreateChild(Constants.ApiRequestTag, ctx.Builder)) { var controller = scope.Resolve <T>(); controller.Peer = ctx.Context.Connection; try { if (controller == null) { throw new InvalidOperationException("The controller could not be found. Make sure it has been properly registered in the dependency manager."); } await action(controller, ctx.Context, scope); } catch (Exception ex) { if (controller == null || !await controller.HandleException(new ApiExceptionContext(ctx.Route, ex, ctx.Context))) { scope.Resolve <ILogger>().Log(LogLevel.Error, ctx.Route, $"An exception occurred while executing action '{ctx.Route}' in controller '{typeof(T).Name}'.", ex); throw; } } } }
private bool TryAddRoute(Type controllerType, MethodInfo method) { var attr = method.GetCustomAttribute <ApiAttribute>(); if (attr == null) { return(false); } var route = attr.Route ?? GetProcedureName(controllerType, method, false); var returnType = method.ReturnType; if (attr.Type == ApiType.FireForget && returnType != typeof(Task) && returnType != typeof(void)) { return(false); } if (attr.Access == ApiAccess.Public) { if (attr.Type == ApiType.FireForget) { var a = CreateExecuteActionFunction <Packet <IScenePeerClient> >(method); _scene.AddRoute(route, packet => { var initialApiCallCtx = new ApiCallContext <Packet <IScenePeerClient> >(packet, method, route); Func <ApiCallContext <Packet <IScenePeerClient> >, Task> next = apiCallContext => ExecuteRouteAction(initialApiCallCtx, (c, pctx, r) => a(c, pctx, r)); foreach (var handler in _scene.DependencyResolver.Resolve <Func <IEnumerable <IApiHandler> > >()()) { next = WrapWithHandler(handler.RunFF, next); } return(next(initialApiCallCtx)); }, _ => _); } else { var a = CreateExecuteActionFunction <RequestContext <IScenePeerClient> >(method); _scene.AddProcedure(route, packet => { var initialApiCallCtx = new ApiCallContext <RequestContext <IScenePeerClient> >(packet, method, route); Func <ApiCallContext <RequestContext <IScenePeerClient> >, Task> next = apiCallContext => ExecuteRpcAction(initialApiCallCtx, (c, pctx, r) => a(c, pctx, r)); foreach (var handler in _scene.DependencyResolver.Resolve <Func <IEnumerable <IApiHandler> > >()()) { next = WrapWithHandler(handler.RunRpc, next); } return(next(initialApiCallCtx)); }, true); } } else //S2S { if (attr.Type == ApiType.FireForget) { var a = CreateExecuteActionFunction <Packet <IScenePeer> >(method); _scene.AddInternalRoute(route, packet => { var initialApiCallCtx = new ApiCallContext <Packet <IScenePeer> >(packet, method, route); Func <ApiCallContext <Packet <IScenePeer> >, Task> next = apiCallContext => ExecuteRouteAction(initialApiCallCtx, (c, pctx, r) => a(c, pctx, r)); foreach (var handler in _scene.DependencyResolver.Resolve <Func <IEnumerable <IApiHandler> > >()()) { next = WrapWithHandler(handler.RunFF, next); } return(next(initialApiCallCtx)); }, _ => _); } else { var a = CreateExecuteActionFunction <RequestContext <IScenePeer> >(method); _scene.Starting.Add(d => { _scene.DependencyResolver.Resolve <RpcService>().AddInternalProcedure(route, packet => { var initialApiCallCtx = new ApiCallContext <RequestContext <IScenePeer> >(packet, method, route); Func <ApiCallContext <RequestContext <IScenePeer> >, Task> next = apiCallContext => ExecuteRpcAction(initialApiCallCtx, (c, pctx, r) => a(c, pctx, r)); foreach (var handler in _scene.DependencyResolver.Resolve <Func <IEnumerable <IApiHandler> > >()()) { next = WrapWithHandler(handler.RunRpc, next); } return(next(initialApiCallCtx)); }, true); return(Task.CompletedTask); }); } } return(true); }
public void RegisterControllers() { var type = typeof(T); _scene.Connecting.Add(p => ExecuteConnecting(p)); _scene.ConnectionRejected.Add(p => ExecuteConnectionRejected(p)); _scene.Connected.Add(p => ExecuteConnected(p)); _scene.Disconnected.Add(args => ExecuteDisconnected(args)); foreach (var method in type.GetMethods()) { var procedureName = GetProcedureName(type, method); if (IsRawRpc <IScenePeerClient>(method)) { var ctxParam = Expression.Parameter(typeof(RequestContext <IScenePeerClient>), "ctx"); var controllerParam = Expression.Parameter(typeof(T), "controller"); var callExpr = Expression.Call(controllerParam, method, ctxParam); var action = Expression.Lambda <Func <T, RequestContext <IScenePeerClient>, Task> >(callExpr, controllerParam, ctxParam).Compile(); _scene.AddProcedure(procedureName, ctx => { var initialApiCallCtx = new ApiCallContext <RequestContext <IScenePeerClient> >(ctx, method, procedureName); Func <ApiCallContext <RequestContext <IScenePeerClient> >, Task> next = apiCallContext => ExecuteRpcAction(initialApiCallCtx, (c, pctx, r) => action(c, pctx)); foreach (var handler in _scene.DependencyResolver.Resolve <Func <IEnumerable <IApiHandler> > >()()) { next = WrapWithHandler(handler.RunRpc, next); } return(next(initialApiCallCtx)); }); } else if (IsRawRoute <IScenePeerClient>(method)) { var ctxParam = Expression.Parameter(typeof(Packet <IScenePeerClient>), "ctx"); var controllerParam = Expression.Parameter(typeof(T), "controller"); var callExpr = Expression.Call(controllerParam, method, ctxParam); var action = Expression.Lambda <Func <T, Packet <IScenePeerClient>, Task> >(callExpr, controllerParam, ctxParam).Compile(); _scene.AddRoute(procedureName, packet => { var initialApiCallCtx = new ApiCallContext <Packet <IScenePeerClient> >(packet, method, procedureName); Func <ApiCallContext <Packet <IScenePeerClient> >, Task> next = apiCallContext => ExecuteRouteAction(initialApiCallCtx, (c, pctx, r) => action(c, pctx)); foreach (var handler in _scene.DependencyResolver.Resolve <Func <IEnumerable <IApiHandler> > >()()) { next = WrapWithHandler(handler.RunFF, next); } return(next(initialApiCallCtx)); }, _ => _); } else if (IsRawRpc <IScenePeer>(method)) { var ctxParam = Expression.Parameter(typeof(RequestContext <IScenePeer>), "ctx"); var controllerParam = Expression.Parameter(typeof(T), "controller"); var callExpr = Expression.Call(controllerParam, method, ctxParam); var action = Expression.Lambda <Func <T, RequestContext <IScenePeer>, Task> >(callExpr, controllerParam, ctxParam).Compile(); _scene.Starting.Add(async parameters => { _scene.DependencyResolver.Resolve <RpcService>().AddInternalProcedure(procedureName, ctx => { var initialApiCallCtx = new ApiCallContext <RequestContext <IScenePeer> >(ctx, method, procedureName); Func <ApiCallContext <RequestContext <IScenePeer> >, Task> next = apiCallContext => ExecuteRpcAction(initialApiCallCtx, (c, pctx, r) => action(c, pctx)); foreach (var handler in _scene.DependencyResolver.Resolve <Func <IEnumerable <IApiHandler> > >()()) { next = WrapWithHandler(handler.RunRpc, next); } return(next(initialApiCallCtx)); }, false); await Task.FromResult(true); }); } else if (IsRawRoute <IScenePeer>(method)) { var ctxParam = Expression.Parameter(typeof(Packet <IScenePeer>), "ctx"); var controllerParam = Expression.Parameter(typeof(T), "controller"); var callExpr = Expression.Call(controllerParam, method, ctxParam); var action = Expression.Lambda <Func <T, Packet <IScenePeer>, Task> >(callExpr, controllerParam, ctxParam).Compile(); _scene.AddInternalRoute(procedureName, packet => { var initialApiCallCtx = new ApiCallContext <Packet <IScenePeer> >(packet, method, procedureName); Func <ApiCallContext <Packet <IScenePeer> >, Task> next = apiCallContext => ExecuteRouteAction(initialApiCallCtx, (c, pctx, r) => action(c, pctx)); foreach (var handler in _scene.DependencyResolver.Resolve <Func <IEnumerable <IApiHandler> > >()()) { next = WrapWithHandler(handler.RunFF, next); } return(next(initialApiCallCtx)); }, _ => _); } else { TryAddRoute(type, method); } } }