private async Task <JsonRpcMessage> DispatchIncomingRequestAsync(JsonRpcMessage request, JsonSerializer jsonSerializer) { if (this.callbackTarget == null) { string message = string.Format(CultureInfo.CurrentCulture, Resources.DroppingRequestDueToNoTargetObject, request.Method); return(JsonRpcMessage.CreateError(request.Id, JsonRpcErrorCode.NoCallbackObject, message)); } bool ctsAdded = false; try { var targetMethod = new TargetMethod(request, this.callbackTarget, jsonSerializer); if (!targetMethod.IsFound) { return(JsonRpcMessage.CreateError(request.Id, JsonRpcErrorCode.MethodNotFound, targetMethod.LookupErrorMessage)); } var cancellationToken = CancellationToken.None; if (targetMethod.AcceptsCancellationToken && !request.IsNotification) { var cts = new CancellationTokenSource(); cancellationToken = cts.Token; lock (this.dispatcherMapLock) { this.inboundCancellationSources.Add(request.Id, cts); ctsAdded = true; } } object result = targetMethod.Invoke(cancellationToken); if (!(result is Task)) { return(JsonRpcMessage.CreateResult(request.Id, result, this.JsonSerializer)); } return(await((Task)result).ContinueWith(this.handleInvocationTaskResultDelegate, request.Id, TaskScheduler.Default).ConfigureAwait(false)); } catch (Exception ex) { return(CreateError(request.Id, ex)); } finally { if (ctsAdded) { lock (this.dispatcherMapLock) { this.inboundCancellationSources.Remove(request.Id); } } } }
private static JsonRpcMessage CreateError(JToken id, Exception exception) { if (exception == null) { throw new ArgumentNullException(nameof(exception)); } if (exception is TargetInvocationException || (exception is AggregateException && exception.InnerException != null)) { // Never let the outer (TargetInvocationException) escape because the inner is the interesting one to the caller, the outer is due to // the fact we are using reflection. exception = exception.InnerException; } var data = new { stack = exception.StackTrace, code = exception.HResult.ToString(CultureInfo.InvariantCulture) }; return(JsonRpcMessage.CreateError(id, JsonRpcErrorCode.InvocationError, exception.Message, data)); }
private JsonRpcMessage HandleInvocationTaskResult(JToken id, Task t) { if (t == null) { throw new ArgumentNullException(nameof(t)); } if (!t.IsCompleted) { throw new ArgumentException(Resources.TaskNotCompleted, nameof(t)); } if (t.IsFaulted) { return(CreateError(id, t.Exception)); } if (t.IsCanceled) { return(JsonRpcMessage.CreateError(id, JsonRpcErrorCode.InvocationError, Resources.TaskWasCancelled)); } object taskResult = null; Type taskType = t.GetType(); // If t is a Task<SomeType>, it will have Result property. // If t is just a Task, there is no Result property on it. if (!taskType.Equals(typeof(Task))) { #pragma warning disable VSTHRD002 // misfiring analyzer https://github.com/Microsoft/vs-threading/issues/60 #pragma warning disable VSTHRD102 // misfiring analyzer https://github.com/Microsoft/vs-threading/issues/60 const string ResultPropertyName = nameof(Task <int> .Result); #pragma warning restore VSTHRD002 #pragma warning restore VSTHRD102 // We can't really write direct code to deal with Task<T>, since we have no idea of T in this context, so we simply use reflection to // read the result at runtime. PropertyInfo resultProperty = taskType.GetTypeInfo().GetDeclaredProperty(ResultPropertyName); taskResult = resultProperty?.GetValue(t); } return(JsonRpcMessage.CreateResult(id, taskResult, this.JsonSerializer)); }