private void OnJsonRpcDisconnected(JsonRpcDisconnectedEventArgs eventArgs) { EventHandler <JsonRpcDisconnectedEventArgs> handlersToInvoke = null; lock (this.disconnectedEventLock) { if (!this.hasDisconnectedEventBeenRaised) { this.hasDisconnectedEventBeenRaised = true; handlersToInvoke = this.onDisconnected; this.onDisconnected = null; } } try { // Fire the event first so that subscribers can interact with a non-disposed stream handlersToInvoke?.Invoke(this, eventArgs); } finally { // Dispose the stream and cancel pending requests in the finally block // So this is executed even if Disconnected event handler throws. this.disposeCts.Cancel(); this.MessageHandler.Dispose(); this.CancelPendingRequests(); } }
/// <summary> /// Disposes managed and native resources held by this instance. /// </summary> /// <param name="disposing"><c>true</c> if being disposed; <c>false</c> if being finalized.</param> protected virtual void Dispose(bool disposing) { if (!this.disposed) { this.disposed = true; if (disposing) { var disconnectedEventArgs = new JsonRpcDisconnectedEventArgs(Resources.StreamDisposed, DisconnectedReason.Disposed); this.OnJsonRpcDisconnected(disconnectedEventArgs); } } }
private async Task HandleRpcAsync(string json) { JsonRpcMessage rpc; try { rpc = JsonRpcMessage.FromJson(json, this.MessageJsonDeserializerSettings); } catch (JsonException exception) { var e = new JsonRpcDisconnectedEventArgs(string.Format(CultureInfo.CurrentCulture, Resources.FailureDeserializingJsonRpc, json, exception.Message), DisconnectedReason.ParseError, json, exception); // Fatal error. Raise disconnected event. this.OnJsonRpcDisconnected(e); return; } if (rpc.IsRequest) { // We can't accept a request that requires a response if we can't write. Verify.Operation(rpc.IsNotification || this.MessageHandler.CanWrite, Resources.StreamMustBeWriteable); if (rpc.IsNotification && rpc.Method == CancelRequestSpecialMethod) { this.HandleCancellationNotification(rpc); return; } JsonRpcMessage result = await this.DispatchIncomingRequestAsync(rpc, this.JsonSerializer).ConfigureAwait(false); if (!rpc.IsNotification) { try { await this.TransmitAsync(result, this.disposeCts.Token).ConfigureAwait(false); } catch (OperationCanceledException) { } catch (ObjectDisposedException) { } catch (Exception exception) { var e = new JsonRpcDisconnectedEventArgs(string.Format(CultureInfo.CurrentCulture, Resources.ErrorWritingJsonRpcResult, exception.GetType().Name, exception.Message), DisconnectedReason.StreamError, exception); // Fatal error. Raise disconnected event. this.OnJsonRpcDisconnected(e); } } return; } if (rpc.IsResponse) { OutstandingCallData data = null; lock (this.dispatcherMapLock) { int id = (int)rpc.Id; if (this.resultDispatcherMap.TryGetValue(id, out data)) { this.resultDispatcherMap.Remove(id); } } if (data != null) { data.CompletionHandler(rpc); } return; } // Not a request or return. Raise disconnected event. this.OnJsonRpcDisconnected(new JsonRpcDisconnectedEventArgs( string.Format(CultureInfo.CurrentCulture, Resources.UnrecognizedIncomingJsonRpc, json), DisconnectedReason.ParseError, json)); }
private async Task ReadAndHandleRequestsAsync() { JsonRpcDisconnectedEventArgs disconnectedEventArgs = null; try { while (!this.disposed) { string json = null; try { json = await this.MessageHandler.ReadAsync(this.disposeCts.Token).ConfigureAwait(false); } catch (OperationCanceledException) { } catch (ObjectDisposedException) { } catch (Exception exception) { var e = new JsonRpcDisconnectedEventArgs(string.Format(CultureInfo.CurrentCulture, Resources.ReadingJsonRpcStreamFailed, exception.GetType().Name, exception.Message), DisconnectedReason.StreamError, exception); // Fatal error. Raise disconnected event. this.OnJsonRpcDisconnected(e); break; } if (json == null) { // End of stream reached disconnectedEventArgs = new JsonRpcDisconnectedEventArgs(Resources.ReachedEndOfStream, DisconnectedReason.Disposed); break; } #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed Task.Run(async delegate { try { await this.HandleRpcAsync(json).ConfigureAwait(false); } catch (Exception exception) { var eventArgs = new JsonRpcDisconnectedEventArgs( string.Format(CultureInfo.CurrentCulture, Resources.UnexpectedErrorProcessingJsonRpc, json, exception.Message), DisconnectedReason.ParseError, json, exception); // Fatal error. Raise disconnected event. this.OnJsonRpcDisconnected(eventArgs); } }, this.disposeCts.Token); #pragma warning restore CS4014 } } finally { if (disconnectedEventArgs == null) { disconnectedEventArgs = new JsonRpcDisconnectedEventArgs(Resources.StreamDisposed, DisconnectedReason.Disposed); } this.OnJsonRpcDisconnected(disconnectedEventArgs); } }