diff --git a/src/StreamJsonRpc/JsonMessageFormatter.cs b/src/StreamJsonRpc/JsonMessageFormatter.cs index 2d92f931a..1e883630b 100644 --- a/src/StreamJsonRpc/JsonMessageFormatter.cs +++ b/src/StreamJsonRpc/JsonMessageFormatter.cs @@ -72,16 +72,24 @@ public class JsonMessageFormatter : IJsonRpcAsyncMessageTextFormatter, IJsonRpcF /// private readonly SequenceTextReader sequenceTextReader = new SequenceTextReader(); + /// + /// Backing field for the property. + /// + private MultiplexingStream? multiplexingStream; + /// /// instance containing useful methods to help on the implementation of message formatters. /// - private readonly MessageFormatterProgressTracker formatterProgressTracker = new MessageFormatterProgressTracker(); + private MessageFormatterProgressTracker? formatterProgressTracker; /// /// The helper for marshaling pipes as RPC method arguments. /// - private readonly MessageFormatterDuplexPipeTracker duplexPipeTracker = new MessageFormatterDuplexPipeTracker(); + private MessageFormatterDuplexPipeTracker? duplexPipeTracker; + /// + /// The helper for marshaling in RPC method arguments or return values. + /// private MessageFormatterEnumerableTracker? enumerableTracker; /// @@ -212,11 +220,11 @@ public Version ProtocolVersion /// public MultiplexingStream? MultiplexingStream { - get => this.duplexPipeTracker.MultiplexingStream; + get => this.multiplexingStream; set { Verify.Operation(this.rpc == null, Resources.FormatterConfigurationLockedAfterJsonRpcAssigned); - this.duplexPipeTracker.MultiplexingStream = value; + this.multiplexingStream = value; } } @@ -230,7 +238,9 @@ JsonRpc IJsonRpcInstanceContainer.Rpc if (value != null) { + this.formatterProgressTracker = new MessageFormatterProgressTracker(value, this); this.enumerableTracker = new MessageFormatterEnumerableTracker(value, this); + this.duplexPipeTracker = new MessageFormatterDuplexPipeTracker(value, this) { MultiplexingStream = this.multiplexingStream }; } } } @@ -244,6 +254,42 @@ JsonRpc IJsonRpcInstanceContainer.Rpc /// bool IJsonRpcFormatterState.SerializingRequest => this.serializingRequest; + /// + /// Gets the instance containing useful methods to help on the implementation of message formatters. + /// + private MessageFormatterProgressTracker FormatterProgressTracker + { + get + { + Assumes.NotNull(this.formatterProgressTracker); // This should have been set in the Rpc property setter. + return this.formatterProgressTracker; + } + } + + /// + /// Gets the helper for marshaling pipes as RPC method arguments. + /// + private MessageFormatterDuplexPipeTracker DuplexPipeTracker + { + get + { + Assumes.NotNull(this.duplexPipeTracker); // This should have been set in the Rpc property setter. + return this.duplexPipeTracker; + } + } + + /// + /// Gets the helper for marshaling in RPC method arguments or return values. + /// + private MessageFormatterEnumerableTracker EnumerableTracker + { + get + { + Assumes.NotNull(this.enumerableTracker); // This should have been set in the Rpc property setter. + return this.enumerableTracker; + } + } + /// public JsonRpcMessage Deserialize(ReadOnlySequence contentBuffer) => this.Deserialize(contentBuffer, this.Encoding); @@ -332,11 +378,6 @@ public JsonRpcMessage Deserialize(JToken json) /// The JSON of the message. public JToken Serialize(JsonRpcMessage message) { - if (message is IJsonRpcMessageWithId msgWithId && (message is JsonRpcResult || message is JsonRpcError)) - { - this.duplexPipeTracker.OnResponseSent(msgWithId.RequestId, successful: msgWithId is JsonRpcResult); - } - this.observedTransmittedRequestWithStringId |= message is JsonRpcRequest request && request.RequestId.String != null; // Pre-tokenize the user data so we can use their custom converters for just their data and not for the base message. @@ -365,7 +406,7 @@ public JToken Serialize(JsonRpcMessage message) /// public void Dispose() { - this.duplexPipeTracker.Dispose(); + this.duplexPipeTracker?.Dispose(); } private static IReadOnlyDictionary PartiallyParseNamedArguments(JObject args) @@ -465,8 +506,6 @@ private void TokenizeUserData(JsonRpcMessage jsonRpcMessage) if (jsonRpcMessage is Protocol.JsonRpcRequest request) { this.serializingRequest = true; - this.formatterProgressTracker.RequestIdBeingSerialized = request.RequestId; - this.duplexPipeTracker.RequestIdBeingSerialized = request.RequestId; if (request.ArgumentsList != null) { @@ -493,8 +532,6 @@ private void TokenizeUserData(JsonRpcMessage jsonRpcMessage) { this.serializingMessageWithId = default; this.serializingRequest = false; - this.formatterProgressTracker.RequestIdBeingSerialized = default; - this.duplexPipeTracker.RequestIdBeingSerialized = default; } } @@ -535,7 +572,7 @@ private JsonRpcRequest ReadRequest(JToken json) // If method is $/progress, get the progress instance from the dictionary and call Report string method = json.Value("method"); - if (string.Equals(method, MessageFormatterProgressTracker.ProgressRequestSpecialMethod, StringComparison.Ordinal)) + if (this.formatterProgressTracker != null && string.Equals(method, MessageFormatterProgressTracker.ProgressRequestSpecialMethod, StringComparison.Ordinal)) { try { @@ -578,9 +615,6 @@ private JsonRpcResult ReadResult(JToken json) JToken result = json["result"]; - this.formatterProgressTracker.OnResponseReceived(id); - this.duplexPipeTracker.OnResponseReceived(id, successful: true); - return new JsonRpcResult(this.JsonSerializer) { RequestId = id, @@ -595,9 +629,6 @@ private JsonRpcError ReadError(JToken json) RequestId id = this.NormalizeId(json["id"].ToObject()); JToken error = json["error"]; - this.formatterProgressTracker.OnResponseReceived(id); - this.duplexPipeTracker.OnResponseReceived(id, successful: false); - return new JsonRpcError { RequestId = id, @@ -679,7 +710,6 @@ public override bool TryGetArgumentByNameOrIndex(string? name, int position, Typ // Deserialization of messages should never occur concurrently for a single instance of a formatter. Assumes.True(this.formatter.deserializingMessageWithId.IsEmpty); this.formatter.deserializingMessageWithId = this.RequestId; - this.formatter.duplexPipeTracker.RequestIdBeingDeserialized = this.RequestId; try { value = token?.ToObject(typeHint, this.formatter.JsonSerializer); @@ -687,7 +717,6 @@ public override bool TryGetArgumentByNameOrIndex(string? name, int position, Typ finally { this.formatter.deserializingMessageWithId = default; - this.formatter.duplexPipeTracker.RequestIdBeingDeserialized = default; } return true; @@ -801,7 +830,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object? exis public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - long progressId = this.formatter.formatterProgressTracker.GetTokenForProgress(value); + long progressId = this.formatter.FormatterProgressTracker.GetTokenForProgress(value); writer.WriteValue(progressId); } } @@ -832,7 +861,7 @@ public override bool CanConvert(Type objectType) Assumes.NotNull(this.formatter.rpc); JToken token = JToken.Load(reader); - return this.formatter.formatterProgressTracker.CreateProgress(this.formatter.rpc, token, objectType); + return this.formatter.FormatterProgressTracker.CreateProgress(this.formatter.rpc, token, objectType); } public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) @@ -853,7 +882,7 @@ internal AsyncEnumerableConsumerConverter(JsonMessageFormatter jsonMessageFormat this.formatter = jsonMessageFormatter; } - public override bool CanConvert(Type objectType) => this.formatter.enumerableTracker != null && MessageFormatterEnumerableTracker.CanDeserialize(objectType); + public override bool CanConvert(Type objectType) => MessageFormatterEnumerableTracker.CanDeserialize(objectType); public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { @@ -862,9 +891,8 @@ internal AsyncEnumerableConsumerConverter(JsonMessageFormatter jsonMessageFormat return null; } - Assumes.NotNull(this.formatter.enumerableTracker); JToken token = JToken.Load(reader); - return this.formatter.enumerableTracker.CreateEnumerableProxy(objectType, token); + return this.formatter.EnumerableTracker.CreateEnumerableProxy(objectType, token); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) @@ -885,7 +913,7 @@ internal AsyncEnumerableGeneratorConverter(JsonMessageFormatter jsonMessageForma this.formatter = jsonMessageFormatter; } - public override bool CanConvert(Type objectType) => this.formatter.enumerableTracker != null && MessageFormatterEnumerableTracker.CanSerialize(objectType); + public override bool CanConvert(Type objectType) => MessageFormatterEnumerableTracker.CanSerialize(objectType); public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { @@ -894,9 +922,7 @@ internal AsyncEnumerableGeneratorConverter(JsonMessageFormatter jsonMessageForma public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - Assumes.NotNull(this.formatter.enumerableTracker); - - long token = this.formatter.enumerableTracker.GetToken(value); + long token = this.formatter.EnumerableTracker.GetToken(value); writer.WriteValue(token); } } @@ -913,12 +939,12 @@ public DuplexPipeConverter(JsonMessageFormatter jsonMessageFormatter) public override IDuplexPipe? ReadJson(JsonReader reader, Type objectType, IDuplexPipe? existingValue, bool hasExistingValue, JsonSerializer serializer) { int? tokenId = JToken.Load(reader).Value(); - return this.jsonMessageFormatter.duplexPipeTracker.GetPipe(tokenId); + return this.jsonMessageFormatter.duplexPipeTracker!.GetPipe(tokenId); } public override void WriteJson(JsonWriter writer, IDuplexPipe? value, JsonSerializer serializer) { - var token = this.jsonMessageFormatter.duplexPipeTracker.GetToken(value); + var token = this.jsonMessageFormatter.duplexPipeTracker!.GetToken(value); writer.WriteValue(token); } } @@ -935,12 +961,12 @@ public PipeReaderConverter(JsonMessageFormatter jsonMessageFormatter) public override PipeReader? ReadJson(JsonReader reader, Type objectType, PipeReader? existingValue, bool hasExistingValue, JsonSerializer serializer) { int? tokenId = JToken.Load(reader).Value(); - return this.jsonMessageFormatter.duplexPipeTracker.GetPipeReader(tokenId); + return this.jsonMessageFormatter.DuplexPipeTracker.GetPipeReader(tokenId); } public override void WriteJson(JsonWriter writer, PipeReader? value, JsonSerializer serializer) { - var token = this.jsonMessageFormatter.duplexPipeTracker.GetToken(value); + var token = this.jsonMessageFormatter.DuplexPipeTracker.GetToken(value); writer.WriteValue(token); } } @@ -957,12 +983,12 @@ public PipeWriterConverter(JsonMessageFormatter jsonMessageFormatter) public override PipeWriter? ReadJson(JsonReader reader, Type objectType, PipeWriter? existingValue, bool hasExistingValue, JsonSerializer serializer) { int? tokenId = JToken.Load(reader).Value(); - return this.jsonMessageFormatter.duplexPipeTracker.GetPipeWriter(tokenId); + return this.jsonMessageFormatter.DuplexPipeTracker.GetPipeWriter(tokenId); } public override void WriteJson(JsonWriter writer, PipeWriter? value, JsonSerializer serializer) { - var token = this.jsonMessageFormatter.duplexPipeTracker.GetToken(value); + var token = this.jsonMessageFormatter.DuplexPipeTracker.GetToken(value); writer.WriteValue(token); } } @@ -979,12 +1005,12 @@ public StreamConverter(JsonMessageFormatter jsonMessageFormatter) public override Stream? ReadJson(JsonReader reader, Type objectType, Stream? existingValue, bool hasExistingValue, JsonSerializer serializer) { int? tokenId = JToken.Load(reader).Value(); - return this.jsonMessageFormatter.duplexPipeTracker.GetPipe(tokenId)?.AsStream(); + return this.jsonMessageFormatter.DuplexPipeTracker.GetPipe(tokenId)?.AsStream(); } public override void WriteJson(JsonWriter writer, Stream? value, JsonSerializer serializer) { - var token = this.jsonMessageFormatter.duplexPipeTracker.GetToken(value?.UsePipe()); + var token = this.jsonMessageFormatter.DuplexPipeTracker.GetToken(value?.UsePipe()); writer.WriteValue(token); } } diff --git a/src/StreamJsonRpc/JsonRpc.cs b/src/StreamJsonRpc/JsonRpc.cs index 4e6f5b52c..32d167684 100644 --- a/src/StreamJsonRpc/JsonRpc.cs +++ b/src/StreamJsonRpc/JsonRpc.cs @@ -132,9 +132,20 @@ public class JsonRpc : IDisposableObservable, IJsonRpcFormatterCallbacks [DebuggerBrowsable(DebuggerBrowsableState.Never)] private SynchronizationContext? synchronizationContext; - private EventHandler? requestTransmissionAborted; - private EventHandler? resultReceived; - private EventHandler? errorReceived; + /// + /// Backing field for the event. + /// + private EventHandler? requestTransmissionAborted; + + /// + /// Backing field for the event. + /// + private EventHandler? responseReceived; + + /// + /// Backing field for the event. + /// + private EventHandler? responseSent; /// /// Initializes a new instance of the class that uses @@ -239,22 +250,25 @@ public event EventHandler? Disconnected } } - event EventHandler IJsonRpcFormatterCallbacks.RequestTransmissionAborted + /// + event EventHandler IJsonRpcFormatterCallbacks.RequestTransmissionAborted { add => this.requestTransmissionAborted += value; remove => this.requestTransmissionAborted -= value; } - event EventHandler IJsonRpcFormatterCallbacks.ResultReceived + /// + event EventHandler IJsonRpcFormatterCallbacks.ResponseReceived { - add => this.resultReceived += value; - remove => this.resultReceived -= value; + add => this.responseReceived += value; + remove => this.responseReceived -= value; } - event EventHandler IJsonRpcFormatterCallbacks.ErrorReceived + /// + event EventHandler IJsonRpcFormatterCallbacks.ResponseSent { - add => this.errorReceived += value; - remove => this.errorReceived -= value; + add => this.responseSent += value; + remove => this.responseSent -= value; } private event EventHandler? DisconnectedPrivate; @@ -1302,21 +1316,21 @@ protected virtual void OnRequestTransmissionAborted(JsonRpcRequest request) { if (!request.RequestId.IsEmpty) { - this.requestTransmissionAborted?.Invoke(this, new JsonRpcFormatterCallbackEventArgs(request)); + this.requestTransmissionAborted?.Invoke(this, new JsonRpcMessageEventArgs(request)); } } /// - /// Raises the event. + /// Raises the event. /// - /// The result that was received. - protected virtual void OnResultReceived(JsonRpcResult result) => this.resultReceived?.Invoke(this, new JsonRpcFormatterCallbackEventArgs(result)); + /// The result or error that was received. + protected virtual void OnResponseReceived(JsonRpcMessage response) => this.responseReceived?.Invoke(this, new JsonRpcResponseEventArgs((IJsonRpcMessageWithId)response)); /// - /// Raises the event. + /// Raises the event. /// - /// The error that was received. - protected virtual void OnErrorReceived(JsonRpcError error) => this.errorReceived?.Invoke(this, new JsonRpcFormatterCallbackEventArgs(error)); + /// The result or error that was sent. + protected virtual void OnResponseSent(JsonRpcMessage response) => this.responseSent?.Invoke(this, new JsonRpcResponseEventArgs((IJsonRpcMessageWithId)response)); /// /// Creates a dictionary which maps a request method name to its clr method name via value. @@ -2181,6 +2195,7 @@ private async Task HandleRpcAsync(JsonRpcMessage rpc) try { await this.TransmitAsync(result, this.DisconnectedToken).ConfigureAwait(false); + this.OnResponseSent(result); } catch (OperationCanceledException) when (this.DisconnectedToken.IsCancellationRequested) { @@ -2202,16 +2217,9 @@ private async Task HandleRpcAsync(JsonRpcMessage rpc) } else if (rpc is IJsonRpcMessageWithId resultOrError) { + this.OnResponseReceived(rpc); JsonRpcResult? result = resultOrError as JsonRpcResult; JsonRpcError? error = resultOrError as JsonRpcError; - if (result != null) - { - this.OnResultReceived(result); - } - else if (error != null) - { - this.OnErrorReceived(error); - } OutstandingCallData? data = null; lock (this.dispatcherMapLock) diff --git a/src/StreamJsonRpc/MessagePackFormatter.cs b/src/StreamJsonRpc/MessagePackFormatter.cs index 3559a5969..865f7fdec 100644 --- a/src/StreamJsonRpc/MessagePackFormatter.cs +++ b/src/StreamJsonRpc/MessagePackFormatter.cs @@ -43,16 +43,6 @@ public class MessagePackFormatter : IJsonRpcMessageFormatter, IJsonRpcInstanceCo private const string ErrorPropertyName = "error"; - /// - /// instance containing useful methods to help on the implementation of message formatters. - /// - private readonly MessageFormatterProgressTracker formatterProgressTracker = new MessageFormatterProgressTracker(); - - /// - /// The helper for marshaling pipes as RPC method arguments. - /// - private readonly MessageFormatterDuplexPipeTracker duplexPipeTracker = new MessageFormatterDuplexPipeTracker(); - /// /// The options to use for serializing top-level RPC messages. /// @@ -64,6 +54,24 @@ public class MessagePackFormatter : IJsonRpcMessageFormatter, IJsonRpcInstanceCo private readonly PipeFormatterResolver pipeFormatterResolver; + /// + /// Backing field for the property. + /// + private MultiplexingStream? multiplexingStream; + + /// + /// The we use to support method arguments. + /// + private MessageFormatterProgressTracker? formatterProgressTracker; + + /// + /// The helper for marshaling pipes as RPC method arguments. + /// + private MessageFormatterDuplexPipeTracker? duplexPipeTracker; + + /// + /// The tracker we use to support transmission of types. + /// private MessageFormatterEnumerableTracker? enumerableTracker; /// @@ -154,6 +162,8 @@ JsonRpc IJsonRpcInstanceContainer.Rpc if (value != null) { + this.formatterProgressTracker = new MessageFormatterProgressTracker(value, this); + this.duplexPipeTracker = new MessageFormatterDuplexPipeTracker(value, this) { MultiplexingStream = this.multiplexingStream }; this.enumerableTracker = new MessageFormatterEnumerableTracker(value, this); } } @@ -164,11 +174,11 @@ JsonRpc IJsonRpcInstanceContainer.Rpc /// public MultiplexingStream? MultiplexingStream { - get => this.duplexPipeTracker.MultiplexingStream; + get => this.multiplexingStream; set { Verify.Operation(this.rpc == null, Resources.FormatterConfigurationLockedAfterJsonRpcAssigned); - this.duplexPipeTracker.MultiplexingStream = value; + this.multiplexingStream = value; } } @@ -181,6 +191,42 @@ public MultiplexingStream? MultiplexingStream /// bool IJsonRpcFormatterState.SerializingRequest => this.serializingRequest; + /// + /// Gets the instance containing useful methods to help on the implementation of message formatters. + /// + private MessageFormatterProgressTracker FormatterProgressTracker + { + get + { + Assumes.NotNull(this.formatterProgressTracker); // This should have been set in the Rpc property setter. + return this.formatterProgressTracker; + } + } + + /// + /// Gets the helper for marshaling pipes as RPC method arguments. + /// + private MessageFormatterDuplexPipeTracker DuplexPipeTracker + { + get + { + Assumes.NotNull(this.duplexPipeTracker); // This should have been set in the Rpc property setter. + return this.duplexPipeTracker; + } + } + + /// + /// Gets the helper for marshaling in RPC method arguments or return values. + /// + private MessageFormatterEnumerableTracker EnumerableTracker + { + get + { + Assumes.NotNull(this.enumerableTracker); // This should have been set in the Rpc property setter. + return this.enumerableTracker; + } + } + /// /// Sets the to use for serialization of user data. /// @@ -198,11 +244,6 @@ public void SetMessagePackSerializerOptions(MessagePackSerializerOptions options /// public void Serialize(IBufferWriter contentBuffer, JsonRpcMessage message) { - if (message is IJsonRpcMessageWithId msgWithId && (message is Protocol.JsonRpcResult || message is Protocol.JsonRpcError)) - { - this.duplexPipeTracker.OnResponseSent(msgWithId.RequestId, successful: msgWithId is Protocol.JsonRpcResult); - } - if (message is Protocol.JsonRpcRequest request && request.Arguments != null && request.ArgumentsList == null && !(request.Arguments is IReadOnlyDictionary)) { // This request contains named arguments, but not using a standard dictionary. Convert it to a dictionary so that @@ -221,7 +262,7 @@ public void Serialize(IBufferWriter contentBuffer, JsonRpcMessage message) /// public void Dispose() { - this.duplexPipeTracker.Dispose(); + this.duplexPipeTracker?.Dispose(); } /// @@ -513,7 +554,7 @@ public void Serialize(ref MessagePackWriter writer, TClass value, MessagePackSer } else { - long progressId = this.formatter.formatterProgressTracker.GetTokenForProgress(value); + long progressId = this.formatter.FormatterProgressTracker.GetTokenForProgress(value); writer.Write(progressId); } } @@ -541,7 +582,7 @@ public TClass Deserialize(ref MessagePackReader reader, MessagePackSerializerOpt Assumes.NotNull(this.formatter.rpc); RawMessagePack token = RawMessagePack.ReadRaw(ref reader, copy: true); - return (TClass)this.formatter.formatterProgressTracker.CreateProgress(this.formatter.rpc, token, typeof(TClass)); + return (TClass)this.formatter.FormatterProgressTracker.CreateProgress(this.formatter.rpc, token, typeof(TClass)); } public void Serialize(ref MessagePackWriter writer, TClass value, MessagePackSerializerOptions options) @@ -552,7 +593,7 @@ public void Serialize(ref MessagePackWriter writer, TClass value, MessagePackSer } else { - long progressId = this.formatter.formatterProgressTracker.GetTokenForProgress(value); + long progressId = this.formatter.FormatterProgressTracker.GetTokenForProgress(value); writer.Write(progressId); } } @@ -724,12 +765,12 @@ public DuplexPipeFormatter(MessagePackFormatter formatter) return null; } - return (T)this.formatter.duplexPipeTracker.GetPipe(reader.ReadInt32()); + return (T)this.formatter.DuplexPipeTracker.GetPipe(reader.ReadInt32()); } public void Serialize(ref MessagePackWriter writer, T? value, MessagePackSerializerOptions options) { - if (this.formatter.duplexPipeTracker.GetToken(value) is { } token) + if (this.formatter.DuplexPipeTracker.GetToken(value) is { } token) { writer.Write(token); } @@ -757,12 +798,12 @@ public PipeReaderFormatter(MessagePackFormatter formatter) return null; } - return (T)this.formatter.duplexPipeTracker.GetPipeReader(reader.ReadInt32()); + return (T)this.formatter.DuplexPipeTracker.GetPipeReader(reader.ReadInt32()); } public void Serialize(ref MessagePackWriter writer, T? value, MessagePackSerializerOptions options) { - if (this.formatter.duplexPipeTracker.GetToken(value) is { } token) + if (this.formatter.DuplexPipeTracker.GetToken(value) is { } token) { writer.Write(token); } @@ -790,12 +831,12 @@ public PipeWriterFormatter(MessagePackFormatter formatter) return null; } - return (T)this.formatter.duplexPipeTracker.GetPipeWriter(reader.ReadInt32()); + return (T)this.formatter.DuplexPipeTracker.GetPipeWriter(reader.ReadInt32()); } public void Serialize(ref MessagePackWriter writer, T? value, MessagePackSerializerOptions options) { - if (this.formatter.duplexPipeTracker.GetToken(value) is { } token) + if (this.formatter.DuplexPipeTracker.GetToken(value) is { } token) { writer.Write(token); } @@ -823,12 +864,12 @@ public StreamFormatter(MessagePackFormatter formatter) return null; } - return (T)this.formatter.duplexPipeTracker.GetPipe(reader.ReadInt32()).AsStream(); + return (T)this.formatter.DuplexPipeTracker.GetPipe(reader.ReadInt32()).AsStream(); } public void Serialize(ref MessagePackWriter writer, T? value, MessagePackSerializerOptions options) { - if (this.formatter.duplexPipeTracker.GetToken(value?.UsePipe()) is { } token) + if (this.formatter.DuplexPipeTracker.GetToken(value?.UsePipe()) is { } token) { writer.Write(token); } @@ -987,7 +1028,7 @@ public Protocol.JsonRpcRequest Deserialize(ref MessagePackReader reader, Message if (result.TryGetArgumentByNameOrIndex("token", 0, typeof(long), out object? tokenObject) && tokenObject is long progressId) { MessageFormatterProgressTracker.ProgressParamInformation? progressInfo = null; - if (this.formatter.formatterProgressTracker.TryGetProgressObject(progressId, out progressInfo)) + if (this.formatter.FormatterProgressTracker.TryGetProgressObject(progressId, out progressInfo)) { if (result.TryGetArgumentByNameOrIndex("value", 1, progressInfo.ValueType, out object? value)) { @@ -1007,49 +1048,38 @@ public Protocol.JsonRpcRequest Deserialize(ref MessagePackReader reader, Message public void Serialize(ref MessagePackWriter writer, Protocol.JsonRpcRequest value, MessagePackSerializerOptions options) { - try - { - this.formatter.formatterProgressTracker.RequestIdBeingSerialized = value.RequestId; - this.formatter.duplexPipeTracker.RequestIdBeingSerialized = value.RequestId; + writer.WriteMapHeader(4); - writer.WriteMapHeader(4); - - writer.Write(VersionPropertyName); - writer.Write(value.Version); + writer.Write(VersionPropertyName); + writer.Write(value.Version); - writer.Write(IdPropertyName); - options.Resolver.GetFormatterWithVerify().Serialize(ref writer, value.RequestId, options); + writer.Write(IdPropertyName); + options.Resolver.GetFormatterWithVerify().Serialize(ref writer, value.RequestId, options); - writer.Write(MethodPropertyName); - writer.Write(value.Method); + writer.Write(MethodPropertyName); + writer.Write(value.Method); - writer.Write(ParamsPropertyName); - if (value.ArgumentsList != null) - { - writer.WriteArrayHeader(value.ArgumentsList.Count); - foreach (var arg in value.ArgumentsList) - { - this.formatter.dynamicObjectTypeFormatterForUserSuppliedResolver.Serialize(ref writer, arg, this.formatter.userDataSerializationOptions); - } - } - else if (value.NamedArguments != null) + writer.Write(ParamsPropertyName); + if (value.ArgumentsList != null) + { + writer.WriteArrayHeader(value.ArgumentsList.Count); + foreach (var arg in value.ArgumentsList) { - writer.WriteMapHeader(value.NamedArguments.Count); - foreach (KeyValuePair entry in value.NamedArguments) - { - writer.Write(entry.Key); - this.formatter.dynamicObjectTypeFormatterForUserSuppliedResolver.Serialize(ref writer, entry.Value, this.formatter.userDataSerializationOptions); - } + this.formatter.dynamicObjectTypeFormatterForUserSuppliedResolver.Serialize(ref writer, arg, this.formatter.userDataSerializationOptions); } - else + } + else if (value.NamedArguments != null) + { + writer.WriteMapHeader(value.NamedArguments.Count); + foreach (KeyValuePair entry in value.NamedArguments) { - writer.WriteNil(); + writer.Write(entry.Key); + this.formatter.dynamicObjectTypeFormatterForUserSuppliedResolver.Serialize(ref writer, entry.Value, this.formatter.userDataSerializationOptions); } } - finally + else { - this.formatter.formatterProgressTracker.RequestIdBeingSerialized = default; - this.formatter.duplexPipeTracker.RequestIdBeingSerialized = default; + writer.WriteNil(); } } } @@ -1087,9 +1117,6 @@ public Protocol.JsonRpcResult Deserialize(ref MessagePackReader reader, MessageP } } - this.formatter.formatterProgressTracker.OnResponseReceived(result.RequestId); - this.formatter.duplexPipeTracker.OnResponseReceived(result.RequestId, successful: true); - return result; } @@ -1141,9 +1168,6 @@ public Protocol.JsonRpcError Deserialize(ref MessagePackReader reader, MessagePa } } - this.formatter.formatterProgressTracker.OnResponseReceived(error.RequestId); - this.formatter.duplexPipeTracker.OnResponseReceived(error.RequestId, successful: false); - return error; } @@ -1302,7 +1326,6 @@ public override bool TryGetArgumentByNameOrIndex(string? name, int position, Typ // Deserialization of messages should never occur concurrently for a single instance of a formatter. Assumes.True(this.formatter.deserializingMessageWithId.IsEmpty); this.formatter.deserializingMessageWithId = this.RequestId; - this.formatter.duplexPipeTracker.RequestIdBeingDeserialized = this.RequestId; value = MessagePackSerializer.Deserialize(typeHint ?? typeof(object), ref reader, this.formatter.userDataSerializationOptions); return true; @@ -1321,7 +1344,6 @@ public override bool TryGetArgumentByNameOrIndex(string? name, int position, Typ finally { this.formatter.deserializingMessageWithId = default; - this.formatter.duplexPipeTracker.RequestIdBeingDeserialized = default; } } } diff --git a/src/StreamJsonRpc/Reflection/IJsonRpcFormatterCallbacks.cs b/src/StreamJsonRpc/Reflection/IJsonRpcFormatterCallbacks.cs index 26a7be8b2..702283082 100644 --- a/src/StreamJsonRpc/Reflection/IJsonRpcFormatterCallbacks.cs +++ b/src/StreamJsonRpc/Reflection/IJsonRpcFormatterCallbacks.cs @@ -4,8 +4,6 @@ namespace StreamJsonRpc.Reflection { using System; - using Microsoft; - using StreamJsonRpc.Protocol; /// /// Implemented by to expose callbacks allowing an to perform resource cleanup. @@ -18,48 +16,16 @@ public interface IJsonRpcFormatterCallbacks /// /// This usually occurs because of an exception during serialization or transmission, possibly due to cancellation. /// - event EventHandler RequestTransmissionAborted; + event EventHandler RequestTransmissionAborted; /// - /// Occurs when receives a successful response to a previously sent request. + /// Occurs when receives a response to a previously sent request. /// - event EventHandler ResultReceived; + event EventHandler ResponseReceived; /// - /// Occurs when receives an error response to a previously sent request. + /// Occurs when transmits a response message. /// - event EventHandler ErrorReceived; - } - - /// - /// The data passed to event handlers. - /// - public class JsonRpcFormatterCallbackEventArgs : EventArgs - { - /// - /// Initializes a new instance of the class. - /// - /// The ID from the request or response that the event is regarding. - public JsonRpcFormatterCallbackEventArgs(RequestId requestId) - { - Requires.Argument(!requestId.IsEmpty, nameof(requestId), "Non-default ID required."); - this.RequestId = requestId; - } - - /// - /// Initializes a new instance of the class. - /// - /// The message the event is regarding. - internal JsonRpcFormatterCallbackEventArgs(IJsonRpcMessageWithId message) - { - Requires.NotNull(message, nameof(message)); - Requires.Argument(!message.RequestId.IsEmpty, nameof(message), "Non-default ID required."); - this.RequestId = message.RequestId; - } - - /// - /// Gets the id on the request, result or error. - /// - public RequestId RequestId { get; private set; } + event EventHandler ResponseSent; } } diff --git a/src/StreamJsonRpc/Reflection/JsonRpcMessageEventArgs.cs b/src/StreamJsonRpc/Reflection/JsonRpcMessageEventArgs.cs new file mode 100644 index 000000000..a815bf777 --- /dev/null +++ b/src/StreamJsonRpc/Reflection/JsonRpcMessageEventArgs.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace StreamJsonRpc.Reflection +{ + using System; + using Microsoft; + using StreamJsonRpc.Protocol; + + /// + /// Carries the from request or response messages. + /// + public class JsonRpcMessageEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The ID from the request or response that the event is regarding. + public JsonRpcMessageEventArgs(RequestId requestId) + { + Requires.Argument(!requestId.IsEmpty, nameof(requestId), "Non-default ID required."); + this.RequestId = requestId; + } + + /// + /// Initializes a new instance of the class. + /// + /// The message the event is regarding. + internal JsonRpcMessageEventArgs(IJsonRpcMessageWithId message) + { + Requires.NotNull(message, nameof(message)); + Requires.Argument(!message.RequestId.IsEmpty, nameof(message), "Non-default ID required."); + this.RequestId = message.RequestId; + } + + /// + /// Gets the id on the request, result or error. + /// + public RequestId RequestId { get; private set; } + } +} diff --git a/src/StreamJsonRpc/Reflection/JsonRpcResponseEventArgs.cs b/src/StreamJsonRpc/Reflection/JsonRpcResponseEventArgs.cs new file mode 100644 index 000000000..60ce5689d --- /dev/null +++ b/src/StreamJsonRpc/Reflection/JsonRpcResponseEventArgs.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace StreamJsonRpc.Reflection +{ + using System; + using Microsoft; + using StreamJsonRpc.Protocol; + + /// + /// Carries the and success status of response messages. + /// + public class JsonRpcResponseEventArgs : JsonRpcMessageEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The ID from the request or response that the event is regarding. + /// A flag indicating whether the response is a result (as opposed to an error). + public JsonRpcResponseEventArgs(RequestId requestId, bool isSuccessfulResponse) + : base(requestId) + { + this.IsSuccessfulResponse = isSuccessfulResponse; + } + + /// + /// Initializes a new instance of the class. + /// + /// The message the event is regarding. + internal JsonRpcResponseEventArgs(IJsonRpcMessageWithId message) + : this(message.RequestId, message is JsonRpcResult) + { + } + + /// + /// Gets a value indicating whether the response is a result (as opposed to an error). + /// + public bool IsSuccessfulResponse { get; } + } +} diff --git a/src/StreamJsonRpc/Reflection/MessageFormatterDuplexPipeTracker.cs b/src/StreamJsonRpc/Reflection/MessageFormatterDuplexPipeTracker.cs index cf9f3cb00..93f37c00a 100644 --- a/src/StreamJsonRpc/Reflection/MessageFormatterDuplexPipeTracker.cs +++ b/src/StreamJsonRpc/Reflection/MessageFormatterDuplexPipeTracker.cs @@ -29,6 +29,11 @@ namespace StreamJsonRpc.Reflection /// public class MessageFormatterDuplexPipeTracker : IDisposableObservable { + /// + /// The formatter that owns this tracker. + /// + private readonly IJsonRpcFormatterState formatterState; + /// /// A map of outbound request IDs to channels that they included. /// @@ -57,19 +62,21 @@ public class MessageFormatterDuplexPipeTracker : IDisposableObservable /// /// Initializes a new instance of the class. /// - public MessageFormatterDuplexPipeTracker() + /// The instance that may be used to send or receive RPC messages related to . + /// The formatter that owns this tracker. + public MessageFormatterDuplexPipeTracker(JsonRpc jsonRpc, IJsonRpcFormatterState formatterState) { - } + Requires.NotNull(jsonRpc, nameof(jsonRpc)); + Requires.NotNull(formatterState, nameof(formatterState)); - /// - /// Gets or sets the id of the request currently being serialized for use as a key in . - /// - public RequestId RequestIdBeingSerialized { get; set; } + this.formatterState = formatterState; - /// - /// Gets or sets the ID of the request currently being deserialized for use as a key in . - /// - public RequestId RequestIdBeingDeserialized { get; set; } + // We don't offer a way to remove these handlers because this object should has a lifetime closely tied to the JsonRpc object anyway. + IJsonRpcFormatterCallbacks callbacks = jsonRpc; + callbacks.RequestTransmissionAborted += (s, e) => this.CleanUpOutboundResources(e.RequestId, successful: false); + callbacks.ResponseReceived += (s, e) => this.CleanUpOutboundResources(e.RequestId, successful: e.IsSuccessfulResponse); + callbacks.ResponseSent += (s, e) => this.CleanUpInboundResources(e.RequestId, successful: e.IsSuccessfulResponse); + } /// /// Gets or sets the multiplexing stream used to create and accept channels. @@ -82,16 +89,22 @@ public MessageFormatterDuplexPipeTracker() /// bool IDisposableObservable.IsDisposed => this.isDisposed; + /// + /// Gets the id of the request currently being serialized for use as a key in . + /// + private RequestId RequestIdBeingSerialized => this.formatterState.SerializingRequest ? this.formatterState.SerializingMessageWithId : default; + + /// + /// Gets the ID of the request currently being deserialized for use as a key in . + /// + private RequestId RequestIdBeingDeserialized => this.formatterState.DeserializingMessageWithId; + /// /// Creates a token to represent an as it is transmitted from the client to an RPC server as a method argument. /// /// The client pipe that is to be shared with the RPC server. May be null. /// The token to use as the RPC method argument; or null if was null. - /// - /// This method should only be called while serializing requests that include an ID (i.e. requests for which we expect a response). - /// When the response is received, a call should always be made to . - /// - /// Thrown if no was provided to the constructor. + /// Thrown if no was provided to the constructor or when serializing a message without an ID property. [return: NotNullIfNotNull("duplexPipe")] public int? GetToken(IDuplexPipe? duplexPipe) { @@ -128,11 +141,7 @@ public MessageFormatterDuplexPipeTracker() /// /// The client pipe that is to be shared with the RPC server. May be null. /// The token to use as the RPC method argument; or null if was null. - /// - /// This method should only be called while serializing requests that include an ID (i.e. requests for which we expect a response). - /// When the response is received, a call should always be made to . - /// - /// Thrown if no was provided to the constructor. + /// Thrown if no was provided to the constructor or when serializing a message without an ID property. [return: NotNullIfNotNull("reader")] public int? GetToken(PipeReader? reader) => this.GetToken(reader != null ? new DuplexPipe(reader) : null); @@ -141,11 +150,7 @@ public MessageFormatterDuplexPipeTracker() /// /// The client pipe that is to be shared with the RPC server. May be null. /// The token to use as the RPC method argument; or null if was null. - /// - /// This method should only be called while serializing requests that include an ID (i.e. requests for which we expect a response). - /// When the response is received, a call should always be made to . - /// - /// Thrown if no was provided to the constructor. + /// Thrown if no was provided to the constructor or when serializing a message without an ID property. [return: NotNullIfNotNull("writer")] public int? GetToken(PipeWriter? writer) => this.GetToken(writer != null ? new DuplexPipe(writer) : null); @@ -232,15 +237,34 @@ public MessageFormatterDuplexPipeTracker() return null; } - /// - /// Notifies this tracker when a response to any request is sent - /// so that appropriate channel and state cleanup can take place. - /// - /// The ID of the request for which a response was sent. - /// A value indicating whether the response represents a successful result (i.e. a instead of an ). - public void OnResponseSent(RequestId requestId, bool successful) + /// + public void Dispose() { - Verify.NotDisposed(this); + this.isDisposed = true; + + // Release memory and shutdown channels that outlived the RPC channel. + this.outboundRequestChannelMap = this.outboundRequestChannelMap.Clear(); + this.inboundRequestChannelMap = this.inboundRequestChannelMap.Clear(); + + ImmutableDictionary openInboundChannels = Interlocked.Exchange(ref this.openInboundChannels, this.openInboundChannels.Clear()); + foreach (KeyValuePair entry in openInboundChannels) + { + entry.Value.Dispose(); + } + + ImmutableDictionary openOutboundChannels = Interlocked.Exchange(ref this.openOutboundChannels, this.openOutboundChannels.Clear()); + foreach (KeyValuePair entry in openOutboundChannels) + { + entry.Value.Dispose(); + } + } + + private void CleanUpInboundResources(RequestId requestId, bool successful) + { + if (this.isDisposed) + { + return; + } if (ImmutableInterlocked.TryRemove(ref this.inboundRequestChannelMap, requestId, out ImmutableList channels)) { @@ -256,15 +280,12 @@ public void OnResponseSent(RequestId requestId, bool successful) } } - /// - /// Notifies this tracker when a response to any request is received - /// so that appropriate channel and state cleanup can take place. - /// - /// The ID of the request for which a response was received. - /// A value indicating whether the response represents a successful result (i.e. a instead of an ). - public void OnResponseReceived(RequestId requestId, bool successful) + private void CleanUpOutboundResources(RequestId requestId, bool successful) { - Verify.NotDisposed(this); + if (this.isDisposed) + { + return; + } if (ImmutableInterlocked.TryRemove(ref this.outboundRequestChannelMap, requestId, out ImmutableList channels)) { @@ -280,28 +301,6 @@ public void OnResponseReceived(RequestId requestId, bool successful) } } - /// - public void Dispose() - { - this.isDisposed = true; - - // Release memory and shutdown channels that outlived the RPC channel. - this.outboundRequestChannelMap = this.outboundRequestChannelMap.Clear(); - this.inboundRequestChannelMap = this.inboundRequestChannelMap.Clear(); - - ImmutableDictionary openInboundChannels = Interlocked.Exchange(ref this.openInboundChannels, this.openInboundChannels.Clear()); - foreach (KeyValuePair entry in openInboundChannels) - { - entry.Value.Dispose(); - } - - ImmutableDictionary openOutboundChannels = Interlocked.Exchange(ref this.openOutboundChannels, this.openOutboundChannels.Clear()); - foreach (KeyValuePair entry in openOutboundChannels) - { - entry.Value.Dispose(); - } - } - /// /// Throws if is null. /// diff --git a/src/StreamJsonRpc/Reflection/MessageFormatterEnumerableTracker.cs b/src/StreamJsonRpc/Reflection/MessageFormatterEnumerableTracker.cs index 3cbcae417..9db91a682 100644 --- a/src/StreamJsonRpc/Reflection/MessageFormatterEnumerableTracker.cs +++ b/src/StreamJsonRpc/Reflection/MessageFormatterEnumerableTracker.cs @@ -51,18 +51,20 @@ public class MessageFormatterEnumerableTracker /// The formatter that owns this tracker. public MessageFormatterEnumerableTracker(JsonRpc jsonRpc, IJsonRpcFormatterState formatterState) { - this.jsonRpc = jsonRpc ?? throw new ArgumentNullException(nameof(jsonRpc)); - this.formatterState = formatterState ?? throw new ArgumentNullException(nameof(formatterState)); + Requires.NotNull(jsonRpc, nameof(jsonRpc)); + Requires.NotNull(formatterState, nameof(formatterState)); - this.jsonRpc.AddLocalRpcMethod(NextMethodName, new Func>(this.OnNextAsync)); - this.jsonRpc.AddLocalRpcMethod(DisposeMethodName, new Func(this.OnDisposeAsync)); + this.jsonRpc = jsonRpc; + this.formatterState = formatterState; + + jsonRpc.AddLocalRpcMethod(NextMethodName, new Func>(this.OnNextAsync)); + jsonRpc.AddLocalRpcMethod(DisposeMethodName, new Func(this.OnDisposeAsync)); this.formatterState = formatterState; // We don't offer a way to remove these handlers because this object should has a lifetime closely tied to the JsonRpc object anyway. - IJsonRpcFormatterCallbacks callbacks = this.jsonRpc; - callbacks.RequestTransmissionAborted += this.JsonRpc_RequestTransmissionAborted; - callbacks.ResultReceived += this.JsonRpc_ResultReceived; - callbacks.ErrorReceived += this.JsonRpc_ErrorReceived; + IJsonRpcFormatterCallbacks callbacks = jsonRpc; + callbacks.RequestTransmissionAborted += (s, e) => this.CleanUpResources(e.RequestId); + callbacks.ResponseReceived += (s, e) => this.CleanUpResources(e.RequestId); } private interface IGeneratingEnumeratorTracker : System.IAsyncDisposable @@ -206,28 +208,7 @@ private ValueTask OnDisposeAsync(long token) return generator.DisposeAsync(); } - /// - /// Handles the event. - /// - /// The instance that raised the event. - /// The event args. - private void JsonRpc_ResultReceived(object sender, JsonRpcFormatterCallbackEventArgs e) => this.CleanUpResources(e.RequestId, error: false); - - /// - /// Handles the event. - /// - /// The instance that raised the event. - /// The event args. - private void JsonRpc_ErrorReceived(object sender, JsonRpcFormatterCallbackEventArgs e) => this.CleanUpResources(e.RequestId, error: true); - - /// - /// Handles the event. - /// - /// The instance that raised the event. - /// The event args. - private void JsonRpc_RequestTransmissionAborted(object sender, JsonRpcFormatterCallbackEventArgs e) => this.CleanUpResources(e.RequestId, error: true); - - private void CleanUpResources(RequestId requestId, bool error) + private void CleanUpResources(RequestId requestId) { lock (this.syncObject) { diff --git a/src/StreamJsonRpc/Reflection/MessageFormatterProgressTracker.cs b/src/StreamJsonRpc/Reflection/MessageFormatterProgressTracker.cs index 239737aea..dea7768b2 100644 --- a/src/StreamJsonRpc/Reflection/MessageFormatterProgressTracker.cs +++ b/src/StreamJsonRpc/Reflection/MessageFormatterProgressTracker.cs @@ -36,15 +36,37 @@ public class MessageFormatterProgressTracker /// private readonly object progressLock = new object(); + /// + /// State from the formatter that owns this tracker. + /// + private readonly IJsonRpcFormatterState formatterState; + /// /// Gets or sets the the next id value to assign as token for the progress objects. /// private long nextProgressId; /// - /// Gets or Sets the id of the request currently being serialized so the converter can use it to create the request-progress map. + /// Initializes a new instance of the class. + /// + /// The object that ultimately owns this tracker. + /// The formatter that owns this tracker. + public MessageFormatterProgressTracker(JsonRpc jsonRpc, IJsonRpcFormatterState formatterState) + { + Requires.NotNull(jsonRpc, nameof(jsonRpc)); + Requires.NotNull(formatterState, nameof(formatterState)); + + this.formatterState = formatterState; + + IJsonRpcFormatterCallbacks callbacks = jsonRpc; + callbacks.RequestTransmissionAborted += (s, e) => this.CleanUpResources(e.RequestId); + callbacks.ResponseReceived += (s, e) => this.CleanUpResources(e.RequestId); + } + + /// + /// Gets the id of the request currently being serialized so the converter can use it to create the request-progress map. /// - public RequestId RequestIdBeingSerialized { get; set; } + private RequestId RequestIdBeingSerialized => this.formatterState.SerializingRequest ? this.formatterState.SerializingMessageWithId : default; /// /// Converts given to its type. @@ -104,25 +126,6 @@ public long GetTokenForProgress(object value) } } - /// - /// Call this method when a response is received to clear the objects associated with the request and avoid a memory leak. - /// - /// The id of the request whose associated objects need to be cleared. - public void OnResponseReceived(RequestId requestId) - { - lock (this.progressLock) - { - if (this.requestProgressMap.TryGetValue(requestId, out ImmutableList? progressInfos)) - { - this.requestProgressMap.Remove(requestId); - foreach (ProgressParamInformation progressInfo in progressInfos) - { - this.progressMap.Remove(progressInfo.Token); - } - } - } - } - /// /// Gets the object associated with the given progress id. /// @@ -168,6 +171,21 @@ public object CreateProgress(JsonRpc rpc, object token, Type valueType) return Activator.CreateInstance(progressType, new object[] { rpc, token })!; } + private void CleanUpResources(RequestId requestId) + { + lock (this.progressLock) + { + if (this.requestProgressMap.TryGetValue(requestId, out ImmutableList? progressInfos)) + { + this.requestProgressMap.Remove(requestId); + foreach (ProgressParamInformation progressInfo in progressInfos) + { + this.progressMap.Remove(progressInfo.Token); + } + } + } + } + /// /// Class used to keep relevant information of an object that implements . /// diff --git a/src/StreamJsonRpc/netcoreapp2.1/PublicAPI.Shipped.txt b/src/StreamJsonRpc/netcoreapp2.1/PublicAPI.Shipped.txt index 505477aad..06105b606 100644 --- a/src/StreamJsonRpc/netcoreapp2.1/PublicAPI.Shipped.txt +++ b/src/StreamJsonRpc/netcoreapp2.1/PublicAPI.Shipped.txt @@ -319,20 +319,15 @@ StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.GetPipeWriter(int? to StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.GetToken(System.IO.Pipelines.IDuplexPipe duplexPipe) -> int? StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.GetToken(System.IO.Pipelines.PipeReader reader) -> int? StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.GetToken(System.IO.Pipelines.PipeWriter writer) -> int? -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.MessageFormatterDuplexPipeTracker() -> void StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.MultiplexingStream.get -> Nerdbank.Streams.MultiplexingStream StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.MultiplexingStream.set -> void -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.RequestIdBeingDeserialized.set -> void -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.RequestIdBeingSerialized.set -> void StreamJsonRpc.Reflection.MessageFormatterProgressTracker StreamJsonRpc.Reflection.MessageFormatterProgressTracker.CreateProgress(StreamJsonRpc.JsonRpc rpc, object token, System.Type valueType) -> object StreamJsonRpc.Reflection.MessageFormatterProgressTracker.CreateProgress(StreamJsonRpc.JsonRpc rpc, object token) -> System.IProgress StreamJsonRpc.Reflection.MessageFormatterProgressTracker.GetTokenForProgress(object value) -> long -StreamJsonRpc.Reflection.MessageFormatterProgressTracker.MessageFormatterProgressTracker() -> void StreamJsonRpc.Reflection.MessageFormatterProgressTracker.ProgressParamInformation StreamJsonRpc.Reflection.MessageFormatterProgressTracker.ProgressParamInformation.InvokeReport(object typedValue) -> void StreamJsonRpc.Reflection.MessageFormatterProgressTracker.ProgressParamInformation.ValueType.get -> System.Type -StreamJsonRpc.Reflection.MessageFormatterProgressTracker.RequestIdBeingSerialized.set -> void const StreamJsonRpc.Reflection.MessageFormatterProgressTracker.ProgressRequestSpecialMethod = "$/progress" -> string static StreamJsonRpc.JsonRpc.Attach(StreamJsonRpc.IJsonRpcMessageHandler handler) -> T static StreamJsonRpc.JsonRpc.Attach(StreamJsonRpc.IJsonRpcMessageHandler handler, StreamJsonRpc.JsonRpcProxyOptions options) -> T diff --git a/src/StreamJsonRpc/netcoreapp2.1/PublicAPI.Unshipped.txt b/src/StreamJsonRpc/netcoreapp2.1/PublicAPI.Unshipped.txt index 955b7bab8..0a8871934 100644 --- a/src/StreamJsonRpc/netcoreapp2.1/PublicAPI.Unshipped.txt +++ b/src/StreamJsonRpc/netcoreapp2.1/PublicAPI.Unshipped.txt @@ -30,31 +30,30 @@ StreamJsonRpc.Protocol.JsonRpcRequest.RequestId.set -> void StreamJsonRpc.Protocol.JsonRpcResult.RequestId.get -> StreamJsonRpc.RequestId StreamJsonRpc.Protocol.JsonRpcResult.RequestId.set -> void StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks -StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks.ErrorReceived -> System.EventHandler -StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks.RequestTransmissionAborted -> System.EventHandler -StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks.ResultReceived -> System.EventHandler +StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks.RequestTransmissionAborted -> System.EventHandler +StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks.ResponseReceived -> System.EventHandler +StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks.ResponseSent -> System.EventHandler StreamJsonRpc.Reflection.IJsonRpcFormatterState StreamJsonRpc.Reflection.IJsonRpcFormatterState.DeserializingMessageWithId.get -> StreamJsonRpc.RequestId StreamJsonRpc.Reflection.IJsonRpcFormatterState.SerializingMessageWithId.get -> StreamJsonRpc.RequestId StreamJsonRpc.Reflection.IJsonRpcFormatterState.SerializingRequest.get -> bool StreamJsonRpc.Reflection.IJsonRpcMessageBufferManager StreamJsonRpc.Reflection.IJsonRpcMessageBufferManager.DeserializationComplete(StreamJsonRpc.Protocol.JsonRpcMessage message) -> void -StreamJsonRpc.Reflection.JsonRpcFormatterCallbackEventArgs -StreamJsonRpc.Reflection.JsonRpcFormatterCallbackEventArgs.JsonRpcFormatterCallbackEventArgs(StreamJsonRpc.RequestId requestId) -> void -StreamJsonRpc.Reflection.JsonRpcFormatterCallbackEventArgs.RequestId.get -> StreamJsonRpc.RequestId -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.OnResponseReceived(StreamJsonRpc.RequestId requestId, bool successful) -> void -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.OnResponseSent(StreamJsonRpc.RequestId requestId, bool successful) -> void -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.RequestIdBeingDeserialized.get -> StreamJsonRpc.RequestId -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.RequestIdBeingSerialized.get -> StreamJsonRpc.RequestId +StreamJsonRpc.Reflection.JsonRpcMessageEventArgs +StreamJsonRpc.Reflection.JsonRpcMessageEventArgs.JsonRpcMessageEventArgs(StreamJsonRpc.RequestId requestId) -> void +StreamJsonRpc.Reflection.JsonRpcMessageEventArgs.RequestId.get -> StreamJsonRpc.RequestId +StreamJsonRpc.Reflection.JsonRpcResponseEventArgs +StreamJsonRpc.Reflection.JsonRpcResponseEventArgs.IsSuccessfulResponse.get -> bool +StreamJsonRpc.Reflection.JsonRpcResponseEventArgs.JsonRpcResponseEventArgs(StreamJsonRpc.RequestId requestId, bool isSuccessfulResponse) -> void +StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.MessageFormatterDuplexPipeTracker(StreamJsonRpc.JsonRpc jsonRpc, StreamJsonRpc.Reflection.IJsonRpcFormatterState formatterState) -> void StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker.CreateEnumerableProxy(System.Type enumeratedType, object handle) -> object StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker.CreateEnumerableProxy(object handle) -> System.Collections.Generic.IAsyncEnumerable StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker.GetToken(object enumerable) -> long StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker.GetToken(System.Collections.Generic.IAsyncEnumerable enumerable) -> long StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker.MessageFormatterEnumerableTracker(StreamJsonRpc.JsonRpc jsonRpc, StreamJsonRpc.Reflection.IJsonRpcFormatterState formatterState) -> void -StreamJsonRpc.Reflection.MessageFormatterProgressTracker.OnResponseReceived(StreamJsonRpc.RequestId requestId) -> void +StreamJsonRpc.Reflection.MessageFormatterProgressTracker.MessageFormatterProgressTracker(StreamJsonRpc.JsonRpc jsonRpc, StreamJsonRpc.Reflection.IJsonRpcFormatterState formatterState) -> void StreamJsonRpc.Reflection.MessageFormatterProgressTracker.ProgressParamInformation.Token.get -> long -StreamJsonRpc.Reflection.MessageFormatterProgressTracker.RequestIdBeingSerialized.get -> StreamJsonRpc.RequestId StreamJsonRpc.Reflection.MessageFormatterProgressTracker.TryGetProgressObject(long progressId, out StreamJsonRpc.Reflection.MessageFormatterProgressTracker.ProgressParamInformation valueType) -> bool StreamJsonRpc.RemoteInvocationException.DeserializedErrorData.get -> object StreamJsonRpc.RemoteInvocationException.RemoteInvocationException(string message, int errorCode, object errorData, object deserializedErrorData) -> void @@ -84,9 +83,9 @@ static StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker.CanSerialize(S static StreamJsonRpc.RequestId.NotSpecified.get -> StreamJsonRpc.RequestId virtual StreamJsonRpc.JsonRpc.CreateNewRequestId() -> StreamJsonRpc.RequestId virtual StreamJsonRpc.JsonRpc.GetErrorDetailsDataType(StreamJsonRpc.Protocol.JsonRpcError error) -> System.Type -virtual StreamJsonRpc.JsonRpc.OnErrorReceived(StreamJsonRpc.Protocol.JsonRpcError error) -> void virtual StreamJsonRpc.JsonRpc.OnRequestTransmissionAborted(StreamJsonRpc.Protocol.JsonRpcRequest request) -> void -virtual StreamJsonRpc.JsonRpc.OnResultReceived(StreamJsonRpc.Protocol.JsonRpcResult result) -> void +virtual StreamJsonRpc.JsonRpc.OnResponseReceived(StreamJsonRpc.Protocol.JsonRpcMessage response) -> void +virtual StreamJsonRpc.JsonRpc.OnResponseSent(StreamJsonRpc.Protocol.JsonRpcMessage response) -> void virtual StreamJsonRpc.MessageHandlerBase.DisposeAsync() -> System.Threading.Tasks.Task virtual StreamJsonRpc.MessageHandlerBase.DisposeReader() -> void virtual StreamJsonRpc.MessageHandlerBase.DisposeWriter() -> void diff --git a/src/StreamJsonRpc/netstandard2.0/PublicAPI.Shipped.txt b/src/StreamJsonRpc/netstandard2.0/PublicAPI.Shipped.txt index 505477aad..06105b606 100644 --- a/src/StreamJsonRpc/netstandard2.0/PublicAPI.Shipped.txt +++ b/src/StreamJsonRpc/netstandard2.0/PublicAPI.Shipped.txt @@ -319,20 +319,15 @@ StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.GetPipeWriter(int? to StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.GetToken(System.IO.Pipelines.IDuplexPipe duplexPipe) -> int? StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.GetToken(System.IO.Pipelines.PipeReader reader) -> int? StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.GetToken(System.IO.Pipelines.PipeWriter writer) -> int? -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.MessageFormatterDuplexPipeTracker() -> void StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.MultiplexingStream.get -> Nerdbank.Streams.MultiplexingStream StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.MultiplexingStream.set -> void -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.RequestIdBeingDeserialized.set -> void -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.RequestIdBeingSerialized.set -> void StreamJsonRpc.Reflection.MessageFormatterProgressTracker StreamJsonRpc.Reflection.MessageFormatterProgressTracker.CreateProgress(StreamJsonRpc.JsonRpc rpc, object token, System.Type valueType) -> object StreamJsonRpc.Reflection.MessageFormatterProgressTracker.CreateProgress(StreamJsonRpc.JsonRpc rpc, object token) -> System.IProgress StreamJsonRpc.Reflection.MessageFormatterProgressTracker.GetTokenForProgress(object value) -> long -StreamJsonRpc.Reflection.MessageFormatterProgressTracker.MessageFormatterProgressTracker() -> void StreamJsonRpc.Reflection.MessageFormatterProgressTracker.ProgressParamInformation StreamJsonRpc.Reflection.MessageFormatterProgressTracker.ProgressParamInformation.InvokeReport(object typedValue) -> void StreamJsonRpc.Reflection.MessageFormatterProgressTracker.ProgressParamInformation.ValueType.get -> System.Type -StreamJsonRpc.Reflection.MessageFormatterProgressTracker.RequestIdBeingSerialized.set -> void const StreamJsonRpc.Reflection.MessageFormatterProgressTracker.ProgressRequestSpecialMethod = "$/progress" -> string static StreamJsonRpc.JsonRpc.Attach(StreamJsonRpc.IJsonRpcMessageHandler handler) -> T static StreamJsonRpc.JsonRpc.Attach(StreamJsonRpc.IJsonRpcMessageHandler handler, StreamJsonRpc.JsonRpcProxyOptions options) -> T diff --git a/src/StreamJsonRpc/netstandard2.0/PublicAPI.Unshipped.txt b/src/StreamJsonRpc/netstandard2.0/PublicAPI.Unshipped.txt index 955b7bab8..0a8871934 100644 --- a/src/StreamJsonRpc/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/StreamJsonRpc/netstandard2.0/PublicAPI.Unshipped.txt @@ -30,31 +30,30 @@ StreamJsonRpc.Protocol.JsonRpcRequest.RequestId.set -> void StreamJsonRpc.Protocol.JsonRpcResult.RequestId.get -> StreamJsonRpc.RequestId StreamJsonRpc.Protocol.JsonRpcResult.RequestId.set -> void StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks -StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks.ErrorReceived -> System.EventHandler -StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks.RequestTransmissionAborted -> System.EventHandler -StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks.ResultReceived -> System.EventHandler +StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks.RequestTransmissionAborted -> System.EventHandler +StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks.ResponseReceived -> System.EventHandler +StreamJsonRpc.Reflection.IJsonRpcFormatterCallbacks.ResponseSent -> System.EventHandler StreamJsonRpc.Reflection.IJsonRpcFormatterState StreamJsonRpc.Reflection.IJsonRpcFormatterState.DeserializingMessageWithId.get -> StreamJsonRpc.RequestId StreamJsonRpc.Reflection.IJsonRpcFormatterState.SerializingMessageWithId.get -> StreamJsonRpc.RequestId StreamJsonRpc.Reflection.IJsonRpcFormatterState.SerializingRequest.get -> bool StreamJsonRpc.Reflection.IJsonRpcMessageBufferManager StreamJsonRpc.Reflection.IJsonRpcMessageBufferManager.DeserializationComplete(StreamJsonRpc.Protocol.JsonRpcMessage message) -> void -StreamJsonRpc.Reflection.JsonRpcFormatterCallbackEventArgs -StreamJsonRpc.Reflection.JsonRpcFormatterCallbackEventArgs.JsonRpcFormatterCallbackEventArgs(StreamJsonRpc.RequestId requestId) -> void -StreamJsonRpc.Reflection.JsonRpcFormatterCallbackEventArgs.RequestId.get -> StreamJsonRpc.RequestId -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.OnResponseReceived(StreamJsonRpc.RequestId requestId, bool successful) -> void -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.OnResponseSent(StreamJsonRpc.RequestId requestId, bool successful) -> void -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.RequestIdBeingDeserialized.get -> StreamJsonRpc.RequestId -StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.RequestIdBeingSerialized.get -> StreamJsonRpc.RequestId +StreamJsonRpc.Reflection.JsonRpcMessageEventArgs +StreamJsonRpc.Reflection.JsonRpcMessageEventArgs.JsonRpcMessageEventArgs(StreamJsonRpc.RequestId requestId) -> void +StreamJsonRpc.Reflection.JsonRpcMessageEventArgs.RequestId.get -> StreamJsonRpc.RequestId +StreamJsonRpc.Reflection.JsonRpcResponseEventArgs +StreamJsonRpc.Reflection.JsonRpcResponseEventArgs.IsSuccessfulResponse.get -> bool +StreamJsonRpc.Reflection.JsonRpcResponseEventArgs.JsonRpcResponseEventArgs(StreamJsonRpc.RequestId requestId, bool isSuccessfulResponse) -> void +StreamJsonRpc.Reflection.MessageFormatterDuplexPipeTracker.MessageFormatterDuplexPipeTracker(StreamJsonRpc.JsonRpc jsonRpc, StreamJsonRpc.Reflection.IJsonRpcFormatterState formatterState) -> void StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker.CreateEnumerableProxy(System.Type enumeratedType, object handle) -> object StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker.CreateEnumerableProxy(object handle) -> System.Collections.Generic.IAsyncEnumerable StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker.GetToken(object enumerable) -> long StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker.GetToken(System.Collections.Generic.IAsyncEnumerable enumerable) -> long StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker.MessageFormatterEnumerableTracker(StreamJsonRpc.JsonRpc jsonRpc, StreamJsonRpc.Reflection.IJsonRpcFormatterState formatterState) -> void -StreamJsonRpc.Reflection.MessageFormatterProgressTracker.OnResponseReceived(StreamJsonRpc.RequestId requestId) -> void +StreamJsonRpc.Reflection.MessageFormatterProgressTracker.MessageFormatterProgressTracker(StreamJsonRpc.JsonRpc jsonRpc, StreamJsonRpc.Reflection.IJsonRpcFormatterState formatterState) -> void StreamJsonRpc.Reflection.MessageFormatterProgressTracker.ProgressParamInformation.Token.get -> long -StreamJsonRpc.Reflection.MessageFormatterProgressTracker.RequestIdBeingSerialized.get -> StreamJsonRpc.RequestId StreamJsonRpc.Reflection.MessageFormatterProgressTracker.TryGetProgressObject(long progressId, out StreamJsonRpc.Reflection.MessageFormatterProgressTracker.ProgressParamInformation valueType) -> bool StreamJsonRpc.RemoteInvocationException.DeserializedErrorData.get -> object StreamJsonRpc.RemoteInvocationException.RemoteInvocationException(string message, int errorCode, object errorData, object deserializedErrorData) -> void @@ -84,9 +83,9 @@ static StreamJsonRpc.Reflection.MessageFormatterEnumerableTracker.CanSerialize(S static StreamJsonRpc.RequestId.NotSpecified.get -> StreamJsonRpc.RequestId virtual StreamJsonRpc.JsonRpc.CreateNewRequestId() -> StreamJsonRpc.RequestId virtual StreamJsonRpc.JsonRpc.GetErrorDetailsDataType(StreamJsonRpc.Protocol.JsonRpcError error) -> System.Type -virtual StreamJsonRpc.JsonRpc.OnErrorReceived(StreamJsonRpc.Protocol.JsonRpcError error) -> void virtual StreamJsonRpc.JsonRpc.OnRequestTransmissionAborted(StreamJsonRpc.Protocol.JsonRpcRequest request) -> void -virtual StreamJsonRpc.JsonRpc.OnResultReceived(StreamJsonRpc.Protocol.JsonRpcResult result) -> void +virtual StreamJsonRpc.JsonRpc.OnResponseReceived(StreamJsonRpc.Protocol.JsonRpcMessage response) -> void +virtual StreamJsonRpc.JsonRpc.OnResponseSent(StreamJsonRpc.Protocol.JsonRpcMessage response) -> void virtual StreamJsonRpc.MessageHandlerBase.DisposeAsync() -> System.Threading.Tasks.Task virtual StreamJsonRpc.MessageHandlerBase.DisposeReader() -> void virtual StreamJsonRpc.MessageHandlerBase.DisposeWriter() -> void