diff --git a/src/StreamJsonRpc/JsonRpc.cs b/src/StreamJsonRpc/JsonRpc.cs index 46c3f3df..36563bf8 100644 --- a/src/StreamJsonRpc/JsonRpc.cs +++ b/src/StreamJsonRpc/JsonRpc.cs @@ -1529,7 +1529,7 @@ protected async Task InvokeCoreAsync(RequestId id, string targ object? argument = arguments; if (arguments is not null) { - if (arguments.Count != 1 || arguments[0] is null || !arguments[0]!.GetType().GetTypeInfo().IsClass) + if (arguments.Count != 1 || arguments[0] is null) { throw new ArgumentException(Resources.ParameterNotObject); } diff --git a/test/StreamJsonRpc.Tests/JsonRpcJsonHeadersTests.cs b/test/StreamJsonRpc.Tests/JsonRpcJsonHeadersTests.cs index 5aeec1f4..9deaf760 100644 --- a/test/StreamJsonRpc.Tests/JsonRpcJsonHeadersTests.cs +++ b/test/StreamJsonRpc.Tests/JsonRpcJsonHeadersTests.cs @@ -4,6 +4,7 @@ using System.Text; using Microsoft.VisualStudio.Threading; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; public class JsonRpcJsonHeadersTests : JsonRpcTests { @@ -163,6 +164,9 @@ protected override void InitializeFormattersAndHandlers( : new HeaderDelimitedMessageHandler(clientStream, clientStream, clientMessageFormatter); } + protected override object[] CreateFormatterIntrinsicParamsObject(string arg) => + [new JObject { ["arg"] = arg }]; + protected class UnserializableTypeConverter : JsonConverter { public override bool CanConvert(Type objectType) => objectType == typeof(CustomSerializedType); diff --git a/test/StreamJsonRpc.Tests/JsonRpcMessagePackLengthTests.cs b/test/StreamJsonRpc.Tests/JsonRpcMessagePackLengthTests.cs index f0881be7..db4300df 100644 --- a/test/StreamJsonRpc.Tests/JsonRpcMessagePackLengthTests.cs +++ b/test/StreamJsonRpc.Tests/JsonRpcMessagePackLengthTests.cs @@ -409,6 +409,8 @@ protected override void InitializeFormattersAndHandlers( : new LengthHeaderMessageHandler(clientStream, clientStream, clientMessageFormatter); } + protected override object[] CreateFormatterIntrinsicParamsObject(string arg) => []; + [MessagePackObject] [Union(0, typeof(UnionDerivedClass))] public abstract class UnionBaseClass diff --git a/test/StreamJsonRpc.Tests/JsonRpcSystemTextJsonHeadersTests.cs b/test/StreamJsonRpc.Tests/JsonRpcSystemTextJsonHeadersTests.cs index cf8d5476..28a9d3b9 100644 --- a/test/StreamJsonRpc.Tests/JsonRpcSystemTextJsonHeadersTests.cs +++ b/test/StreamJsonRpc.Tests/JsonRpcSystemTextJsonHeadersTests.cs @@ -2,8 +2,10 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Text.Json; +using System.Text.Json.Nodes; using System.Text.Json.Serialization; using Microsoft.VisualStudio.Threading; +using Newtonsoft.Json.Linq; public class JsonRpcSystemTextJsonHeadersTests : JsonRpcTests { @@ -61,6 +63,12 @@ protected override void InitializeFormattersAndHandlers( : new HeaderDelimitedMessageHandler(clientStream, clientStream, clientMessageFormatter); } + protected override object[] CreateFormatterIntrinsicParamsObject(string arg) => + [ + new JsonObject { ["arg"] = JsonValue.Create(arg) }, + JsonDocument.Parse($$"""{ "arg": "{{arg}}" }""").RootElement, // JsonElement + ]; + protected class DelayedFlushingHandler : HeaderDelimitedMessageHandler, IControlledFlushHandler { public DelayedFlushingHandler(Stream stream, IJsonRpcMessageFormatter formatter) diff --git a/test/StreamJsonRpc.Tests/JsonRpcTests.cs b/test/StreamJsonRpc.Tests/JsonRpcTests.cs index 72500451..fa8023d3 100644 --- a/test/StreamJsonRpc.Tests/JsonRpcTests.cs +++ b/test/StreamJsonRpc.Tests/JsonRpcTests.cs @@ -9,6 +9,7 @@ using System.Text; using Microsoft.VisualStudio.Threading; using Nerdbank.Streams; +using Newtonsoft.Json.Linq; using JsonNET = Newtonsoft.Json; using STJ = System.Text.Json.Serialization; @@ -3088,6 +3089,22 @@ public virtual async Task CanPassExceptionFromServer_ErrorData() Assert.StrictEqual(COR_E_UNAUTHORIZEDACCESS, errorData?.HResult); } + [SkippableFact] + public async Task InvokeWithParameterObjectAsync_FormatterIntrinsic() + { + string arg = "some value"; + object[] variousArgs = this.CreateFormatterIntrinsicParamsObject(arg); + Skip.If(variousArgs.Length == 0, "This test is only meaningful when the formatter supports intrinsic types."); + + foreach (object args in variousArgs) + { + var invokeTask = this.clientRpc.InvokeWithParameterObjectAsync(nameof(Server.AsyncMethod), args, this.TimeoutToken); + this.server.AllowServerMethodToReturn.Set(); + string result = await invokeTask; + Assert.Equal($"{arg}!", result); + } + } + protected static Exception CreateExceptionToBeThrownByDeserializer() => new Exception("This exception is meant to be thrown."); protected override void Dispose(bool disposing) @@ -3128,6 +3145,12 @@ protected abstract void InitializeFormattersAndHandlers( out IJsonRpcMessageHandler clientMessageHandler, bool controlledFlushingClient); + /// + /// Creates objects that each may be passed to as the whole parameter object. + /// The object should be an intrinsic type for the formatter that requires no special serialization. + /// + protected abstract object[] CreateFormatterIntrinsicParamsObject(string arg); + protected override Task CheckGCPressureAsync(Func scenario, int maxBytesAllocated = -1, int iterations = 100, int allowedAttempts = 10) { // Make sure we aren't logging anything but errors.