Skip to content

Commit

Permalink
Fixes (#44)
Browse files Browse the repository at this point in the history
Fixes #43  Fixes #35 And Misc fixes with detecting methods and base path detection
  • Loading branch information
Ethan Celletti authored Jan 8, 2018
1 parent 404fe2e commit dc69dea
Show file tree
Hide file tree
Showing 15 changed files with 296 additions and 58 deletions.
28 changes: 28 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"version": "0.2.0",
"configurations": [
{
"name": "Router Tester",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/test/EdjCase.JsonRpc.Router.Sample/bin/Debug/netcoreapp2.0/EdjCase.JsonRpc.Router.Sample.dll",
"args": [],
"cwd": "${workspaceFolder}/test/EdjCase.JsonRpc.Router.Sample",
// For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
"console": "internalConsole",
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}
15 changes: 15 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/test/EdjCase.JsonRpc.Client.Sample/EdjCase.JsonRpc.Client.Sample.csproj"
],
"problemMatcher": "$msCompile"
}
]
}
27 changes: 9 additions & 18 deletions src/EdjCase.JsonRpc.Core/JsonConverters/RpcIdJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using Newtonsoft.Json;
using EdjCase.JsonRpc.Core.Utilities;

namespace EdjCase.JsonRpc.Core.JsonConverters
{
Expand All @@ -16,8 +17,8 @@ public class RpcIdJsonConverter : JsonConverter
/// <param name="serializer">Json serializer</param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
value = this.ValidateValue(value);
writer.WriteValue(value);
RpcId id = this.ValidateValue(value);
writer.WriteValue(id.Value);
}

/// <summary>
Expand Down Expand Up @@ -45,11 +46,15 @@ private RpcId ValidateValue(object value)
{
return default;
}
if(value is RpcId rpcId)
{
return rpcId;
}
if(value is string stringValue)
{
return new RpcId(stringValue);
}
if (this.IsNumericType(value.GetType()))
if (value.GetType().IsNumericType())
{
return new RpcId(Convert.ToDouble(value));
}
Expand All @@ -63,22 +68,8 @@ private RpcId ValidateValue(object value)
/// <returns>True if the converter converts the specified type, otherwise False</returns>
public override bool CanConvert(Type objectType)
{
return objectType == typeof (string) || this.IsNumericType(objectType);
return objectType == typeof (string) || objectType.IsNumericType();
}

/// <summary>
/// Determines if the type is a number
/// </summary>
/// <param name="type">Type of the object</param>
/// <returns>True if the type is a number, otherwise False</returns>
private bool IsNumericType(Type type)
{
return type == typeof (long)
|| type == typeof (int)
|| type == typeof (short)
|| type == typeof (float)
|| type == typeof (double)
|| type == typeof (decimal);
}
}
}
34 changes: 34 additions & 0 deletions src/EdjCase.JsonRpc.Core/Utilities/ExtensionsUtil.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace EdjCase.JsonRpc.Core.Utilities
{
public static class TypeExtensions
{
/// <summary>
/// Determines if the type is a number
/// </summary>
/// <param name="type">Type of the object</param>
/// <param name="includeInteger">Includes a check for whole number types. Defaults to true</param>
/// <returns>True if the type is a number, otherwise False</returns>
public static bool IsNumericType(this Type type, bool includeInteger = true)
{
if (includeInteger)
{
return type == typeof(long)
|| type == typeof(int)
|| type == typeof(short)
|| type == typeof(float)
|| type == typeof(double)
|| type == typeof(decimal);
}
else
{
return type == typeof(float)
|| type == typeof(double)
|| type == typeof(decimal);
}
}
}
}
64 changes: 35 additions & 29 deletions src/EdjCase.JsonRpc.Router/Defaults/DefaultRpcInvoker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private JsonSerializer GetJsonSerializer()
/// <param name="policyProvider">Provides authorization policies for the authroziation service</param>
/// <param name="logger">Optional logger for logging Rpc invocation</param>
/// <param name="serverConfig">Configuration data for the server</param>
public DefaultRpcInvoker(IAuthorizationService authorizationService, IAuthorizationPolicyProvider policyProvider,
public DefaultRpcInvoker(IAuthorizationService authorizationService, IAuthorizationPolicyProvider policyProvider,
ILogger<DefaultRpcInvoker> logger, IOptions<RpcServerConfiguration> serverConfig)
{
this.authorizationService = authorizationService;
Expand Down Expand Up @@ -131,7 +131,7 @@ public async Task<RpcResponse> InvokeRequestAsync(RpcRequest request, RpcPath pa
{
throw new RpcInvalidRequestException($"Request must be jsonrpc version '{JsonRpcContants.JsonRpcVersion}'");
}

RpcMethodInfo rpcMethod = this.GetMatchingMethod(path, request, routeContext.RouteProvider, routeContext.RequestServices);

bool isAuthorized = await this.IsAuthorizedAsync(rpcMethod.Method, routeContext);
Expand Down Expand Up @@ -280,22 +280,34 @@ private RpcMethodInfo GetMatchingMethod(RpcPath path, RpcRequest request, IRpcRo
var potentialMatches = new List<RpcMethodInfo>();
foreach (MethodInfo method in methodsWithSameName)
{
if (this.HasParameterSignature(method, request, out RpcMethodInfo rpcMethodInfo))
(bool isMatch, RpcMethodInfo methodInfo) = this.HasParameterSignature(method, request);
if (isMatch)
{
potentialMatches.Add(rpcMethodInfo);
potentialMatches.Add(methodInfo);
}
}

if (potentialMatches.Count > 1)
{
//Try to remove ambiguity with case sensitive check
potentialMatches = potentialMatches
.Where(m => string.Equals(m.Method.Name, request.Method, StringComparison.Ordinal))
//Try to remove ambiguity with 'perfect matching' (usually optional params and types)
List<RpcMethodInfo> exactMatches = potentialMatches
.Where(p => p.HasExactParameterMatch())
.ToList();
if (potentialMatches.Count != 1)
if (exactMatches.Any())
{
potentialMatches = exactMatches;
}
if (potentialMatches.Count > 1)
{
this.logger?.LogError("More than one method matched the rpc request. Unable to invoke due to ambiguity.");
throw new RpcMethodNotFoundException();
//Try to remove ambiguity with case sensitive check
potentialMatches = potentialMatches
.Where(m => string.Equals(m.Method.Name, 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();
}
}
}

Expand Down Expand Up @@ -389,7 +401,7 @@ private async Task<object> InvokeAsync(RpcMethodInfo methodInfo, RpcPath path, I

//Controller error handling
RpcErrorFilterAttribute errorFilter = methodInfo.Method.DeclaringType.GetTypeInfo().GetCustomAttribute<RpcErrorFilterAttribute>();
if(errorFilter != null)
if (errorFilter != null)
{
OnExceptionResult result = errorFilter.OnException(routeInfo, ex.InnerException);
if (!result.ThrowException)
Expand Down Expand Up @@ -510,7 +522,7 @@ private object ConvertParameter(Type parameterType, object parameterValue)
/// </summary>
/// <param name="parameterList">Array of parameters for the method</param>
/// <returns>True if the method signature matches the parameterList, otherwise False</returns>
private bool HasParameterSignature(MethodInfo method, RpcRequest rpcRequest, out RpcMethodInfo rpcMethodInfo)
private (bool Matches, RpcMethodInfo MethodInfo) HasParameterSignature(MethodInfo method, RpcRequest rpcRequest)
{
JToken[] orignialParameterList;
if (rpcRequest.Parameters == null)
Expand All @@ -527,8 +539,7 @@ private bool HasParameterSignature(MethodInfo method, RpcRequest rpcRequest, out
bool canParse = this.TryParseParameterList(method, parameterMap, out orignialParameterList);
if (!canParse)
{
rpcMethodInfo = null;
return false;
return (false, null);
}
break;
case JTokenType.Array:
Expand All @@ -542,8 +553,7 @@ private bool HasParameterSignature(MethodInfo method, RpcRequest rpcRequest, out
ParameterInfo[] parameterInfoList = method.GetParameters();
if (orignialParameterList.Length > parameterInfoList.Length)
{
rpcMethodInfo = null;
return false;
return (false, null);
}
object[] correctedParameterList = new object[parameterInfoList.Length];

Expand All @@ -554,28 +564,26 @@ private bool HasParameterSignature(MethodInfo method, RpcRequest rpcRequest, out
bool isMatch = this.ParameterMatches(parameterInfo, parameter, out object convertedParameter);
if (!isMatch)
{
rpcMethodInfo = null;
return false;
return (false, null);
}
correctedParameterList[i] = convertedParameter;
}

if(orignialParameterList.Length < parameterInfoList.Length)
if (orignialParameterList.Length < parameterInfoList.Length)
{
//make a new array at the same length with padded 'missing' parameters (if optional)
for (int i = orignialParameterList.Length; i < parameterInfoList.Length; i++)
{
if (!parameterInfoList[i].IsOptional)
{
rpcMethodInfo = null;
return false;
return (false, null);
}
correctedParameterList[i] = Type.Missing;
}
}

rpcMethodInfo = new RpcMethodInfo(method, correctedParameterList, orignialParameterList);
return true;
var rpcMethodInfo = new RpcMethodInfo(method, correctedParameterList, orignialParameterList);
return (true, rpcMethodInfo);
}

/// <summary>
Expand Down Expand Up @@ -665,18 +673,16 @@ private bool ParameterMatches(ParameterInfo parameterInfo, JToken value, out obj
{
case JTokenType.Array:
{
//TODO should just assume they will work and have the end just fail if cant convert?
JsonSerializer serializer = this.GetJsonSerializer();
JArray jArray = (JArray)value;
convertedValue = jArray.ToObject(parameterType, serializer); //Test conversion
convertedValue = jArray.ToObject(parameterType, serializer);
return true;
}
case JTokenType.Object:
{
//TODO should just assume they will work and have the end just fail if cant convert?
JsonSerializer serializer = this.GetJsonSerializer();
JObject jObject = (JObject)value;
convertedValue = jObject.ToObject(parameterType, serializer); //Test conversion
convertedValue = jObject.ToObject(parameterType, serializer);
return true;
}
default:
Expand All @@ -691,7 +697,7 @@ private bool ParameterMatches(ParameterInfo parameterInfo, JToken value, out obj
return false;
}
}


/// <summary>
/// Tries to parse the parameter map into an ordered parameter list
Expand Down
33 changes: 30 additions & 3 deletions src/EdjCase.JsonRpc.Router/RpcMethodInfo.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
using System;
using EdjCase.JsonRpc.Core.Utilities;
using EdjCase.JsonRpc.Router.Utilities;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
Expand All @@ -10,12 +14,35 @@ public class RpcMethodInfo
{
public MethodInfo Method { get; }
public object[] ConvertedParameters { get; }
public object[] RawParameters { get; }
public JToken[] RawParameters { get; }

public RpcMethodInfo(MethodInfo method, object[] convertedParameters, object[] rawParameters)
public RpcMethodInfo(MethodInfo method, object[] convertedParameters, JToken[] rawParameters)
{
this.Method = method;
this.ConvertedParameters = convertedParameters;
this.RawParameters = rawParameters;
}

public bool HasExactParameterMatch()
{
try
{
ParameterInfo[] parameters = this.Method.GetParameters();
for (int i = 0; i < this.RawParameters.Length; i++)
{
JToken original = this.RawParameters[i];
ParameterInfo parameter = parameters[i];
if (!RpcUtil.TypesMatch(original, parameter.ParameterType))
{
return false;
}
}
return true;
}
catch
{
return false;
}
}
}
}
Loading

0 comments on commit dc69dea

Please sign in to comment.