public static async Task Run() { AuthenticationHeaderValue authHeaderValue = AuthenticationHeaderValue.Parse("Basic R2VrY3RlazpXZWxjMG1lIQ=="); RpcClient client = new RpcClient(new Uri("http://localhost:62390/RpcApi/"), authHeaderValue); RpcRequest request = new RpcRequest("Id1", "CharacterCount", "Test"); RpcResponse response = await client.SendRequestAsync(request, "Strings"); List<RpcRequest> requests = new List<RpcRequest> { request, new RpcRequest("id2", "CharacterCount", "Test2"), new RpcRequest("id3", "CharacterCount", "Test23") }; List<RpcResponse> bulkResponse = await client.SendBulkRequestAsync(requests, "Strings"); IntegerFromSpace responseValue = response.GetResult<IntegerFromSpace>(); if (responseValue == null) { Console.WriteLine("null"); } else { Console.WriteLine(responseValue.Test); } }
public override async Task<RpcResponse> InterceptSendRequestAsync(Func<RpcRequest, string, Task<RpcResponse>> interceptedSendRequestAsync, RpcRequest request, string route = null) { if (request.Method == "eth_accounts") { return BuildResponse(new string[] { "hello", "hello2"}, route); } if (request.Method == "eth_getCode") { return BuildResponse("the code", route); } return await interceptedSendRequestAsync(request, route); }
public static RpcRequest WithNoParameters(string method, RpcId id = default) { return(RpcRequest.WithParameters(method, default, id));
public static RpcRequest WithNoParameters(string id, string method) { return(RpcRequest.ConvertInternal(new RpcId(id), method, null, null)); }
public abstract Task<RpcResponse> InterceptSendRequestAsync( Func<RpcRequest, string, Task<RpcResponse>> interceptedSendRequestAsync, RpcRequest request, string route = null);
/// <summary> /// Call the incoming Rpc request method and gives the appropriate response /// </summary> /// <param name="request">Rpc request</param> /// <param name="route">Rpc route that applies to the current request</param> /// <param name="httpContext">The context of the current http request</param> /// <param name="jsonSerializerSettings">Json serialization settings that will be used in serialization and deserialization for rpc requests</param> /// <returns>An Rpc response for the request</returns> public async Task<RpcResponse> InvokeRequestAsync(RpcRequest request, RpcRoute route, HttpContext httpContext, JsonSerializerSettings jsonSerializerSettings = null) { try { if (request == null) { throw new ArgumentNullException(nameof(request)); } if (route == null) { throw new ArgumentNullException(nameof(route)); } } catch (ArgumentNullException ex) // Dont want to throw any exceptions when doing async requests { return this.GetUnknownExceptionReponse(request, ex); } this.logger?.LogDebug($"Invoking request with id '{request.Id}'"); RpcResponse rpcResponse; try { if (!string.Equals(request.JsonRpcVersion, JsonRpcContants.JsonRpcVersion)) { throw new RpcInvalidRequestException($"Request must be jsonrpc version '{JsonRpcContants.JsonRpcVersion}'"); } object[] parameterList; RpcMethod rpcMethod = this.GetMatchingMethod(route, request, out parameterList, httpContext.RequestServices, jsonSerializerSettings); bool isAuthorized = await this.IsAuthorizedAsync(rpcMethod, httpContext); if (isAuthorized) { this.logger?.LogDebug($"Attempting to invoke method '{request.Method}'"); object result = await rpcMethod.InvokeAsync(parameterList); this.logger?.LogDebug($"Finished invoking method '{request.Method}'"); JsonSerializer jsonSerializer = JsonSerializer.Create(jsonSerializerSettings); if (result is IRpcMethodResult) { this.logger?.LogTrace($"Result is {nameof(IRpcMethodResult)}."); rpcResponse = ((IRpcMethodResult)result).ToRpcResponse(request.Id, obj => JToken.FromObject(obj, jsonSerializer)); } else { this.logger?.LogTrace($"Result is plain object."); JToken resultJToken = result != null ? JToken.FromObject(result, jsonSerializer) : null; rpcResponse = new RpcResponse(request.Id, resultJToken); } } else { var authError = new RpcError(RpcErrorCode.InvalidRequest, "Unauthorized"); rpcResponse = new RpcResponse(request.Id, authError); } } catch (RpcException ex) { this.logger?.LogException(ex, "An Rpc error occurred. Returning an Rpc error response"); RpcError error = new RpcError(ex, this.serverConfig.Value.ShowServerExceptions); rpcResponse = new RpcResponse(request.Id, error); } catch (Exception ex) { rpcResponse = this.GetUnknownExceptionReponse(request, ex); } if (request.Id != null) { this.logger?.LogDebug($"Finished request with id '{request.Id}'"); //Only give a response if there is an id return rpcResponse; } this.logger?.LogDebug($"Finished request with no id. Not returning a response"); return null; }
/// <summary> /// Finds the matching Rpc method for the current request /// </summary> /// <param name="route">Rpc route for the current request</param> /// <param name="request">Current Rpc request</param> /// <param name="parameterList">Paramter list parsed from the request</param> /// <param name="serviceProvider">(Optional)IoC Container for rpc method controllers</param> /// <param name="jsonSerializerSettings">Json serialization settings that will be used in serialization and deserialization for rpc requests</param> /// <returns>The matching Rpc method to the current request</returns> private RpcMethod GetMatchingMethod(RpcRoute route, RpcRequest request, out object[] parameterList, IServiceProvider serviceProvider = null, JsonSerializerSettings jsonSerializerSettings = null) { if (route == null) { throw new ArgumentNullException(nameof(route)); } if (request == null) { throw new ArgumentNullException(nameof(request)); } this.logger?.LogDebug($"Attempting to match Rpc request to a method '{request.Method}'"); List<RpcMethod> methods = DefaultRpcInvoker.GetRpcMethods(route, serviceProvider, jsonSerializerSettings); //Case insenstive check for hybrid approach. Will check for case sensitive if there is ambiguity methods = methods .Where(m => string.Equals(m.Method, request.Method, StringComparison.OrdinalIgnoreCase)) .ToList(); RpcMethod rpcMethod = null; parameterList = null; int originalMethodCount = methods.Count; if (methods.Count > 0) { List<RpcMethod> potentialMatches = new List<RpcMethod>(); foreach (RpcMethod method in methods) { bool matchingMethod; if (request.ParameterMap != null) { matchingMethod = method.HasParameterSignature(request.ParameterMap, out parameterList); } else { matchingMethod = method.HasParameterSignature(request.ParameterList); parameterList = request.ParameterList; } if (matchingMethod) { potentialMatches.Add(method); } } if (potentialMatches.Count > 1) { //Try to remove ambiguity with case sensitive check potentialMatches = potentialMatches .Where(m => string.Equals(m.Method, request.Method, StringComparison.Ordinal)) .ToList(); if (potentialMatches.Count != 1) { this.logger?.LogError("More than one method matched the rpc request. Unable to invoke due to ambiguity."); throw new RpcMethodNotFoundException(); } } if (potentialMatches.Count == 1) { rpcMethod = potentialMatches.First(); } } if (rpcMethod == null) { this.logger?.LogError("No methods matched request."); throw new RpcMethodNotFoundException(); } this.logger?.LogDebug("Request was matched to a method"); return rpcMethod; }
/// <summary> /// Converts an unknown caught exception into a Rpc response /// </summary> /// <param name="request">Current Rpc request</param> /// <param name="ex">Unknown exception</param> /// <returns>Rpc error response from the exception</returns> private RpcResponse GetUnknownExceptionReponse(RpcRequest request, Exception ex) { this.logger?.LogException(ex, "An unknown error occurred. Returning an Rpc error response"); RpcUnknownException exception = new RpcUnknownException("An internal server error has occurred", ex); RpcError error = new RpcError(exception, this.serverConfig.Value.ShowServerExceptions); if (request?.Id == null) { return null; } RpcResponse rpcResponse = new RpcResponse(request.Id, error); return rpcResponse; }