private async Task <string> HandleRequestAsync(JsonRpcRequest jsonRpcRequest, CancellationToken cancellationToken) { var methodName = jsonRpcRequest.Method; if (!MetadataProvider.TryGetMetadata(methodName, out var prodecureMetadata)) { return(Error(JsonRpcErrorCodes.MethodNotFound, $"'{methodName}' method not found.", jsonRpcRequest.Id)); } try { var methodParameters = prodecureMetadata.Parameters; var parameters = new List <object>(); if (jsonRpcRequest.Parameters is JArray jarr) { var count = methodParameters.Count < jarr.Count ? methodParameters.Count : jarr.Count; for (int i = 0; i < count; i++) { parameters.Add(jarr[i].ToObject(methodParameters[i].type, DefaultSerializer)); } } else if (jsonRpcRequest.Parameters is JObject jobj) { for (int i = 0; i < methodParameters.Count; i++) { var param = methodParameters[i]; if (!jobj.ContainsKey(param.name)) { return(Error(JsonRpcErrorCodes.InvalidParams, $"A value for the '{param.name}' is missing.", jsonRpcRequest.Id)); } parameters.Add(jobj[param.name].ToObject(param.type, DefaultSerializer)); } } // Special case: if there is a missing parameter and the procedure is expecting a CancellationTokenSource // then pass the cancellationToken we have. This will allow us to cancel async requests when the server is stopped. if (parameters.Count == methodParameters.Count - 1) { var position = methodParameters.FindIndex(x => x.type == typeof(CancellationToken)); if (position > -1) { parameters.Insert(position, cancellationToken); } } if (parameters.Count < methodParameters.Count(x => !x.isOptional)) { return(Error(JsonRpcErrorCodes.InvalidParams, $"{methodParameters.Count} parameters were expected but {parameters.Count} were received.", jsonRpcRequest.Id)); } var missingParameters = methodParameters.Count - parameters.Count; parameters.AddRange(methodParameters.TakeLast(missingParameters).Select(x => x.defaultValue)); var result = prodecureMetadata.MethodInfo.Invoke(Service, parameters.ToArray()); if (jsonRpcRequest.IsNotification) // the client is not interested in getting a response { return(""); } JsonRpcResponse response = null; if (prodecureMetadata.MethodInfo.IsAsync()) { if (!prodecureMetadata.MethodInfo.ReturnType.IsGenericType) { await((Task)result).ConfigureAwait(false); response = JsonRpcResponse.CreateResultResponse(jsonRpcRequest.Id, null); } else { var ret = await((dynamic)result).ConfigureAwait(false); response = JsonRpcResponse.CreateResultResponse(jsonRpcRequest.Id, ret); } } else { response = JsonRpcResponse.CreateResultResponse(jsonRpcRequest.Id, result); } return(response.ToJson(DefaultSettings)); } catch (TargetInvocationException e) { return(Error(JsonRpcErrorCodes.InternalError, e.InnerException.Message, jsonRpcRequest.Id)); } catch (Exception e) { return(Error(JsonRpcErrorCodes.InternalError, e.Message, jsonRpcRequest.Id)); } }
private string Error(JsonRpcErrorCodes code, string reason, string id) { var response = JsonRpcResponse.CreateErrorResponse(id, code, reason); return(id is { }