public static void RegisterMethods(Assembly fromAssembly) { if (fromAssembly == null) { throw new ArgumentNullException(nameof(fromAssembly)); } foreach (var t in fromAssembly.DefinedTypes) { var classAttribute = t.GetCustomAttribute <JsonRpcClassAttribute>(); var className = classAttribute?.Name ?? t.Name; foreach (var m in t.DeclaredMethods) { var methodAttribute = m.GetCustomAttribute <JsonRpcMethodAttribute>(); if (methodAttribute == null) { continue; } var name = methodAttribute.Name ?? $"{className}.{m.Name}"; var asyncIndex = name.LastIndexOf("Async", StringComparison.Ordinal); if (asyncIndex > -1) { name = name.Remove(asyncIndex); } name = name.ToLowerInvariant(); var method = new JsonRpcMethod(); method.Name = name; method.Description = methodAttribute.Description; method.MethodInfo = m; foreach (var parameterInfo in m.GetParameters()) { var parameterAttribute = parameterInfo.GetCustomAttribute <JsonRpcParameterAttribute>(); if (parameterAttribute?.Ignore ?? false) { continue; } var parameter = new JsonRpcParameter(); parameter.Name = parameterAttribute?.Name ?? parameterInfo.Name; parameter.Description = parameterAttribute?.Description; parameter.Type = JsonTypeMap.GetJsonType(parameterInfo.ParameterType); parameter.Optional = parameterInfo.IsOptional; method.Parameters.Add(parameter); } Methods.Add(method); } } }
private static async void HandleRequest(HttpListenerContext httpContext) { if (!new[] { "GET", "POST" }.Contains(httpContext.Request.HttpMethod, StringComparer.InvariantCultureIgnoreCase)) { httpContext.Response.StatusCode = (int)HttpStatusCode.NotFound; httpContext.Response.OutputStream.Close(); return; } JsonRpcRequest request = null; JsonRpcMethod method = null; var serializer = CreateSerializer(); if (httpContext.Request.QueryString.Count > 0) { request = new JsonRpcRequest(); var parameters = new Dictionary <string, string>(); var queryString = httpContext.Request.QueryString; foreach (var key in queryString.AllKeys) { if (key == null) { continue; } ; var value = queryString[key]; if (key == "jsonrpc") { request.JsonRpc = value; continue; } if (key == "id") { request.Id = value; continue; } if (key == "method") { request.Method = value; continue; } parameters[key] = value; } method = GetMethod(request.Method); //Move unknown values into ExtensionData if (method != null) { var extensionData = new Dictionary <string, string>(); foreach (var parameter in parameters) { if (!method.Parameters.Contains(parameter.Key)) { extensionData.Add(parameter.Key, parameter.Value); } } foreach (var parameter in extensionData) { parameters.Remove(parameter.Key); } request.ExtensionData = JObject.FromObject(extensionData, serializer); } request.Params = JObject.FromObject(parameters, serializer); } else { var contentType = httpContext.Request.ContentType?.ToLowerInvariant().Split(';')[0]; if (contentType != null) { string requestJson = null; switch (contentType) { case "application/json": using (var reader = new StreamReader(httpContext.Request.InputStream)) { requestJson = await reader.ReadToEndAsync(); } break; case "multipart/form-data": using (var reader = new StreamReader(httpContext.Request.InputStream)) { var boundary = await reader.ReadLineAsync(); var multipartString = await reader.ReadToEndAsync(); var parts = multipartString.Split(new[] { boundary }, StringSplitOptions.RemoveEmptyEntries); var requestPartHeader = "Content-Disposition: form-data; name=\"request\""; var requestPart = parts.FirstOrDefault(p => p.StartsWith(requestPartHeader)); if (requestPart != null) { requestJson = requestPart.Substring(requestPartHeader.Length).Trim(); } } break; default: httpContext.Response.StatusCode = (int)HttpStatusCode.UnsupportedMediaType; httpContext.Response.OutputStream.Close(); return; } try { request = JsonConvert.DeserializeObject <JsonRpcRequest>(requestJson, SerializerSettings); } catch (Exception e) { await WriteResponseAsync(httpContext, JsonRpcResponse.FromError(JsonRpcErrorCodes.ParseError, null, e)); return; } method = GetMethod(request.Method); } } if (request?.Method == null) { var info = new JsonRpcInfo(); info.Methods = Methods.ToList(); await WriteResponseAsync(httpContext, JsonRpcResponse.FromResult(null, info)); return; } var jsonRpcContext = new JsonRpcContext(httpContext, request); JsonRpcContext.Current = jsonRpcContext; try { foreach (var f in OnReceivedRequestFuncs) { await f(jsonRpcContext); } } catch (Exception e) { await WriteResponseAsync(httpContext, JsonRpcResponse.FromError(JsonRpcErrorCodes.InternalError, request.Id, e)); return; } if (method == null) { await WriteResponseAsync(httpContext, JsonRpcResponse.FromError(JsonRpcErrorCodes.MethodNotFound, request.Id, request.Method)); return; } //Prepare the method parameters var parameterValues = new List <object>(); try { var parameters = method.MethodInfo.GetParameters(); foreach (var parameter in parameters) { var parameterAttribute = parameter.GetCustomAttribute <JsonRpcParameterAttribute>(); if (parameterAttribute?.Ignore == true) { parameterValues.Add(Type.Missing); continue; } var parameterName = parameterAttribute?.Name ?? parameter.Name; var value = request.Params?[parameterName]?.ToObject(parameter.ParameterType, serializer) ?? Type.Missing; parameterValues.Add(value); } } catch (Exception e) { await WriteResponseAsync(httpContext, JsonRpcResponse.FromError(JsonRpcErrorCodes.ParseError, request.Id, e)); return; } //Execute the method try { try { var methodTask = (Task)method.MethodInfo.Invoke(null, parameterValues.ToArray()); await methodTask; var result = methodTask.GetType().GetProperty("Result")?.GetValue(methodTask); if (!(result is Stream)) { result = new JsonRpcResponse { Id = request.Id, JsonRpc = "2.0", Result = result }; } await WriteResponseAsync(httpContext, result); return; } catch (TargetInvocationException ex) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } } catch (JsonRpcUnauthorizedException e) { await WriteResponseAsync(httpContext, JsonRpcResponse.FromError(JsonRpcErrorCodes.Unauthorized, request.Id, e)); return; } catch (Exception e) { await WriteResponseAsync(httpContext, JsonRpcResponse.FromError(JsonRpcErrorCodes.ExecutionError, request.Id, e)); return; } }