diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..bdb0cab --- /dev/null +++ b/.gitattributes @@ -0,0 +1,17 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.github/workflows/build_publish_master.yml b/.github/workflows/build_publish_master.yml new file mode 100644 index 0000000..1a7fe10 --- /dev/null +++ b/.github/workflows/build_publish_master.yml @@ -0,0 +1,33 @@ +name: Build Master +on: + push: + paths-ignore: + - "**/*.md" + branches: [ master ] + +jobs: + build: + + strategy: + matrix: + os: ['ubuntu-latest'] + dotnet-version: ['3.1.201'] + project : ['Json-Rpc'] + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v2 + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: ${{matrix.dotnet-version}} + - name: Install dependencies + run: dotnet restore + - name: Build + run: dotnet build ${{matrix.project}} --configuration Release + - name: Test + run: dotnet test AustinHarris.JsonRpcTestN + # Publish + - name: publish nuget version change + run: dotnet nuget push Json-Rpc/bin/Release/*.nupkg --skip-duplicate --source "https://www.nuget.org" --api-key ${{secrets.NugetKey}} # API key for the NuGet feed diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml new file mode 100644 index 0000000..f3e06e9 --- /dev/null +++ b/.github/workflows/build_pull_request.yml @@ -0,0 +1,35 @@ +name: Pull Reqest +on: + pull_request: + paths-ignore: + - "**/*.md" + branches: [ master ] + +jobs: + build: + + strategy: + matrix: + os: ['windows-latest','ubuntu-latest'] + dotnet-version: ['3.1.201'] + project : ['Json-Rpc'] + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v2 + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: ${{matrix.dotnet-version}} + - name: Install dependencies + run: dotnet restore + - name: Build + run: dotnet build ${{matrix.project}} --configuration Release --version-suffix ci-${{ github.run_id }}-${{ github.run_number }} + - name: Test + run: dotnet test AustinHarris.JsonRpcTestN + # Publish + - name: publish nuget version change + if: ${{matrix.os == 'ubuntu-latest'}} + run: dotnet nuget push Json-Rpc/bin/Release/*.nupkg --skip-duplicate --source "https://www.nuget.org" --api-key ${{secrets.NugetKey}} # API key for the NuGet feed + \ No newline at end of file diff --git a/.gitignore b/.gitignore index bdc3535..6ea46be 100644 --- a/.gitignore +++ b/.gitignore @@ -106,3 +106,5 @@ Generated_Code #added for RIA/Silverlight projects _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML +.nuget/NuGet.exe +.vs/ diff --git a/.nuget/NuGet.Config b/.nuget/NuGet.Config new file mode 100644 index 0000000..67f8ea0 --- /dev/null +++ b/.nuget/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.nuget/NuGet.targets b/.nuget/NuGet.targets new file mode 100644 index 0000000..a6dbdfb --- /dev/null +++ b/.nuget/NuGet.targets @@ -0,0 +1,90 @@ + + + + $(MSBuildProjectDirectory)\..\ + + + false + + + false + + + true + + + true + + + + + + + + + + + $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) + + + + + $(SolutionDir).nuget + + + + $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config + $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config + + + + $(MSBuildProjectDirectory)\packages.config + $(PackagesProjectConfig) + + + + + $(NuGetToolsPath)\NuGet.exe + @(PackageSource) + + "$(NuGetExePath)" + mono --runtime=v4.0.30319 "$(NuGetExePath)" + + $(TargetDir.Trim('\\')) + + -RequireConsent + -NonInteractive + + "$(SolutionDir) " + "$(SolutionDir)" + + + $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) + $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols + + + + + + + $(BuildDependsOn); + BuildPackage; + + + + + + + + + + + + + diff --git a/AustinHarris.JsonRpc.AspNet/AustinHarris.JsonRpc.AspNet.csproj b/AustinHarris.JsonRpc.AspNet/AustinHarris.JsonRpc.AspNet.csproj index e31b302..3470e2c 100644 --- a/AustinHarris.JsonRpc.AspNet/AustinHarris.JsonRpc.AspNet.csproj +++ b/AustinHarris.JsonRpc.AspNet/AustinHarris.JsonRpc.AspNet.csproj @@ -15,6 +15,8 @@ SAK SAK SAK + ..\ + true true @@ -34,9 +36,9 @@ 4 - - False - ..\packages\Newtonsoft.Json.6.0.3\lib\net40\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.12.0.3\lib\net40\Newtonsoft.Json.dll + True @@ -45,6 +47,7 @@ + @@ -57,6 +60,13 @@ + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + - \ No newline at end of file diff --git a/AustinHarris.JsonRpcTest/Properties/AssemblyInfo.cs b/AustinHarris.JsonRpcTest/Properties/AssemblyInfo.cs deleted file mode 100644 index 8fe95b7..0000000 --- a/AustinHarris.JsonRpcTest/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("AustinHarris.JsonRpcTest")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("AustinHarris.JsonRpcTest")] -[assembly: AssemblyCopyright("Copyright © 2014")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("45d95cf9-ddf4-4eda-add0-80f5222a2a38")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/AustinHarris.JsonRpcTestN/AustinHarris.JsonRpcTestN.csproj b/AustinHarris.JsonRpcTestN/AustinHarris.JsonRpcTestN.csproj new file mode 100644 index 0000000..c5db038 --- /dev/null +++ b/AustinHarris.JsonRpcTestN/AustinHarris.JsonRpcTestN.csproj @@ -0,0 +1,21 @@ + + + + Austin Harris + netcoreapp3.0;netcoreapp3.1 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AustinHarris.JsonRpcTest/UnitTest1.cs b/AustinHarris.JsonRpcTestN/Test.cs similarity index 59% rename from AustinHarris.JsonRpcTest/UnitTest1.cs rename to AustinHarris.JsonRpcTestN/Test.cs index feecd71..ed46543 100644 --- a/AustinHarris.JsonRpcTest/UnitTest1.cs +++ b/AustinHarris.JsonRpcTestN/Test.cs @@ -1,191 +1,237 @@ -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using AustinHarris.JsonRpc.Client; +using NUnit.Framework; +using System; +using System.Linq; using AustinHarris.JsonRpc; +using System.Text.RegularExpressions; +using Newtonsoft.Json.Linq; -namespace UnitTests +namespace AustinHarris.JsonRpcTestN { - [TestClass] - public class UnitTest1 + public class Poco { - static object[] services ; + public static Poco WithOffset(int offset) + { + return new Poco(offset); + } + + readonly int _offset; + public Poco(int offset) + { + _offset = offset; + } + + [JsonRpcMethod("add")] + public int Add(int input) { return input + _offset; } + } + + [TestFixture()] + public class Test + { + [Test()] + public void TestCase() + { + } + static object[] services; - static UnitTest1() + static Test() { services = new object[] { - new CalculatorService()}; - + new CalculatorService()}; } - [TestMethod] + [Test()] + public void TestCanCreateMultipleServicesOfSameTypeInTheirOwnSessions() + { + Func request = (int param) => String.Format("{{method:'add',params:[{0}],id:1}}", param); + Func expectedResult = (int param) => String.Format("{{\"jsonrpc\":\"2.0\",\"result\":{0},\"id\":1}}", param); + + for (int i = 0; i < 100; i++) + { + ServiceBinder.BindService(i.ToString(), Poco.WithOffset(i)); + } + + for (int i = 0; i < 100; i++) + { + var result = JsonRpcProcessor.Process(i.ToString(), request(10)); + result.Wait(); + var actual1 = JObject.Parse(result.Result); + var expected1 = JObject.Parse(expectedResult(10 + i)); + Assert.AreEqual(expected1, actual1); + } + } + + [Test()] + public void TestCanCreateAndRemoveSession() + { + var h = JsonRpc.Handler.GetSessionHandler("this one"); + var metadata = new System.Collections.Generic.List> { + Tuple.Create ("sooper", typeof(string)), + Tuple.Create ("returns", typeof(string)) + }.ToDictionary(x => x.Item1, x => x.Item2); + h.RegisterFuction("workie", metadata, new System.Collections.Generic.Dictionary(),new Func(x => "workie ... " + x)); + + string request = @"{method:'workie',params:{'sooper':'good'},id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"workie ... good\",\"id\":1}"; + string expectedResultAfterDestroy = "{\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Method not found\",\"code\":-32601,\"data\":\"The method does not exist / is not available.\"},\"id\":1}"; + var result = JsonRpcProcessor.Process("this one", request); + result.Wait(); + + + var actual1 = JObject.Parse(result.Result); + var expected1 = JObject.Parse(expectedResult); + Assert.IsTrue(JToken.DeepEquals(expected1, actual1)); + + h.Destroy(); + + var result2 = JsonRpcProcessor.Process("this one", request); + result2.Wait(); + + Assert.IsTrue(JToken.DeepEquals(JObject.Parse(expectedResultAfterDestroy), JObject.Parse(result2.Result))); + } + + [Test()] public void TestInProcessClient() { string request = @"{method:'NullableFloatToNullableFloat',params:[0.0],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":0.0,\"id\":1}"; - var result = JsonRpcProcessor.Process(request); + var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.AreEqual(result.Result, expectedResult); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void NullableDateTimeToNullableDateTime() { string request = @"{method:'NullableDateTimeToNullableDateTime',params:['2014-06-30T14:50:38.5208399+09:00'],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"2014-06-30T14:50:38.5208399+09:00\",\"id\":1}"; + var expectedDate = DateTime.Parse("2014-06-30T14:50:38.5208399+09:00"); var result = JsonRpcProcessor.Process(request); result.Wait(); - Assert.AreEqual(result.Result, expectedResult); - Assert.AreEqual(expectedResult, result.Result); + var acutalDate = DateTime.Parse(result.Result.Substring(27, 33)); + Assert.AreEqual(expectedDate, acutalDate); } - [TestMethod] - public void NullableFloatToNullableFloat() + [TestCase(@"{method:'NullableFloatToNullableFloat',params:[1.2345],id:1}", ExpectedResult = "{\"jsonrpc\":\"2.0\",\"result\":1.2345,\"id\":1}")] + [TestCase(@"{method:'NullableFloatToNullableFloat',params:[3.14159],id:1}", ExpectedResult = "{\"jsonrpc\":\"2.0\",\"result\":3.14159,\"id\":1}")] + [TestCase(@"{method:'NullableFloatToNullableFloat',params:[null],id:1}", ExpectedResult = "{\"jsonrpc\":\"2.0\",\"result\":null,\"id\":1}")] + public string NullableFloatToNullableFloat(string request) { - string request = @"{method:'NullableFloatToNullableFloat',params:[1.2345],id:1}"; - string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":1.2345,\"id\":1}"; - var result = JsonRpcProcessor.Process(request); - result.Wait(); - Assert.AreEqual(result.Result, expectedResult); - Assert.AreEqual(expectedResult, result.Result); - } - - [TestMethod] - public void NullableFloatToNullableFloat3() - { - string request = @"{method:'NullableFloatToNullableFloat',params:[3.14159],id:1}"; - string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":3.14159,\"id\":1}"; var result = JsonRpcProcessor.Process(request); result.Wait(); - Assert.AreEqual(result.Result, expectedResult); - Assert.AreEqual(expectedResult, result.Result); + return result.Result; } - - - [TestMethod] - public void NullableFloatToNullableFloat2() - { - string request = @"{method:'NullableFloatToNullableFloat',params:[null],id:1}"; - string expectedResult = "{\"jsonrpc\":\"2.0\",\"id\":1}"; - var result = JsonRpcProcessor.Process(request); - result.Wait(); - Assert.AreEqual(result.Result, expectedResult); - Assert.AreEqual(expectedResult, result.Result); - } - - [TestMethod] + + + [Test()] public void DecimalToNullableDecimal() { string request = @"{method:'DecimalToNullableDecimal',params:[0.0],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":0.0,\"id\":1}"; - var result = JsonRpcProcessor.Process(request); + var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.AreEqual(result.Result, expectedResult); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void StringToListOfString() { string request = @"{method:'StringToListOfString',params:['some string'],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":[\"one\",\"two\",\"three\",\"some string\"],\"id\":1}"; - var result = JsonRpcProcessor.Process(request); + var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.AreEqual(result.Result, expectedResult); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void CustomStringToListOfString() { string request = @"{method:'CustomStringToListOfString',params:[{str:'some string'}],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":[\"one\",\"two\",\"three\",\"some string\"],\"id\":1}"; - var result = JsonRpcProcessor.Process(request); + var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.AreEqual(result.Result, expectedResult); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void StringToThrowingException() { string request = @"{method:'StringToThrowingException',params:['some string'],id:1}"; - string expectedResult = "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32603,\"message\":\"Internal Error\",\"data\":"; - var result = JsonRpcProcessor.Process(request); + var result = JsonRpcProcessor.Process(request); result.Wait(); - Assert.IsTrue(result.Result.StartsWith(expectedResult)); + StringAssert.Contains("-32603", result.Result); } - [TestMethod] + [Test()] public void StringToRefException() { string request = @"{method:'StringToRefException',params:['some string'],id:1}"; - string expectedResult = "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-1,\"message\":\"refException worked\",\"data\":null},\"id\":1}"; - var result = JsonRpcProcessor.Process(request); + string expectedResult = "{\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"refException worked\",\"code\":-1,\"data\":null},\"id\":1}"; + var result = JsonRpcProcessor.Process(request); result.Wait(); - Assert.IsTrue(result.Result.StartsWith(expectedResult)); - Assert.AreEqual(expectedResult, result.Result); + Assert.IsTrue(JToken.DeepEquals(JObject.Parse(expectedResult), JObject.Parse(result.Result))); } - [TestMethod] + [Test()] public void StringToThrowJsonRpcException() { string request = @"{method:'StringToThrowJsonRpcException',params:['some string'],id:1}"; - string expectedResult = "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-27000,\"message\":\"Just some testing\""; - var result = JsonRpcProcessor.Process(request); + var result = JsonRpcProcessor.Process(request); result.Wait(); - Assert.IsTrue(result.Result.StartsWith(expectedResult)); - + StringAssert.Contains("-2700", result.Result); } - [TestMethod] + [Test()] public void ReturnsDateTime() { string request = @"{method:'ReturnsDateTime',params:[],id:1}"; - var result = JsonRpcProcessor.Process(request); + var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.IsFalse(result.Result.Contains("error")); } - [TestMethod] + [Test()] public void ReturnsCustomRecursiveClass() { string request = @"{method:'ReturnsCustomRecursiveClass',params:[],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":{\"Nested1\":{\"Nested1\":null,\"Value1\":5},\"Value1\":10},\"id\":1}"; - var result = JsonRpcProcessor.Process(request); + var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void FloatToFloat() { string request = @"{method:'FloatToFloat',params:[0.123],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":0.123,\"id\":1}"; - var result = JsonRpcProcessor.Process(request); + var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void IntToInt() { string request = @"{method:'IntToInt',params:[789],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":789,\"id\":1}"; - var result = JsonRpcProcessor.Process(request); + var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void OptionalParamInt16() - { + { string request = @"{method:'TestOptionalParamInt16',params:[789],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":789,\"id\":1}"; var result = JsonRpcProcessor.Process(request); @@ -194,7 +240,7 @@ public void OptionalParamInt16() Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void OptionalParamInt16NoParam() { string request = @"{method:'TestOptionalParamInt16',params:[],id:1}"; @@ -205,41 +251,41 @@ public void OptionalParamInt16NoParam() Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void Int16ToInt16() { string request = @"{method:'Int16ToInt16',params:[789],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":789,\"id\":1}"; - var result = JsonRpcProcessor.Process(request); + var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void Int32ToInt32() { string request = @"{method:'Int32ToInt32',params:[789],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":789,\"id\":1}"; - var result = JsonRpcProcessor.Process(request); + var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void Int64ToInt64() { string request = @"{method:'Int64ToInt64',params:[78915984515564],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":78915984515564,\"id\":1}"; - var result = JsonRpcProcessor.Process(request); + var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamByteMissing() { string request = @"{method:'TestOptionalParambyte',params:[],id:1}"; @@ -249,7 +295,7 @@ public void TestOptionalParamByteMissing() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamSbyteMissing() { string request = @"{method:'TestOptionalParamsbyte',params:[],id:1}"; @@ -259,7 +305,7 @@ public void TestOptionalParamSbyteMissing() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamShortMissing() { string request = @"{method:'TestOptionalParamshort',params:[],id:1}"; @@ -269,7 +315,7 @@ public void TestOptionalParamShortMissing() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamintMissing() { string request = @"{method:'TestOptionalParamint',params:[],id:1}"; @@ -279,7 +325,7 @@ public void TestOptionalParamintMissing() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamLongMissing() { string request = @"{method:'TestOptionalParamlong',params:[],id:1}"; @@ -289,7 +335,7 @@ public void TestOptionalParamLongMissing() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUshortMissing() { string request = @"{method:'TestOptionalParamushort',params:[],id:1}"; @@ -299,7 +345,7 @@ public void TestOptionalParamUshortMissing() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUintMissing() { string request = @"{method:'TestOptionalParamuint',params:[],id:1}"; @@ -309,7 +355,7 @@ public void TestOptionalParamUintMissing() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUlongMissing() { string request = @"{method:'TestOptionalParamulong',params:[],id:1}"; @@ -319,7 +365,7 @@ public void TestOptionalParamUlongMissing() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamFloatMissing() { string request = @"{method:'TestOptionalParamfloat',params:[],id:1}"; @@ -329,7 +375,7 @@ public void TestOptionalParamFloatMissing() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDoubleMissing() { string request = @"{method:'TestOptionalParamdouble',params:[],id:1}"; @@ -339,7 +385,7 @@ public void TestOptionalParamDoubleMissing() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamBoolMissing() { string request = @"{method:'TestOptionalParambool',params:[],id:1}"; @@ -349,7 +395,7 @@ public void TestOptionalParamBoolMissing() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamCharMissing() { string request = @"{method:'TestOptionalParamchar',params:[],id:1}"; @@ -359,7 +405,7 @@ public void TestOptionalParamCharMissing() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDecimalMissing() { string request = @"{method:'TestOptionalParamdecimal',params:[],id:1}"; @@ -370,7 +416,7 @@ public void TestOptionalParamDecimalMissing() Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamBytePresent() { string request = @"{method:'TestOptionalParambyte',params:[71],id:1}"; @@ -380,7 +426,7 @@ public void TestOptionalParamBytePresent() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamSbytePresent() { string request = @"{method:'TestOptionalParamsbyte',params:[71],id:1}"; @@ -390,7 +436,7 @@ public void TestOptionalParamSbytePresent() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamShortPresent() { string request = @"{method:'TestOptionalParamshort',params:[71],id:1}"; @@ -400,7 +446,7 @@ public void TestOptionalParamShortPresent() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamintPresent() { string request = @"{method:'TestOptionalParamint',params:[71],id:1}"; @@ -410,7 +456,7 @@ public void TestOptionalParamintPresent() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamLongPresent() { string request = @"{method:'TestOptionalParamlong',params:[71],id:1}"; @@ -420,7 +466,7 @@ public void TestOptionalParamLongPresent() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUshortPresent() { string request = @"{method:'TestOptionalParamushort',params:[71],id:1}"; @@ -430,7 +476,7 @@ public void TestOptionalParamUshortPresent() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUintPresent() { string request = @"{method:'TestOptionalParamuint',params:[71],id:1}"; @@ -440,7 +486,7 @@ public void TestOptionalParamUintPresent() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUlongPresent() { string request = @"{method:'TestOptionalParamulong',params:[71],id:1}"; @@ -450,7 +496,7 @@ public void TestOptionalParamUlongPresent() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamFloatPresent() { string request = @"{method:'TestOptionalParamfloat',params:[71],id:1}"; @@ -460,7 +506,7 @@ public void TestOptionalParamFloatPresent() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDoublePresent() { string request = @"{method:'TestOptionalParamdouble',params:[71],id:1}"; @@ -470,7 +516,7 @@ public void TestOptionalParamDoublePresent() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamBoolPresent() { string request = @"{method:'TestOptionalParambool',params:[false],id:1}"; @@ -480,17 +526,17 @@ public void TestOptionalParamBoolPresent() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamCharPresent() { - string request = @"{method:'TestOptionalParamchar',params:["+(int)'b'+"],id:1}"; + string request = @"{method:'TestOptionalParamchar',params:[" + (int)'b' + "],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"b\",\"id\":1}"; var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDecimalPresent() { string request = @"{method:'TestOptionalParamdecimal',params:[71],id:1}"; @@ -501,7 +547,7 @@ public void TestOptionalParamDecimalPresent() Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamBytePresentObjectSyntax() { string request = @"{method:'TestOptionalParambyte',params:{'input':71},id:1}"; @@ -511,7 +557,7 @@ public void TestOptionalParamBytePresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamSbytePresentObjectSyntax() { string request = @"{method:'TestOptionalParamsbyte',params:{'input':71},id:1}"; @@ -521,7 +567,7 @@ public void TestOptionalParamSbytePresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamShortPresentObjectSyntax() { string request = @"{method:'TestOptionalParamshort',params:{'input':71},id:1}"; @@ -531,7 +577,7 @@ public void TestOptionalParamShortPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamintPresentObjectSyntax() { string request = @"{method:'TestOptionalParamint',params:{'input':71},id:1}"; @@ -541,7 +587,7 @@ public void TestOptionalParamintPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamLongPresentObjectSyntax() { string request = @"{method:'TestOptionalParamlong',params:{'input':71},id:1}"; @@ -551,7 +597,7 @@ public void TestOptionalParamLongPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUshortPresentObjectSyntax() { string request = @"{method:'TestOptionalParamushort',params:{'input':71},id:1}"; @@ -561,7 +607,7 @@ public void TestOptionalParamUshortPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUintPresentObjectSyntax() { string request = @"{method:'TestOptionalParamuint',params:{'input':71},id:1}"; @@ -571,7 +617,7 @@ public void TestOptionalParamUintPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUlongPresentObjectSyntax() { string request = @"{method:'TestOptionalParamulong',params:{'input':71},id:1}"; @@ -581,7 +627,7 @@ public void TestOptionalParamUlongPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamFloatPresentObjectSyntax() { string request = @"{method:'TestOptionalParamfloat',params:{'input':71},id:1}"; @@ -591,7 +637,7 @@ public void TestOptionalParamFloatPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDoublePresentObjectSyntax() { string request = @"{method:'TestOptionalParamdouble',params:{'input':71},id:1}"; @@ -601,7 +647,7 @@ public void TestOptionalParamDoublePresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamBoolPresentObjectSyntax() { string request = @"{method:'TestOptionalParambool',params:{'input':false},id:1}"; @@ -611,17 +657,17 @@ public void TestOptionalParamBoolPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamCharPresentObjectSyntax() { - string request = @"{method:'TestOptionalParamchar',params:{'input':"+(int)'c'+"},id:1}"; + string request = @"{method:'TestOptionalParamchar',params:{'input':" + (int)'c' + "},id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"c\",\"id\":1}"; var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDecimalPresentObjectSyntax() { string request = @"{method:'TestOptionalParamdecimal',params:{'input':71},id:1}"; @@ -632,7 +678,7 @@ public void TestOptionalParamDecimalPresentObjectSyntax() Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamByteMissingObjectSyntax() { string request = @"{method:'TestOptionalParambyte',params:{},id:1}"; @@ -642,7 +688,7 @@ public void TestOptionalParamByteMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamSbyteMissingObjectSyntax() { string request = @"{method:'TestOptionalParamsbyte',params:{},id:1}"; @@ -652,7 +698,7 @@ public void TestOptionalParamSbyteMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamShortMissingObjectSyntax() { string request = @"{method:'TestOptionalParamshort',params:{},id:1}"; @@ -662,7 +708,7 @@ public void TestOptionalParamShortMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamintMissingObjectSyntax() { string request = @"{method:'TestOptionalParamint',params:{},id:1}"; @@ -672,7 +718,7 @@ public void TestOptionalParamintMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamLongMissingObjectSyntax() { string request = @"{method:'TestOptionalParamlong',params:{},id:1}"; @@ -682,7 +728,7 @@ public void TestOptionalParamLongMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUshortMissingObjectSyntax() { string request = @"{method:'TestOptionalParamushort',params:{},id:1}"; @@ -692,7 +738,7 @@ public void TestOptionalParamUshortMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUintMissingObjectSyntax() { string request = @"{method:'TestOptionalParamuint',params:{},id:1}"; @@ -702,7 +748,7 @@ public void TestOptionalParamUintMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUlongMissingObjectSyntax() { string request = @"{method:'TestOptionalParamulong',params:{},id:1}"; @@ -712,7 +758,7 @@ public void TestOptionalParamUlongMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamFloatMissingObjectSyntax() { string request = @"{method:'TestOptionalParamfloat',params:{},id:1}"; @@ -722,7 +768,7 @@ public void TestOptionalParamFloatMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDoubleMissingObjectSyntax() { string request = @"{method:'TestOptionalParamdouble',params:{},id:1}"; @@ -732,7 +778,7 @@ public void TestOptionalParamDoubleMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamBoolMissingObjectSyntax() { string request = @"{method:'TestOptionalParambool',params:{},id:1}"; @@ -742,7 +788,7 @@ public void TestOptionalParamBoolMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamCharMissingObjectSyntax() { string request = @"{method:'TestOptionalParamchar',params:{},id:1}"; @@ -752,7 +798,7 @@ public void TestOptionalParamCharMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDecimalMissingObjectSyntax() { string request = @"{method:'TestOptionalParamdecimal',params:{},id:1}"; @@ -763,7 +809,7 @@ public void TestOptionalParamDecimalMissingObjectSyntax() Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamByte_2ndMissingObjectSyntax() { string request = @"{method:'TestOptionalParambyte_2x',params:{input1:123},id:1}"; @@ -773,7 +819,7 @@ public void TestOptionalParamByte_2ndMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamSbyte_2ndMissingObjectSyntax() { string request = @"{method:'TestOptionalParamsbyte_2x',params:{input1:123},id:1}"; @@ -783,7 +829,7 @@ public void TestOptionalParamSbyte_2ndMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamShort_2ndMissingObjectSyntax() { string request = @"{method:'TestOptionalParamshort_2x',params:{input1:123},id:1}"; @@ -793,7 +839,7 @@ public void TestOptionalParamShort_2ndMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamint_2ndMissingObjectSyntax() { string request = @"{method:'TestOptionalParamint_2x',params:{input1:123},id:1}"; @@ -803,7 +849,7 @@ public void TestOptionalParamint_2ndMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamLong_2ndMissingObjectSyntax() { string request = @"{method:'TestOptionalParamlong_2x',params:{input1:123},id:1}"; @@ -813,7 +859,7 @@ public void TestOptionalParamLong_2ndMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUshort_2ndMissingObjectSyntax() { string request = @"{method:'TestOptionalParamushort_2x',params:{input1:123},id:1}"; @@ -823,7 +869,7 @@ public void TestOptionalParamUshort_2ndMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUint_2ndMissingObjectSyntax() { string request = @"{method:'TestOptionalParamuint_2x',params:{input1:123},id:1}"; @@ -833,7 +879,7 @@ public void TestOptionalParamUint_2ndMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUlong_2ndMissingObjectSyntax() { string request = @"{method:'TestOptionalParamulong_2x',params:{input1:123},id:1}"; @@ -843,7 +889,7 @@ public void TestOptionalParamUlong_2ndMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamFloat_2ndMissingObjectSyntax() { string request = @"{method:'TestOptionalParamfloat_2x',params:{input1:123},id:1}"; @@ -853,7 +899,7 @@ public void TestOptionalParamFloat_2ndMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDouble_2ndMissingObjectSyntax() { string request = @"{method:'TestOptionalParamdouble_2x',params:{input1:123},id:1}"; @@ -863,7 +909,7 @@ public void TestOptionalParamDouble_2ndMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamBool_2ndMissingObjectSyntax() { string request = @"{method:'TestOptionalParambool_2x',params:{input1:123},id:1}"; @@ -873,7 +919,7 @@ public void TestOptionalParamBool_2ndMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamChar_2ndMissingObjectSyntax() { string request = @"{method:'TestOptionalParamchar_2x',params:{input1:123},id:1}"; @@ -883,7 +929,7 @@ public void TestOptionalParamChar_2ndMissingObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDecimal_2ndMissingObjectSyntax() { string request = @"{method:'TestOptionalParamdecimal_2x',params:{input1:123},id:1}"; @@ -894,7 +940,7 @@ public void TestOptionalParamDecimal_2ndMissingObjectSyntax() Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamByte_2ndPresentObjectSyntax() { string request = @"{method:'TestOptionalParambyte_2x',params:{input1:123, input2: 67},id:1}"; @@ -904,7 +950,7 @@ public void TestOptionalParamByte_2ndPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamByte_2ndPresentArraySyntax() { string request = @"{method:'TestOptionalParambyte_2x',params:[123, 67],id:1}"; @@ -914,7 +960,7 @@ public void TestOptionalParamByte_2ndPresentArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamByte_2ndMissingArraySyntax() { string request = @"{method:'TestOptionalParambyte_2x',params:[123],id:1}"; @@ -924,7 +970,7 @@ public void TestOptionalParamByte_2ndMissingArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamSbyte_2ndPresentObjectSyntax() { string request = @"{method:'TestOptionalParamsbyte_2x',params:{input1:123, input2: 97},id:1}"; @@ -934,7 +980,7 @@ public void TestOptionalParamSbyte_2ndPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamSbyte_2ndPresentArraySyntax() { string request = @"{method:'TestOptionalParamsbyte_2x',params:[123, 98],id:1}"; @@ -944,7 +990,7 @@ public void TestOptionalParamSbyte_2ndPresentArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamSbyte_2ndMissingArraySyntax() { string request = @"{method:'TestOptionalParamsbyte_2x',params:[123],id:1}"; @@ -954,7 +1000,7 @@ public void TestOptionalParamSbyte_2ndMissingArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamShort_2ndPresentObjectSyntax() { string request = @"{method:'TestOptionalParamshort_2x',params:{input1:123, input2: 671},id:1}"; @@ -964,7 +1010,7 @@ public void TestOptionalParamShort_2ndPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamShort_2ndPresentArraySyntax() { string request = @"{method:'TestOptionalParamshort_2x',params:[123, 671],id:1}"; @@ -974,7 +1020,7 @@ public void TestOptionalParamShort_2ndPresentArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamShort_2ndMissingArraySyntax() { string request = @"{method:'TestOptionalParamshort_2x',params:[123],id:1}"; @@ -984,7 +1030,7 @@ public void TestOptionalParamShort_2ndMissingArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamint_2ndPresentObjectSyntax() { string request = @"{method:'TestOptionalParamint_2x',params:{input1:123, input2: 671},id:1}"; @@ -994,7 +1040,7 @@ public void TestOptionalParamint_2ndPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamint_2ndPresentArraySyntax() { string request = @"{method:'TestOptionalParamint_2x',params:[123, 671],id:1}"; @@ -1004,7 +1050,7 @@ public void TestOptionalParamint_2ndPresentArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamint_2ndMissingArraySyntax() { string request = @"{method:'TestOptionalParamint_2x',params:[123],id:1}"; @@ -1014,7 +1060,7 @@ public void TestOptionalParamint_2ndMissingArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamLong_2ndPresentObjectSyntax() { string request = @"{method:'TestOptionalParamlong_2x',params:{input1:123, input2: 671},id:1}"; @@ -1024,7 +1070,7 @@ public void TestOptionalParamLong_2ndPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamLong_2ndPresentArraySyntax() { string request = @"{method:'TestOptionalParamlong_2x',params:[123, 671],id:1}"; @@ -1034,7 +1080,7 @@ public void TestOptionalParamLong_2ndPresentArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamLong_2ndMissingArraySyntax() { string request = @"{method:'TestOptionalParamlong_2x',params:[123],id:1}"; @@ -1044,7 +1090,7 @@ public void TestOptionalParamLong_2ndMissingArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUshort_2ndPresentObjectSyntax() { string request = @"{method:'TestOptionalParamushort_2x',params:{input1:123, input2: 671},id:1}"; @@ -1054,7 +1100,7 @@ public void TestOptionalParamUshort_2ndPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUshort_2ndPresentArraySyntax() { string request = @"{method:'TestOptionalParamushort_2x',params:[123, 671],id:1}"; @@ -1064,7 +1110,7 @@ public void TestOptionalParamUshort_2ndPresentArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUshort_2ndMissingArraySyntax() { string request = @"{method:'TestOptionalParamushort_2x',params:[123],id:1}"; @@ -1074,7 +1120,7 @@ public void TestOptionalParamUshort_2ndMissingArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUint_2ndPresentObjectSyntax() { string request = @"{method:'TestOptionalParamuint_2x',params:{input1:123, input2: 671},id:1}"; @@ -1084,7 +1130,7 @@ public void TestOptionalParamUint_2ndPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUint_2ndPresentArraySyntax() { string request = @"{method:'TestOptionalParamuint_2x',params:[123, 671],id:1}"; @@ -1094,7 +1140,7 @@ public void TestOptionalParamUint_2ndPresentArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUint_2ndMissingArraySyntax() { string request = @"{method:'TestOptionalParamuint_2x',params:[123],id:1}"; @@ -1104,7 +1150,7 @@ public void TestOptionalParamUint_2ndMissingArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUlong_2ndPresentObjectSyntax() { string request = @"{method:'TestOptionalParamulong_2x',params:{input1:123, input2: 671},id:1}"; @@ -1114,7 +1160,7 @@ public void TestOptionalParamUlong_2ndPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUlong_2ndPresentArraySyntax() { string request = @"{method:'TestOptionalParamulong_2x',params:[123, 671],id:1}"; @@ -1124,7 +1170,7 @@ public void TestOptionalParamUlong_2ndPresentArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamUlong_2ndMissingArraySyntax() { string request = @"{method:'TestOptionalParamulong_2x',params:[123],id:1}"; @@ -1134,7 +1180,7 @@ public void TestOptionalParamUlong_2ndMissingArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamFloat_2ndPresentObjectSyntax() { string request = @"{method:'TestOptionalParamfloat_2x',params:{input1:123, input2: 671},id:1}"; @@ -1144,7 +1190,7 @@ public void TestOptionalParamFloat_2ndPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamFloat_2ndPresentArraySyntax() { string request = @"{method:'TestOptionalParamfloat_2x',params:[123, 671],id:1}"; @@ -1154,7 +1200,7 @@ public void TestOptionalParamFloat_2ndPresentArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamFloat_2ndMissingArraySyntax() { string request = @"{method:'TestOptionalParamfloat_2x',params:[123],id:1}"; @@ -1164,7 +1210,7 @@ public void TestOptionalParamFloat_2ndMissingArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDouble_2ndPresentObjectSyntax() { string request = @"{method:'TestOptionalParamdouble_2x',params:{input1:123, input2: 671},id:1}"; @@ -1174,7 +1220,7 @@ public void TestOptionalParamDouble_2ndPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDouble_2ndPresentArraySyntax() { string request = @"{method:'TestOptionalParamdouble_2x',params:[123, 671],id:1}"; @@ -1184,7 +1230,7 @@ public void TestOptionalParamDouble_2ndPresentArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDouble_2ndMissingArraySyntax() { string request = @"{method:'TestOptionalParamdouble_2x',params:[123],id:1}"; @@ -1194,7 +1240,7 @@ public void TestOptionalParamDouble_2ndMissingArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamBool_2ndPresentObjectSyntax() { string request = @"{method:'TestOptionalParambool_2x',params:{input1:123, input2: 671},id:1}"; @@ -1204,7 +1250,7 @@ public void TestOptionalParamBool_2ndPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamBool_2ndPresentArraySyntax() { string request = @"{method:'TestOptionalParambool_2x',params:[true, false],id:1}"; @@ -1214,7 +1260,7 @@ public void TestOptionalParamBool_2ndPresentArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamBool_2ndMissingArraySyntax() { string request = @"{method:'TestOptionalParambool_2x',params:[123],id:1}"; @@ -1224,7 +1270,7 @@ public void TestOptionalParamBool_2ndMissingArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamChar_2ndPresentObjectSyntax() { string request = @"{method:'TestOptionalParamchar_2x',params:{'input1':" + (int)'c' + ", 'input2':" + (int)'d' + "},id:1}"; @@ -1234,7 +1280,7 @@ public void TestOptionalParamChar_2ndPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamChar_2ndPresentArraySyntax() { string request = @"{method:'TestOptionalParamchar_2x',params:[" + (int)'c' + ", " + (int)'d' + "],id:1}"; @@ -1244,17 +1290,17 @@ public void TestOptionalParamChar_2ndPresentArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamChar_2ndMissingArraySyntax() { - string request = @"{method:'TestOptionalParamchar_2x',params:["+(int)'c'+"],id:1}"; + string request = @"{method:'TestOptionalParamchar_2x',params:[" + (int)'c' + "],id:1}"; string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"d\",\"id\":1}"; var result = JsonRpcProcessor.Process(request); result.Wait(); Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDecimal_2ndPresentObjectSyntax() { string request = @"{method:'TestOptionalParamdecimal_2x',params:{input1:123, input2: 671},id:1}"; @@ -1264,7 +1310,7 @@ public void TestOptionalParamDecimal_2ndPresentObjectSyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDecimal_2ndPresentArraySyntax() { string request = @"{method:'TestOptionalParamdecimal_2x',params:[123, 671],id:1}"; @@ -1274,7 +1320,7 @@ public void TestOptionalParamDecimal_2ndPresentArraySyntax() Assert.IsFalse(result.Result.Contains("error")); Assert.AreEqual(expectedResult, result.Result); } - [TestMethod] + [Test()] public void TestOptionalParamDecimal_2ndMissingArraySyntax() { string request = @"{method:'TestOptionalParamdecimal_2x',params:[123],id:1}"; @@ -1285,6 +1331,664 @@ public void TestOptionalParamDecimal_2ndMissingArraySyntax() Assert.AreEqual(expectedResult, result.Result); } + [Test()] + public void TestOptionalParametersStrings_BothMissing() + { + string request = @"{method:'TestOptionalParameters_Strings',params:[],id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":[null,null],\"id\":1}"; + + var result = JsonRpcProcessor.Process(request); + result.Wait(); + Assert.IsFalse(result.Result.Contains("error")); + Assert.AreEqual(expectedResult, result.Result); + } + + [Test()] + public void TestOptionalParametersStrings_SecondMissing() + { + string request = @"{method:'TestOptionalParameters_Strings',params:['first'],id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":[\"first\",null],\"id\":1}"; + + var result = JsonRpcProcessor.Process(request); + result.Wait(); + Assert.IsFalse(result.Result.Contains("error")); + Assert.AreEqual(expectedResult, result.Result); + } + + [Test()] + public void TestOptionalParametersStrings_BothExists() + { + string request = @"{method:'TestOptionalParameters_Strings',params:['first','second'],id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":[\"first\",\"second\"],\"id\":1}"; + + var result = JsonRpcProcessor.Process(request); + result.Wait(); + Assert.IsFalse(result.Result.Contains("error")); + Assert.AreEqual(expectedResult, result.Result); + } + + [Test()] + public void TestOptionalParametersBoolsAndStrings() + { + string request = + "{\"jsonrpc\":\"2.0\",\"method\":\"TestOptionalParametersBoolsAndStrings\",\"params\":{\"input1\":\"murkel\"},\"Id\":1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":true,\"id\":1}"; + + var result = JsonRpcProcessor.Process(request); + result.Wait(); + Assert.IsFalse(result.Result.Contains("error")); + Assert.AreEqual(expectedResult, result.Result); + } + + [TestCase("{method:\"TestDifferentOptionalParameters\",params:{location:\"loc1\", uid:\"abc123\", wavelengths: [0.0], traces: [0.0]},id:1}", ExpectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"this is the requested measurement\",\"id\":1}")] + [TestCase("{method:\"TestDifferentOptionalParameters\",params:{uid:\"abc123\", wavelengths: [0.0], traces: [0.0]},id:1}", ExpectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"this is the requested measurement\",\"id\":1}")] + [TestCase("{method:\"TestDifferentOptionalParameters\",params:{location:\"loc1\", uid:\"abc123\", traces: [0.0]},id:1}", ExpectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"this is the requested measurement\",\"id\":1}")] + [TestCase("{method:\"TestDifferentOptionalParameters\",params:{location:\"loc1\", uid:\"abc123\", wavelengths: [0.0]},id:1}", ExpectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"this is the requested measurement\",\"id\":1}")] + [TestCase("{method:\"TestDifferentOptionalParameters\",params:{uid:\"abc123\", wavelengths: [0.0]},id:1}", ExpectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"this is the requested measurement\",\"id\":1}")] + public string TestDifferentOptionalParametersNamedWorking(string request) + { + var result = JsonRpcProcessor.Process(request); + result.Wait(); + return result.Result; + } + + [Test()] + public void TestBatchResultWrongRequests() + { + string request = @"[{},{""jsonrpc"":""2.0"",""id"":4}]"; + + var result = JsonRpcProcessor.Process(request); + result.Wait(); + + Assert.IsTrue(Regex.IsMatch(result.Result, @"\[(\{.*""error"":.*?,""id"":.*?\}),(\{.*""error"":.*?,""id"":.*?\})\]"), "Should have two errors."); + } + + [Test()] + public void TestBatchResultMultipleMethodCallsNotificationAtLast() + { + string request = + @"[{""jsonrpc"":""2.0"",""method"":""ReturnsDateTime"",""params"":{},""id"":1},{""jsonrpc"":""2.0"",""method"":""Notify"",""params"":[""Hello World!""]}]"; + + var result = JsonRpcProcessor.Process(request); + result.Wait(); + + Assert.IsFalse(result.Result.EndsWith(@",]"), "result.Result.EndsWith(@',]')"); + + } + + [Test()] + public void TestEmptyBatchResult() + { + var secondRequest = @"{""jsonrpc"":""2.0"",""method"":""Notify"",""params"":[""Hello World!""]}"; + var result = JsonRpcProcessor.Process(secondRequest); + result.Wait(); + + Assert.IsTrue(string.IsNullOrEmpty(result.Result)); + } + + + [Test()] + public void TestNotificationVoidResult() + { + var secondRequest = @"{""jsonrpc"":""2.0"",""method"":""Notify"",""params"":[""Hello World!""], ""id"":73}"; + var result = JsonRpcProcessor.Process(secondRequest); + result.Wait(); + Console.WriteLine(result.Result); + Assert.IsTrue(result.Result.Contains("result"), "Json Rpc 2.0 Spec - 'result' - This member is REQUIRED on success. A function that returns void should have the result property included even though the value may be null."); + } + + [Test()] + public void TestLeftOutParams() + { + var request = + @"{""jsonrpc"":""2.0"",""method"":""ReturnsDateTime"",""id"":1}"; + + var result = JsonRpcProcessor.Process(request); + result.Wait(); + + Assert.IsFalse(result.Result.Contains(@"error"":{""code"":-32602"), @"According to JSON-RPC 2.0 the ""params"" member MAY be omitted."); + } + + [Test()] + public void TestMultipleResults() + { + var result = + JsonRpcProcessor.Process( + @"[{""jsonrpc"":""2.0"",""method"":""ReturnsDateTime"",""params"":{},""id"":1},{""jsonrpc"":""2.0"",""method"":""ReturnsDateTime"",""params"":{},""id"":1}]"); + result.Wait(); + + Assert.IsTrue(result.Result.EndsWith("]")); + } + [Test()] + public void TestSingleResultBatch() + { + var result = + JsonRpcProcessor.Process(@"[{""jsonrpc"":""2.0"",""method"":""ReturnsDateTime"",""params"":{},""id"":1}]"); + result.Wait(); + Assert.IsFalse(result.Result.EndsWith("]")); + } + + class PreProcessHandlerLocal + { + public JsonRequest rpc = null; + public object context = null; + public int run = 0; + + public JsonRpcException PreProcess(JsonRequest rpc, object context) + { + run++; + + this.rpc = rpc; + this.context = context; + + return null; + } + } + + [Test()] + public void TestPreProcessor() + { + try { + PreProcessHandlerLocal handler = new PreProcessHandlerLocal(); + Config.SetPreProcessHandler(new PreProcessHandler(handler.PreProcess)); + string request = @"{method:'TestPreProcessor',params:{inputValue:'some string'},id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"Success!\",\"id\":1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + AssertJsonAreEqual(expectedResult, result.Result); + Assert.AreEqual(1, handler.run); + Assert.NotNull(handler.rpc, "RPC should not be null"); + Assert.Null(handler.context, "Context should be null"); + } finally { + Config.SetPreProcessHandler(null); + } + + } + + [Test()] + public void TestPreProcessorThrowsJsonRPCException() + { + try + { + PreProcessHandlerLocal handler = new PreProcessHandlerLocal(); + Config.SetPreProcessHandler(new PreProcessHandler(handler.PreProcess)); + string request = @"{method:'TestPreProcessorThrowsJsonRPCException',params:{inputValue:'some string'},id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-27000,\"message\":\"Just some testing\",\"data\":null},\"id\":1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + AssertJsonAreEqual(expectedResult, result.Result); + Assert.AreEqual(1, handler.run); + Assert.NotNull(handler.rpc, "RPC should not be null"); + Assert.Null(handler.context, "Context should be null"); + } + finally + { + Config.SetPreProcessHandler(null); + } + } + + [Test()] + public void TestPreProcessorThrowsException() + { + try + { + PreProcessHandlerLocal handler = new PreProcessHandlerLocal(); + Config.SetPreProcessHandler(new PreProcessHandler(handler.PreProcess)); + string request = @"{method:'TestPreProcessorThrowsException',params:{inputValue:'some string'},id:1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + StringAssert.Contains("-32603", result.Result); + Assert.AreEqual(1, handler.run); + Assert.NotNull(handler.rpc, "RPC should not be null"); + Assert.Null(handler.context, "Context should be null"); + } + finally + { + Config.SetPreProcessHandler(null); + } + } + + [Test()] + public void TestPreProcessorSetsException() + { + try + { + PreProcessHandlerLocal handler = new PreProcessHandlerLocal(); + Config.SetPreProcessHandler(new PreProcessHandler(handler.PreProcess)); + string request = @"{method:'TestPreProcessorSetsException',params:{inputValue:'some string'},id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-27000,\"message\":\"This exception was thrown using: JsonRpcContext.SetException()\",\"data\":null},\"id\":1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + AssertJsonAreEqual(expectedResult, result.Result); + Assert.AreEqual(1, handler.run); + Assert.NotNull(handler.rpc, "RPC should not be null"); + Assert.Null(handler.context, "Context should be null"); + } + finally + { + Config.SetPreProcessHandler(null); + } + } + + [Test()] + public void TestPreProcessOnSession() + { + var sessionId = "my session"; + var h = JsonRpc.Handler.GetSessionHandler(sessionId); + PreProcessHandlerLocal preHandler = new PreProcessHandlerLocal(); + h.SetPreProcessHandler(new PreProcessHandler(preHandler.PreProcess)); + + var metadata = new System.Collections.Generic.List> { + Tuple.Create ("sooper", typeof(string)), + Tuple.Create ("returns", typeof(string)) + }.ToDictionary(x => x.Item1, x => x.Item2); + h.RegisterFuction("workie", metadata, new System.Collections.Generic.Dictionary(),new Func(x => "workie ... " + x)); + + string request = @"{method:'workie',params:{'sooper':'good'},id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"workie ... good\",\"id\":1}"; + string expectedResultAfterDestroy = "{\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Method not found\",\"code\":-32601,\"data\":\"The method does not exist / is not available.\"},\"id\":1}"; + var result = JsonRpcProcessor.Process(sessionId, request); + result.Wait(); + + var actual1 = JObject.Parse(result.Result); + var expected1 = JObject.Parse(expectedResult); + Assert.IsTrue(JToken.DeepEquals(expected1, actual1)); + Assert.AreEqual(1, preHandler.run); + + h.Destroy(); + + var result2 = JsonRpcProcessor.Process(sessionId, request); + result2.Wait(); + + Assert.AreEqual(1, preHandler.run); + Assert.IsTrue(JToken.DeepEquals(JObject.Parse(expectedResultAfterDestroy), JObject.Parse(result2.Result))); + } + + class PostProcessHandlerLocal + { + public JsonRequest rpc = null; + public JsonResponse response = null; + public object context = null; + public int run = 0; + private bool changeResponse_; + + public PostProcessHandlerLocal(bool changeResponse) + { + changeResponse_ = changeResponse; + } + + public JsonRpcException PostProcess(JsonRequest rpc, JsonResponse response, object context) + { + run++; + + this.rpc = rpc; + this.response = response; + this.context = context; + + if (changeResponse_) + { + return new JsonRpcException(-123, "Test error", null); + } + return null; + } + } + + [Test()] + public void TestPostProcessor() + { + try + { + PostProcessHandlerLocal handler = new PostProcessHandlerLocal(false); + Config.SetPostProcessHandler(new PostProcessHandler(handler.PostProcess)); + string request = @"{method:'TestPostProcessor',params:{inputValue:'some string'},id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"Success!\",\"id\":1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + AssertJsonAreEqual(expectedResult, result.Result); + Assert.AreEqual(1, handler.run, "Expect number of times run 1"); + Assert.NotNull(handler.rpc, "RPC should not be null"); + Assert.NotNull(handler.response, "response should not be null"); + Assert.AreEqual("Success!", (string)handler.response.Result); + Assert.Null(handler.context, "Context should be null"); + } + finally + { + Config.SetPostProcessHandler(null); + } + } + + [Test()] + public void TestPostProcessorThrowsJsonRPCException() + { + try + { + PostProcessHandlerLocal handler = new PostProcessHandlerLocal(false); + Config.SetPostProcessHandler(new PostProcessHandler(handler.PostProcess)); + string request = @"{method:'TestPostProcessorThrowsJsonRPCException',params:{inputValue:'some string'},id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-27000,\"message\":\"Just some testing\",\"data\":null},\"id\":1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + AssertJsonAreEqual(expectedResult, result.Result); + Assert.AreEqual(1, handler.run); + Assert.NotNull(handler.rpc, "RPC should not be null"); + Assert.NotNull(handler.response, "response should not be null"); + Assert.Null(handler.response.Result, "Result should be null"); + Assert.NotNull(handler.response.Error, "Error should not be null"); + Assert.AreEqual(-27000, handler.response.Error.code, "Error code mismatch"); + Assert.AreEqual("Just some testing", handler.response.Error.message, "Error message mismatch"); + Assert.Null(handler.context, "Context should be null"); + } + finally + { + Config.SetPostProcessHandler(null); + } + } + + [Test()] + public void TestPostProcessorThrowsException() + { + try + { + PostProcessHandlerLocal handler = new PostProcessHandlerLocal(false); + Config.SetPostProcessHandler(new PostProcessHandler(handler.PostProcess)); + string request = @"{method:'TestPostProcessorThrowsException',params:{inputValue:'some string'},id:1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + StringAssert.Contains("-32603", result.Result); + Assert.AreEqual(1, handler.run); + Assert.NotNull(handler.rpc, "RPC should not be null"); + Assert.NotNull(handler.response, "response should not be null"); + Assert.Null(handler.response.Result, "Result should be null"); + Assert.NotNull(handler.response.Error, "Error should not be null"); + Assert.AreEqual(-32603, handler.response.Error.code, "Error code mismatch"); + Assert.Null(handler.context, "Context should be null"); + } + finally + { + Config.SetPostProcessHandler(null); + } + } + + [Test()] + public void TestPostProcessorSetsException() + { + try + { + PostProcessHandlerLocal handler = new PostProcessHandlerLocal(false); + Config.SetPostProcessHandler(new PostProcessHandler(handler.PostProcess)); + string request = @"{method:'TestPostProcessorSetsException',params:{inputValue:'some string'},id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-27001,\"message\":\"This exception was thrown using: JsonRpcContext.SetException()\",\"data\":null},\"id\":1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + AssertJsonAreEqual(expectedResult, result.Result); + Assert.AreEqual(1, handler.run); + Assert.NotNull(handler.rpc, "RPC should not be null"); + Assert.Null(handler.context, "Context should be null"); + } + finally + { + Config.SetPreProcessHandler(null); + } + } + + + [Test()] + public void TestPostProcessorChangesReturn() + { + try + { + PostProcessHandlerLocal handler = new PostProcessHandlerLocal(true); + Config.SetPostProcessHandler(new PostProcessHandler(handler.PostProcess)); + string request = @"{method:'TestPostProcessor',params:{inputValue:'some string'},id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-123,\"message\":\"Test error\",\"data\":null},\"id\":1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + AssertJsonAreEqual(expectedResult, result.Result); + Assert.AreEqual(1, handler.run); + Assert.AreEqual(1, handler.run, "Expect number of times run 1"); + Assert.NotNull(handler.rpc, "RPC should not be null"); + Assert.NotNull(handler.response, "response should not be null"); + Assert.AreEqual("Success!", (string)handler.response.Result); + Assert.Null(handler.context, "Context should be null"); + } + finally + { + Config.SetPostProcessHandler(null); + } + } + + [Test()] + public void TestPostProcessorThrowsJsonRPCExceptionChangesReturn() + { + try + { + PostProcessHandlerLocal handler = new PostProcessHandlerLocal(true); + Config.SetPostProcessHandler(new PostProcessHandler(handler.PostProcess)); + string request = @"{method:'TestPostProcessorThrowsJsonRPCException',params:{inputValue:'some string'},id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-123,\"message\":\"Test error\",\"data\":null},\"id\":1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + AssertJsonAreEqual(expectedResult, result.Result); + Assert.AreEqual(1, handler.run); + Assert.NotNull(handler.rpc, "RPC should not be null"); + Assert.NotNull(handler.response, "response should not be null"); + Assert.Null(handler.response.Result, "Result should be null"); + Assert.NotNull(handler.response.Error, "Error should not be null"); + Assert.AreEqual(-27000, handler.response.Error.code, "Error code mismatch"); + Assert.AreEqual("Just some testing", handler.response.Error.message, "Error message mismatch"); + Assert.Null(handler.context, "Context should be null"); + } + finally + { + Config.SetPostProcessHandler(null); + } + } + + [Test()] + public void TestPostProcessorThrowsExceptionChangesReturn() + { + try + { + PostProcessHandlerLocal handler = new PostProcessHandlerLocal(true); + Config.SetPostProcessHandler(new PostProcessHandler(handler.PostProcess)); + string request = @"{method:'TestPostProcessorThrowsException',params:{inputValue:'some string'},id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Test error\",\"code\":-123,\"data\":null},\"id\":1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + AssertJsonAreEqual(expectedResult, result.Result); + Assert.AreEqual(1, handler.run); + Assert.NotNull(handler.rpc, "RPC should not be null"); + Assert.NotNull(handler.response, "response should not be null"); + Assert.Null(handler.response.Result, "Result should be null"); + Assert.NotNull(handler.response.Error, "Error should not be null"); + Assert.AreEqual(-32603, handler.response.Error.code, "Error code mismatch"); + Assert.Null(handler.context, "Context should be null"); + } + finally + { + Config.SetPostProcessHandler(null); + } + } + + [Test()] + public void TestPostProcessOnSession() + { + var sessionId = "my first session"; + var h = JsonRpc.Handler.GetSessionHandler(sessionId); + PostProcessHandlerLocal postHandler = new PostProcessHandlerLocal(false); + h.SetPostProcessHandler(new PostProcessHandler(postHandler.PostProcess)); + + var metadata = new System.Collections.Generic.List> { + Tuple.Create ("sooper", typeof(string)), + Tuple.Create ("returns", typeof(string)) + }.ToDictionary(x => x.Item1, x => x.Item2); + h.RegisterFuction("workie", metadata, new System.Collections.Generic.Dictionary(), new Func(x => "workie ... " + x)); + + string request = @"{method:'workie',params:{'sooper':'good'},id:1}"; + string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":\"workie ... good\",\"id\":1}"; + string expectedResultAfterDestroy = "{\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Method not found\",\"code\":-32601,\"data\":\"The method does not exist / is not available.\"},\"id\":1}"; + var result = JsonRpcProcessor.Process(sessionId, request); + result.Wait(); + + var actual1 = JObject.Parse(result.Result); + var expected1 = JObject.Parse(expectedResult); + Assert.IsTrue(JToken.DeepEquals(expected1, actual1)); + Assert.AreEqual(1, postHandler.run); + + h.Destroy(); + + var result2 = JsonRpcProcessor.Process(sessionId, request); + result2.Wait(); + + Assert.AreEqual(1, postHandler.run); + Assert.IsTrue(JToken.DeepEquals(JObject.Parse(expectedResultAfterDestroy), JObject.Parse(result2.Result))); + } + + [Test()] + public void TestExtraParameters() + { + string request = @"{method:'ReturnsDateTime',params:{extra:'mytext'},id:1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + Assert.IsTrue(result.Result.Contains("error")); + Assert.IsTrue(result.Result.Contains("\"code\":-32602")); + } + + [Test()] + public void TestExtraPositionalParameters() + { + string request = @"{method:'ReturnsDateTime',params:[1,2,'mytext'],id:1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + Assert.IsTrue(result.Result.Contains("error")); + Assert.IsTrue(result.Result.Contains("\"code\":-32602")); + } + + [Test()] + public void TestCustomParameterName() + { + Func request = (string paramName) => String.Format("{{method:'TestCustomParameterName',params:{{ {0}:'some string'}},id:1}}", paramName); + string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":true,\"id\":1}"; + // Check custom param name specified in attribute works + var result = JsonRpcProcessor.Process(request("myCustomParameter")); + result.Wait(); + Assert.AreEqual(JObject.Parse(expectedResult), JObject.Parse(result.Result)); + // Check method can't be used with its actual parameter name + result = JsonRpcProcessor.Process(request("arg")); + result.Wait(); + StringAssert.Contains("-32602", result.Result); // check for 'invalid params' error code + } + + [Test()] + public void TestCustomParameterWithNoSpecificName() + { + Func request = (string paramName) => String.Format("{{method:'TestCustomParameterWithNoSpecificName',params:{{ {0}:'some string'}},id:1}}", paramName); + string expectedResult = "{\"jsonrpc\":\"2.0\",\"result\":true,\"id\":1}"; + // Check method can be used with its parameter name + var result = JsonRpcProcessor.Process(request("arg")); + result.Wait(); + Assert.AreEqual(JObject.Parse(expectedResult), JObject.Parse(result.Result)); + } + + [Test] + public void TestNestedReturnType() + { + var request = @"{""jsonrpc"":""2.0"",""method"":""TestNestedReturnType"",""id"":1}"; + var expected = @"{""jsonrpc"":""2.0"",""result"":{""NodeId"":1,""Leafs"":[{""NodeId"":2,""Leafs"":[]},{""NodeId"":3,""Leafs"":[]}]},""id"":1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + Assert.AreEqual(expected, result.Result); + } + + [Test()] + public void TestWrongParamType() + { + string request = @"{method:'TestOptionalParamdouble',params:{input:'mytext'},id:1}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + Assert.IsTrue(result.Result.Contains("error")); + Assert.IsTrue(result.Result.Contains("\"code\":-32603")); + } + + [Test()] + public void TestWrongIdType() + { + string request = @"{method:'TestOptionalParamdouble',params:{input:5},id:{what:4,that:3}}"; + var result = JsonRpcProcessor.Process(request); + result.Wait(); + Assert.IsTrue(result.Result.Contains("error")); + Assert.IsTrue(result.Result.Contains("\"code\":-32600")); + } + + private static void AssertJsonAreEqual(string expectedJson, string actualJson) + { + Newtonsoft.Json.Linq.JObject expected = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(expectedJson); + Newtonsoft.Json.Linq.JObject actual = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(actualJson); + AssertJsonAreEqual(expected, actual, "root"); + } + + private static void AssertJsonAreEqual(JToken expectedJson, JToken actualJson, string path) + { + Assert.AreEqual(expectedJson.GetType(), actualJson.GetType(), "Type mismatch at " + path); + if (expectedJson is JObject) + { + AssertJsonAreEqual((JObject)expectedJson, (JObject)actualJson, path); + } else if (expectedJson is JObject) + { + AssertJsonAreEqual((JArray)expectedJson, (JArray)actualJson, path); + } else if (expectedJson is JValue) + { + AssertJsonAreEqual((JValue)expectedJson, (JValue)actualJson, path); + } else + { + throw new Exception("I don't know how to handle " + expectedJson.GetType().ToString()); + } + } + + private static void AssertJsonAreEqual(JObject expectedJson, JObject actualJson, string path) + { + Console.WriteLine("expected: {0}", expectedJson); + Console.WriteLine("actual : {0}", actualJson); + Assert.AreEqual(expectedJson.Count, actualJson.Count, "Count of json object at " + path); + for (var expectedElementsEnumerator = expectedJson.GetEnumerator(); expectedElementsEnumerator.MoveNext(); ) + { + JToken actualElement = null; + Assert.IsTrue(actualJson.TryGetValue(expectedElementsEnumerator.Current.Key, out actualElement), "Couldn't find " + path + "[" + expectedElementsEnumerator.Current.Key + "]"); + AssertJsonAreEqual(expectedElementsEnumerator.Current.Value, actualElement, path + "[" + expectedElementsEnumerator.Current.Key + "]"); + } + } + + private static void AssertJsonAreEqual(JArray expectedJson, JArray actualJson, string path) + { + Assert.AreEqual(expectedJson.Count, actualJson.Count, "Count of json array at " + path); + for (int jsonIndex = 0; jsonIndex < expectedJson.Count; jsonIndex++) + { + AssertJsonAreEqual(expectedJson[jsonIndex], actualJson[jsonIndex], path + "[" + jsonIndex.ToString() + "]"); + } + } + + private static void AssertJsonAreEqual(JValue expectedJson, JValue actualJson, string path) + { + Assert.AreEqual(expectedJson.Type, actualJson.Type, path); + switch (expectedJson.Type) + { + case JTokenType.Boolean: + Assert.AreEqual((bool)expectedJson.Value, (bool)actualJson.Value, path); + break; + case JTokenType.Integer: + Assert.AreEqual((System.Int64)expectedJson.Value, (System.Int64)actualJson.Value, path); + break; + case JTokenType.String: + Assert.AreEqual((string)expectedJson.Value, (string)actualJson.Value, path); + break; + case JTokenType.Null: + //Not used + break; + default: + throw new Exception("I don't know how to handle type " + expectedJson.Type.ToString()); + } + } } } + diff --git a/AustinHarris.JsonRpcTest/service.cs b/AustinHarris.JsonRpcTestN/service.cs similarity index 67% rename from AustinHarris.JsonRpcTest/service.cs rename to AustinHarris.JsonRpcTestN/service.cs index cfa256e..b34d957 100644 --- a/AustinHarris.JsonRpcTest/service.cs +++ b/AustinHarris.JsonRpcTestN/service.cs @@ -1,11 +1,19 @@ using AustinHarris.JsonRpc; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; -namespace UnitTests +namespace AustinHarris.JsonRpcTestN { + public class TreeNode + { + public int NodeId { get; set; } + + public IList Leafs { get; set; } + } + public class CalculatorService : JsonRpcService { [JsonRpcMethod] @@ -42,7 +50,6 @@ private List StringToListOfString(string input) private List StringToThrowingException(string input) { throw new Exception("Throwing Exception"); - return new List() { "one", "two", "three", input }; } public class CustomString @@ -72,6 +79,19 @@ private string devideByZero(string s) return s + j / i; } + + [JsonRpcMethod] + private bool TestCustomParameterName([JsonRpcParam("myCustomParameter")] string arg) + { + return true; + } + + [JsonRpcMethod] + private bool TestCustomParameterWithNoSpecificName([JsonRpcParam] string arg) + { + return true; + } + [JsonRpcMethod] private string StringToRefException(string s, ref JsonRpcException refException) { @@ -283,7 +303,98 @@ public decimal TestOptionalParamdecimal_2x(decimal input1, decimal input2 = 987) { return input2; } + [JsonRpcMethod] + private IList TestOptionalParameters_Strings(string input1 = null, string input2 = null) + { + return new List() + { + input1, + input2 + }; + } + + [JsonRpcMethod] + public bool TestOptionalParametersBoolsAndStrings(string input1, bool input2 = true, string input3 = "") + { + return input2; + } + [JsonRpcMethod] + public void Notify(string message) + { + Trace.WriteLine(string.Format("Notified about: {0}", message)); + } + + [JsonRpcMethod] + public string TestPreProcessor(string inputValue) + { + return "Success!"; + } + + [JsonRpcMethod] + public string TestPreProcessorThrowsJsonRPCException(string inputValue) + { + throw new JsonRpcException(-27000, "Just some testing", null); + } + + [JsonRpcMethod] + public string TestPreProcessorThrowsException(string inputValue) + { + throw new Exception("TestException"); + } + + [JsonRpcMethod] + public string TestPreProcessorSetsException(string inputValue) + { + JsonRpcContext.SetException(new JsonRpcException(-27000, "This exception was thrown using: JsonRpcContext.SetException()", null)); + return null; + } + + [JsonRpcMethod] + public string TestPostProcessor(string inputValue) + { + return "Success!"; + } + + [JsonRpcMethod] + public string TestPostProcessorThrowsJsonRPCException(string inputValue) + { + throw new JsonRpcException(-27000, "Just some testing", null); + } + + [JsonRpcMethod] + public string TestPostProcessorThrowsException(string inputValue) + { + throw new Exception("TestException"); + } + + [JsonRpcMethod] + public string TestPostProcessorSetsException(string inputValue) + { + JsonRpcContext.SetException(new JsonRpcException(-27001, "This exception was thrown using: JsonRpcContext.SetException()", null)); + return null; + } + + [JsonRpcMethod] + public TreeNode TestNestedReturnType() + { + return new TreeNode + { + NodeId = 1, + Leafs = + new[] + { + new TreeNode {NodeId = 2, Leafs = new List()}, + new TreeNode {NodeId = 3, Leafs = new List()} + } + }; + } + + [JsonRpcMethod] + private string TestDifferentOptionalParameters(string uid, string location = null, List traces = null, List wavelengths = null) + { + return "this is the requested measurement"; + } } } diff --git a/Json-Rpc/Attributes.cs b/Json-Rpc/Attributes.cs index dd78282..1592511 100644 --- a/Json-Rpc/Attributes.cs +++ b/Json-Rpc/Attributes.cs @@ -24,4 +24,27 @@ public string JsonMethodName get { return jsonMethodName; } } } + + /// + /// Used to assign JsonRpc parameter name to method argument. + /// + [AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)] + public sealed class JsonRpcParamAttribute : Attribute + { + readonly string jsonParamName; + + /// + /// Used to assign JsonRpc parameter name to method argument. + /// + /// Lets you specify the parameter name as it will be referred to by JsonRpc. + public JsonRpcParamAttribute(string jsonParamName = "") + { + this.jsonParamName = jsonParamName; + } + + public string JsonParamName + { + get { return jsonParamName; } + } + } } diff --git a/Json-Rpc/AustinHarris.JsonRpc.csproj b/Json-Rpc/AustinHarris.JsonRpc.csproj index 3f7907f..f6a680d 100644 --- a/Json-Rpc/AustinHarris.JsonRpc.csproj +++ b/Json-Rpc/AustinHarris.JsonRpc.csproj @@ -1,89 +1,27 @@ - - - - Debug - x86 - 8.0.30703 - 2.0 - {24FC1A2A-0BC3-43A7-9BFE-B628C2C4A307} - Library - Properties - AustinHarris.JsonRpc - AustinHarris.JsonRpc - v4.0 - - - 512 - SAK - SAK - SAK - SAK - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - - - - AnyCPU - bin\Debug\ - TRACE;DEBUG - - - AnyCPU - bin\Release\ - - - - - - - - - - - - - - - - - - - - False - ..\packages\Newtonsoft.Json.6.0.3\lib\net40\Newtonsoft.Json.dll - - - - - - - - + + + + Austin Harris + Json-Rpc.Net Core + Core functionality for JsonRpc.Net + 1.2.3 + $(VersionSuffix) + Austin Harris + https://github.com/Astn/JSON-RPC.NET + https://raw.githubusercontent.com/Astn/JSON-RPC.NET/master/LICENSE + + Improves support for optional parameters - @HoMS1987 https://github.com/HoMS1987 + Fixes protocol validation of the ID property - @pedrolcl https://github.com/pedrolcl + DotNet Core support - @astn https://github.com/astn + + netstandard2.0;netstandard2.1;netcoreapp3.1 + true + + + + + + + + \ No newline at end of file diff --git a/Json-Rpc/AustinHarris.JsonRpc.nuspec b/Json-Rpc/AustinHarris.JsonRpc.nuspec index 296958d..ad36f62 100644 --- a/Json-Rpc/AustinHarris.JsonRpc.nuspec +++ b/Json-Rpc/AustinHarris.JsonRpc.nuspec @@ -3,21 +3,21 @@ AustinHarris.JsonRpc $version$ - JSON-RPC.NET Core + JSON-RPC.NET Austin Harris - http://jsonrpc2.codeplex.com/license - http://jsonrpc2.codeplex.com/ + https://raw.githubusercontent.com/Astn/JSON-RPC.NET/master/LICENSE + https://github.com/Astn/JSON-RPC.NET http://download-codeplex.sec.s-msft.com/Download?ProjectName=jsonrpc2&DownloadId=487107 false - Core functionality for JsonRpc.Net - JSON-RPC.Net is a high performance Json-Rpc 2.0 server, leveraging the popular JSON.NET library. Host in ASP.NET, also supports sockets and pipes, oh my! - Added support for optional params. Improved task usage / performance. Better float handling for non en-US cultures. Can now override ParseErrors. Can now unregister handlers. Using lower-cased property names during serialization. Many thanks to raistlinthewiz. + The fastest .Net JSON RPC Server + JSON-RPC.Net is a high performance Json-Rpc 2.0 server, leveraging the popular JSON.NET library. Easily create a JSON RPC server for your Angular javascript apps, also supports sockets and pipes, oh my! + Optional JsonSerializer Settings - @hovi. ProcessSync is now public - @astn en-US - Json Rpc Json-Rpc.Net Json-Rpc JsonRpc Json.net + fast json rpc server socket javascript json-rpc.net json-rpc jsonrpc json.net web services webapi service angular server angularjs - + diff --git a/Json-Rpc/Config.cs b/Json-Rpc/Config.cs index 5c2c1e7..9e6692e 100644 --- a/Json-Rpc/Config.cs +++ b/Json-Rpc/Config.cs @@ -13,6 +13,16 @@ namespace AustinHarris.JsonRpc /// The context associated with this request /// Any non-null result causes the operation to be aborted, and the JsonRpcException is returned to the caller. public delegate JsonRpcException PreProcessHandler(JsonRequest request, object context); + /// + /// The PostProcessHandler is called after the response has been created and prior to returning the data to the caller. + /// If any non-null result is returned from the PostProcessHandler, the current return value is discared and the new return value used + /// in preference. + /// + /// The jsonRpc Request that has been processed. + /// The jsonRpc Response that has been created. + /// The context associated with this request/response pair + /// Any non-null result causes the result to be discarded and the JsonRpcException is returned to the caller. + public delegate JsonRpcException PostProcessHandler(JsonRequest request, JsonResponse response, object context); /// /// Global configurations for JsonRpc @@ -28,6 +38,15 @@ public static void SetPreProcessHandler(PreProcessHandler handler) Handler.DefaultHandler.SetPreProcessHandler(handler); } + /// + /// Sets the the PostProcessing Handler on the default session. + /// + /// + public static void SetPostProcessHandler(PostProcessHandler handler) + { + Handler.DefaultHandler.SetPostProcessHandler(handler); + } + /// /// Sets the PreProcessing Handler on a specific session /// diff --git a/Json-Rpc/Handler.cs b/Json-Rpc/Handler.cs index 2b461d2..095bacb 100644 --- a/Json-Rpc/Handler.cs +++ b/Json-Rpc/Handler.cs @@ -8,15 +8,21 @@ using Newtonsoft.Json; using System.Threading.Tasks; using System.Collections.Concurrent; -using Newtonsoft.Json.Linq; + using Newtonsoft.Json.Linq; + using System.Threading; public class Handler { #region Members - - //private static Handler current; - private static ConcurrentDictionary _sessionHandlers; - private static string _defaultSessionId; + private const string Name_of_JSONRPCEXCEPTION = "JsonRpcException&"; + private static int _sessionHandlerMasterVersion = 1; + [ThreadStatic] + private static Dictionary _sessionHandlersLocal; + [ThreadStatic] + private static int _sessionHandlerLocalVersion = 0; + private static ConcurrentDictionary _sessionHandlersMaster; + + private static volatile string _defaultSessionId; #endregion #region Constructors @@ -25,15 +31,14 @@ static Handler() { //current = new Handler(Guid.NewGuid().ToString()); _defaultSessionId = Guid.NewGuid().ToString(); - _sessionHandlers = new ConcurrentDictionary(); - _sessionHandlers[_defaultSessionId]= new Handler(_defaultSessionId); + _sessionHandlersMaster = new ConcurrentDictionary(); + _sessionHandlersMaster[_defaultSessionId] = new Handler(_defaultSessionId); } private Handler(string sessionId) { SessionId = sessionId; this.MetaData = new SMD(); - this.Handlers = new Dictionary(); } #endregion @@ -53,9 +58,19 @@ private Handler(string sessionId) /// public static Handler GetSessionHandler(string sessionId) { - return _sessionHandlers.GetOrAdd(sessionId, new Handler(sessionId)); + if (_sessionHandlerMasterVersion != _sessionHandlerLocalVersion) + { + _sessionHandlersLocal = new Dictionary(_sessionHandlersMaster); + _sessionHandlerLocalVersion = _sessionHandlerMasterVersion; + } + if (_sessionHandlersLocal.ContainsKey(sessionId)) + { + return _sessionHandlersLocal[sessionId]; + } + Interlocked.Increment(ref _sessionHandlerMasterVersion); + return _sessionHandlersMaster.GetOrAdd(sessionId, new Handler(sessionId)); } - + /// /// gets the default session /// @@ -72,8 +87,8 @@ public static Handler GetSessionHandler() public static void DestroySession(string sessionId) { Handler h; - _sessionHandlers.TryRemove(sessionId,out h); - h.Handlers.Clear(); + _sessionHandlersMaster.TryRemove(sessionId, out h); + Interlocked.Increment(ref _sessionHandlerMasterVersion); h.MetaData.Services.Clear(); } /// @@ -92,10 +107,7 @@ public void Destroy() /// /// The sessionID of this Handler /// - public string SessionId { get; private set; } - - private static ConcurrentDictionary RpcContexts = new ConcurrentDictionary(); - private static ConcurrentDictionary RpcExceptions = new ConcurrentDictionary(); + public string SessionId { get; private set; } /// /// Provides access to a context specific to each JsonRpc method invocation. @@ -104,43 +116,31 @@ public void Destroy() /// public static object RpcContext() { - if (Task.CurrentId == null) - return null; - - if (RpcContexts.ContainsKey(Task.CurrentId.Value) == false) - return null; - - return RpcContexts[Task.CurrentId.Value]; + return __currentRpcContext; } + [ThreadStatic] + static JsonRpcException __currentRpcException; /// /// Allows you to set the exception used in in the JsonRpc response. - /// Warning: Must be called from within the execution context of the jsonRpc method. + /// Warning: Must be called from the same thread as the jsonRpc method. /// /// public static void RpcSetException(JsonRpcException exception) { - if (Task.CurrentId != null) - RpcExceptions[Task.CurrentId.Value] = exception; - else - throw new InvalidOperationException("This method is only valid when used within the context of a method marked as a JsonRpcMethod, and that method must of been invoked by the JsonRpc Handler."); + __currentRpcException = exception; } - - private void RemoveRpcException() + public static JsonRpcException RpcGetAndRemoveRpcException() { - if (Task.CurrentId != null) - { - var id = Task.CurrentId.Value; - RpcExceptions[id] = null; - JsonRpcException va; - RpcExceptions.TryRemove(id, out va); - } + var ex = __currentRpcException; + __currentRpcException = null ; + return ex; } private AustinHarris.JsonRpc.PreProcessHandler externalPreProcessingHandler; + private AustinHarris.JsonRpc.PostProcessHandler externalPostProcessingHandler; private Func externalErrorHandler; private Func parseErrorHandler; - private Dictionary Handlers { get; set; } #endregion /// @@ -151,27 +151,41 @@ private void RemoveRpcException() #region Public Methods /// - /// Registers a jsonRpc method name (key) to be mapped to a specific function + /// Allows you to register all the functions on a Pojo Type that have been attributed as [JsonRpcMethod] to the specified sessionId /// - /// The Method as it will be called from JsonRpc - /// The method that will be invoked - /// - public bool Register(string key, Delegate handle) + /// The session to register against + /// The instance containing JsonRpcMethods to register + public static void RegisterInstance(string sessionID, object instance) { - var result = false; + ServiceBinder.BindService(sessionID, instance); + } - if (!this.Handlers.ContainsKey(key)) - { - this.Handlers.Add(key, handle); - } + /// + /// Allows you to register any function, lambda, etc even when not attributed with JsonRpcMethod. + /// Requires you to specify all types and defaults + /// + /// The method name that will map to the registered function + /// The parameter names and types that will be positionally bound to the function + /// Optional default values for parameters + /// A reference to the Function + public void RegisterFuction(string methodName, Dictionary parameterNameTypeMapping, Dictionary parameterNameDefaultValueMapping, Delegate implementation) + { + MetaData.AddService(methodName, parameterNameTypeMapping, parameterNameDefaultValueMapping, implementation); + } - return result; + public void UnRegisterFunction(string methodName) + { + MetaData.Services.Remove(methodName); } - public void UnRegister(string key) + public void SetPreProcessHandler(AustinHarris.JsonRpc.PreProcessHandler handler) { - this.Handlers.Remove(key); - MetaData.Services.Remove(key); + externalPreProcessingHandler = handler; + } + + public void SetPostProcessHandler(AustinHarris.JsonRpc.PostProcessHandler handler) + { + externalPostProcessingHandler = handler; } /// @@ -187,84 +201,92 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null) var preProcessingException = PreProcess(Rpc, RpcContext); if (preProcessingException != null) { - return new JsonResponse() { Error = preProcessingException, - Id = Rpc.Id }; + JsonResponse response = new JsonResponse() + { + Error = preProcessingException, + Id = Rpc.Id + }; + //callback is called - if it is empty then nothing will be done + //return response always- if callback is empty or not + return PostProcess(Rpc, response, RpcContext); } SMDService metadata = null; Delegate handle = null; - var haveDelegate = this.Handlers.TryGetValue(Rpc.Method, out handle); - var haveMetadata = this.MetaData.Services.TryGetValue(Rpc.Method, out metadata); - - if (haveDelegate == false || haveMetadata == false || metadata == null || handle == null) + if (this.MetaData.Services.TryGetValue(Rpc.Method, out metadata)) { - return new JsonResponse() { Result = null, Error = new JsonRpcException(-32601, "Method not found", "The method does not exist / is not available."), Id = Rpc.Id }; - } - if (Rpc.Params is ICollection == false) + handle = metadata.dele; + } else if (metadata == null) { - return new JsonResponse() + JsonResponse response = new JsonResponse() { Result = null, - Error = new JsonRpcException(-32602, - "Invalid params", "The number of parameters could not be counted"), + Error = new JsonRpcException(-32601, "Method not found", "The method does not exist / is not available."), Id = Rpc.Id }; + return PostProcess(Rpc, response, RpcContext); } - bool isJObject = Rpc.Params is Newtonsoft.Json.Linq.JObject; - bool isJArray = Rpc.Params is Newtonsoft.Json.Linq.JArray; object[] parameters = null; bool expectsRefException = false; var metaDataParamCount = metadata.parameters.Count(x => x != null); + + var loopCt = 0; var getCount = Rpc.Params as ICollection; - var loopCt = getCount.Count; + if (getCount != null) + { + loopCt = getCount.Count; + } + var paramCount = loopCt; - if (paramCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount-1].ObjectType.Name.Contains(typeof(JsonRpcException).Name)) + if (paramCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount - 1].ObjectType.Name.Equals(Name_of_JSONRPCEXCEPTION)) { paramCount++; expectsRefException = true; } parameters = new object[paramCount]; - if (isJArray) + if (Rpc.Params is Newtonsoft.Json.Linq.JArray) { var jarr = ((Newtonsoft.Json.Linq.JArray)Rpc.Params); - //var loopCt = jarr.Count; - //var pCount = loopCt; - //if (pCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount].GetType() == typeof(JsonRpcException)) - // pCount++; - //parameters = new object[pCount]; - for (int i = 0; i < loopCt; i++) + for (int i = 0; i < loopCt && i < metadata.parameters.Length; i++) { parameters[i] = CleanUpParameter(jarr[i], metadata.parameters[i]); - } + } } - else if (isJObject) + else if (Rpc.Params is Newtonsoft.Json.Linq.JObject) { - var jo = Rpc.Params as Newtonsoft.Json.Linq.JObject; - //var loopCt = jo.Count; - //var pCount = loopCt; - //if (pCount == metaDataParamCount - 1 && metadata.parameters[metaDataParamCount].GetType() == typeof(JsonRpcException)) - // pCount++; - //parameters = new object[pCount]; - var asDict = jo as IDictionary; - for (int i = 0; i < loopCt; i++) + var asDict = Rpc.Params as IDictionary; + for (int i = 0; i < loopCt && i < metadata.parameters.Length; i++) { - if (asDict.ContainsKey(metadata.parameters[i].Name) == false) + if (asDict.ContainsKey(metadata.parameters[i].Name) == true) { - return new JsonResponse() + parameters[i] = CleanUpParameter(asDict[metadata.parameters[i].Name], metadata.parameters[i]); + continue; + } + else + { + var foundDefault = metadata.defaultValues + .FirstOrDefault(defaul => defaul.Name == metadata.parameters[i].Name); + if (foundDefault != null) + { + parameters[i] = foundDefault.Value; + continue; + } + + JsonResponse response = new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32602, "Invalid params", string.Format("Named parameter '{0}' was not present.", metadata.parameters[i].Name) - )) - ,Id = Rpc.Id + )), + Id = Rpc.Id }; + return PostProcess(Rpc, response, RpcContext); } - parameters[i] = CleanUpParameter(jo[metadata.parameters[i].Name], metadata.parameters[i]); } } @@ -273,25 +295,37 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null) // if the rpc-call didn't supply a value for an optional parameter, we should be assinging the default value of it. if (parameters.Length < metaDataParamCount && metadata.defaultValues.Length > 0) // rpc call didn't set values for all optional parameters, so we need to assign the default values for them. { - var paramIndex = parameters.Length; // the index we should start storing default values of optional parameters. + var suppliedParamsCount = parameters.Length; // the index we should start storing default values of optional parameters. var missingParamsCount = metaDataParamCount - parameters.Length; // the amount of optional parameters without a value set by rpc-call. - Array.Resize(ref parameters, parameters.Length + metadata.defaultValues.Length); // resize the array to include all optional parameters. + Array.Resize(ref parameters, parameters.Length + missingParamsCount); // resize the array to include all optional parameters. - // we need to add in reverse order as parameters can appear after all required parameters. - // as some of the optional parameters could already have assigned their values in rpc-call, - // by starting from the end we can make sure we only add the required default values. - for (int k = missingParamsCount; k > 0; k--) + for (int paramIndex = parameters.Length - 1, defaultIndex = metadata.defaultValues.Length - 1; // fill missing parameters from the back + paramIndex >= suppliedParamsCount && defaultIndex >= 0; // to don't overwrite supplied ones. + paramIndex--, defaultIndex--) { - var optionalParamIndex = k - 1; // the index of the optional parameter we will be currently setting a default value. - parameters[paramIndex] = metadata.defaultValues[optionalParamIndex].Value; // set the default value for the optional parameter that rpc-call didn't set a value for. - paramIndex++; - paramCount++; // we need to increase the paramCount by one each time we add default-value for an optional parameter that rpc-call didn't set a value for. + parameters[paramIndex] = metadata.defaultValues[defaultIndex].Value; + } + + if (missingParamsCount > metadata.defaultValues.Length) + { + JsonResponse response = new JsonResponse + { + Error = ProcessException(Rpc, + new JsonRpcException(-32602, + "Invalid params", + string.Format( + "Number of default parameters {0} not sufficient to fill all missing parameters {1}", + metadata.defaultValues.Length, missingParamsCount) + )), + Id = Rpc.Id + }; + return PostProcess(Rpc, response, RpcContext); } } - + if (parameters.Length != metaDataParamCount) { - return new JsonResponse() + JsonResponse response = new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32602, @@ -302,76 +336,84 @@ public JsonResponse Handle(JsonRequest Rpc, Object RpcContext = null) )), Id = Rpc.Id }; + return PostProcess(Rpc, response, RpcContext); } try { var results = handle.DynamicInvoke(parameters); - var last = parameters.Length>0 ? parameters[paramCount - 1]:null; - JsonRpcException contextException; - if (Task.CurrentId.HasValue && RpcExceptions.TryRemove(Task.CurrentId.Value, out contextException)) + + var last = parameters.LastOrDefault(); + var contextException = RpcGetAndRemoveRpcException(); + JsonResponse response = null; + if (contextException != null) { - return new JsonResponse() { Error = ProcessException(Rpc, contextException), Id = Rpc.Id }; + response = new JsonResponse() { Error = ProcessException(Rpc, contextException), Id = Rpc.Id }; } - if (expectsRefException && last != null && last is JsonRpcException) + else if (expectsRefException && last != null && last is JsonRpcException) { - return new JsonResponse() { Error = ProcessException(Rpc, last as JsonRpcException), Id = Rpc.Id }; + response = new JsonResponse() { Error = ProcessException(Rpc, last as JsonRpcException), Id = Rpc.Id }; } - - return new JsonResponse() { Result = results }; + else + { + response = new JsonResponse() { Result = results }; + } + return PostProcess(Rpc, response, RpcContext); } catch (Exception ex) { + JsonResponse response; if (ex is TargetParameterCountException) { - return new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32602, "Invalid params", ex)) }; + response = new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32602, "Invalid params", ex)) }; + return PostProcess(Rpc, response, RpcContext); } // We really dont care about the TargetInvocationException, just pass on the inner exception if (ex is JsonRpcException) { - return new JsonResponse() { Error = ProcessException(Rpc, ex as JsonRpcException) }; + response = new JsonResponse() { Error = ProcessException(Rpc, ex as JsonRpcException) }; + return PostProcess(Rpc, response, RpcContext); } if (ex.InnerException != null && ex.InnerException is JsonRpcException) { - return new JsonResponse() { Error = ProcessException(Rpc, ex.InnerException as JsonRpcException) }; + response = new JsonResponse() { Error = ProcessException(Rpc, ex.InnerException as JsonRpcException) }; + return PostProcess(Rpc, response, RpcContext); } else if (ex.InnerException != null) { - return new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32603, "Internal Error", ex.InnerException)) }; + response = new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32603, "Internal Error", ex.InnerException)) }; + return PostProcess(Rpc, response, RpcContext); } - return new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32603, "Internal Error", ex)) }; + response = new JsonResponse() { Error = ProcessException(Rpc, new JsonRpcException(-32603, "Internal Error", ex)) }; + return PostProcess(Rpc, response, RpcContext); } finally { RemoveRpcContext(); } } + #endregion + [ThreadStatic] + static object __currentRpcContext; private void AddRpcContext(object RpcContext) { - if (Task.CurrentId != null) - RpcContexts[Task.CurrentId.Value] = RpcContext; + __currentRpcContext = RpcContext; } private void RemoveRpcContext() { - if (Task.CurrentId != null) - { - var id = Task.CurrentId.Value; - RpcContexts[id] = null; - object va; - RpcContexts.TryRemove(id, out va); - } + __currentRpcContext = null; } - - private JsonRpcException ProcessException(JsonRequest req,JsonRpcException ex) + + private JsonRpcException ProcessException(JsonRequest req, JsonRpcException ex) { - if(externalErrorHandler!=null) - return externalErrorHandler(req,ex); + if (externalErrorHandler != null) + return externalErrorHandler(req, ex); return ex; } - internal JsonRpcException ProcessParseException(string req,JsonRpcException ex) + internal JsonRpcException ProcessParseException(string req, JsonRpcException ex) { if (parseErrorHandler != null) return parseErrorHandler(req, ex); @@ -385,42 +427,95 @@ internal void SetParseErrorHandler(Func { [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "jsonrpc")] - public string JsonRpc { get { return "2.0"; } } + public string JsonRpc { get; set; } = "2.0"; [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "result")] public T Result { get; set; } diff --git a/Json-Rpc/JsonRpcProcessor.cs b/Json-Rpc/JsonRpcProcessor.cs index 16a24b9..5020e88 100644 --- a/Json-Rpc/JsonRpcProcessor.cs +++ b/Json-Rpc/JsonRpcProcessor.cs @@ -5,401 +5,176 @@ using System.Reflection; using System.IO; using System.Collections.Generic; +using System.Linq; using System.Text; +using Newtonsoft.Json; namespace AustinHarris.JsonRpc { public static class JsonRpcProcessor { - public static void Process(JsonRpcStateAsync async, object context = null) + public static void Process(JsonRpcStateAsync async, object context = null, + JsonSerializerSettings settings = null) { - var t = Task.Factory.StartNew((_async) => - { - var i = (Tuple)_async; - ProcessJsonRpcState(i.Item1,i.Item2); - }, new Tuple(async,context)); - + Process(Handler.DefaultSessionId(), async, context, settings); } - public static void Process(string sessionId, JsonRpcStateAsync async, object context = null) + public static void Process(string sessionId, JsonRpcStateAsync async, object context = null, + JsonSerializerSettings settings = null) { - var t = Task.Factory.StartNew((_async) => - { - var i = (Tuple)_async; - ProcessJsonRpcState(i.Item1, i.Item2, i.Item3); - }, new Tuple(sessionId, async, context)); - + Process(sessionId, async.JsonRpc, context, settings) + .ContinueWith(t => + { + async.Result = t.Result; + async.SetCompleted(); + }); } - internal static void ProcessJsonRpcState(JsonRpcStateAsync async, object jsonRpcContext = null) + + public static Task Process(string jsonRpc, object context = null, + JsonSerializerSettings settings = null) { - ProcessJsonRpcState(Handler.DefaultSessionId(), async, jsonRpcContext); + return Process(Handler.DefaultSessionId(), jsonRpc, context, settings); } - internal static void ProcessJsonRpcState(string sessionId, JsonRpcStateAsync async, object jsonRpcContext = null) - { - var context = async.AsyncState; - JsonRequest[] rpcBatch = null; - JsonResponse[] responseBatch = null; + public static Task Process(string sessionId, string jsonRpc, object context = null, + JsonSerializerSettings settings = null) + { + return Task.Factory.StartNew((_) => + { + var tuple = (Tuple)_; + return ProcessSync(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4); + }, new Tuple(sessionId, jsonRpc, context, settings)); + } - JsonRequest rpc = null; + public static string ProcessSync(string sessionId, string jsonRpc, object jsonRpcContext, + JsonSerializerSettings settings = null) + { var handler = Handler.GetSessionHandler(sessionId); - var callback = string.Empty; - - var response = new JsonResponse(); - response.Result = null; - response.Error = null; - string json = async.JsonRpc; - - if (isSingleRpc(json)) + JsonRequest[] batch = null; + try + { + if (isSingleRpc(jsonRpc)) { - try - { - if (json.Length > 0) - { - rpc = Newtonsoft.Json.JsonConvert.DeserializeObject(json); - if (rpc == null) - { - response.Result = null; - response.Id = null; - response.Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.")); - } - else - { - response.Id = rpc.Id; - if (rpc.Method == null) - { - response.Result = null; - response.Id = rpc.Id; - response.Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'")); - } - } - } - else - { - response.Result = null; - response.Id = null; - response.Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "The JSON sent is not a valid Request object.")); - } - } - catch (Exception ex) - { - response.Result = null; - if (rpc != null) response.Id = rpc.Id; - response.Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", ex)); - var result = Newtonsoft.Json.JsonConvert.SerializeObject(response); - async.Result = result; - async.SetCompleted(); - return; - } - - if (response.Error == null - && rpc != null - && rpc.Method != null) - { - var data = Handler.GetSessionHandler(sessionId).Handle(rpc, jsonRpcContext); - if (data != null) - { - response.Error = data.Error; - response.Result = data.Result; - var result = ""; - if (response.Id != null)// dont return a result for notifications - { - result=Newtonsoft.Json.JsonConvert.SerializeObject(response); - } - async.Result = result; - async.SetCompleted(); - return; - } - } - - var err = Newtonsoft.Json.JsonConvert.SerializeObject(response); - - async.Result = err; - async.SetCompleted(); + var foo = JsonConvert.DeserializeObject(jsonRpc, settings); + batch = new[] { foo }; } - else // this is a batch of requests + else { - try - { - rpcBatch = Newtonsoft.Json.JsonConvert.DeserializeObject(json); - responseBatch = new JsonResponse[rpcBatch.Length]; - - for (int i = 0; i < rpcBatch.Length; i++) - { - responseBatch[i] = new JsonResponse(); - if (rpcBatch[i] == null) - { - responseBatch[i].Result = null; - responseBatch[i].Id = null; - responseBatch[i].Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.")); - } - else - { - responseBatch[i].Id = rpcBatch[i].Id; - if (rpcBatch[i].Method == null) - { - responseBatch[i].Result = null; - responseBatch[i].Error =handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'")); - } - } - } - } - catch (Exception ex) - { - response.Result = null; - if (rpc != null) response.Id = rpc.Id; - response.Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", ex)); - var result = Newtonsoft.Json.JsonConvert.SerializeObject(response); - async.Result = result; - async.SetCompleted(); - return; - } - - // we should have a batch of RPC at this point - var respBuilder = new StringBuilder(); - for (int i = 0; i < rpcBatch.Length; i++) - { - if (i == 0) - { - respBuilder.Append("["); - } - - if (rpcBatch[i] == null || rpcBatch[i].Method == null) - { - responseBatch[i].Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'")); - } - else if (responseBatch[i].Error == null) - { - var data = handler.Handle(rpcBatch[i], jsonRpcContext); - if (data != null) - { - responseBatch[i].Error = data.Error; - responseBatch[i].Result = data.Result; - - } - } - // dont return a response for notifications. - if (responseBatch[i].Id != null || responseBatch[i].Error != null) - { - var result = Newtonsoft.Json.JsonConvert.SerializeObject(responseBatch[i]); - respBuilder.Append(result); - if (i != rpcBatch.Length - 1) - { - respBuilder.Append(','); - } - } - - if (i == rpcBatch.Length - 1) - { - respBuilder.Append("]"); - var str = respBuilder.ToString(); - async.Result = str; - async.SetCompleted(); // let IIS think we are completed now. - return; - } - } - - // if we made it this far, then there were no items in the array - response.Id = null; - response.Result = null; - response.Error = handler.ProcessParseException(json, new JsonRpcException(3200, "Invalid Request", "Batch of calls was empty.")); - - var err = Newtonsoft.Json.JsonConvert.SerializeObject(response); - - async.Result = err; - async.SetCompleted(); - } - } - - public static Task Process(string jsonRpc, object context = null) - { - return Process(Handler.DefaultSessionId(), jsonRpc, context); - } - public static Task Process(string sessionId, string jsonRpc, object context = null) - { - var task = Task.Factory.StartNew((_) => + batch = JsonConvert.DeserializeObject(jsonRpc, settings); + } + } + catch (Exception ex) { - // use invariant culture - we have to set it explicitly for every thread we create to - // prevent any floating-point problems (mostly because of number formats in non en-US cultures). - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - - var tup = (Tuple)_; - string _sessionId; - string _jsonRpc; - object _jsonRpcContext = null; - _sessionId = tup.Item1; - _jsonRpc = tup.Item2; - _jsonRpcContext = tup.Item3; - var handler = Handler.GetSessionHandler(_sessionId); - + return Newtonsoft.Json.JsonConvert.SerializeObject(new JsonResponse + { + Error = handler.ProcessParseException(jsonRpc, new JsonRpcException(-32700, "Parse error", ex)) + }, settings); + } - JsonRequest[] rpcBatch = null; - JsonResponse[] responseBatch = null; + if (batch.Length == 0) + { + return Newtonsoft.Json.JsonConvert.SerializeObject(new JsonResponse + { + Error = handler.ProcessParseException(jsonRpc, + new JsonRpcException(3200, "Invalid Request", "Batch of calls was empty.")) + }, settings); + } - JsonRequest rpc = null; + var singleBatch = batch.Length == 1; + StringBuilder sbResult = null; + for (var i = 0; i < batch.Length; i++) + { + var jsonRequest = batch[i]; + var jsonResponse = new JsonResponse(); - var callback = string.Empty; + if (jsonRequest == null) + { + jsonResponse.Error = handler.ProcessParseException(jsonRpc, + new JsonRpcException(-32700, "Parse error", + "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.")); + } + else if (jsonRequest.Method == null) + { + jsonResponse.Error = handler.ProcessParseException(jsonRpc, + new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'")); + } + else if (!isSimpleValueType(jsonRequest.Id)) + { + jsonResponse.Error = handler.ProcessParseException(jsonRpc, + new JsonRpcException(-32600, "Invalid Request", "Id property must be either null or string or integer.")); + } + else + { + jsonResponse.Id = jsonRequest.Id; - var response = new JsonResponse(); + var data = handler.Handle(jsonRequest, jsonRpcContext); - response.Result = null; - response.Error = null; + if (data == null) continue; - string json = _jsonRpc; + jsonResponse.JsonRpc = data.JsonRpc; + jsonResponse.Error = data.Error; + jsonResponse.Result = data.Result; - if (isSingleRpc(json)) + } + if (jsonResponse.Result == null && jsonResponse.Error == null) { - try + // Per json rpc 2.0 spec + // result : This member is REQUIRED on success. + // This member MUST NOT exist if there was an error invoking the method. + // Either the result member or error member MUST be included, but both members MUST NOT be included. + jsonResponse.Result = new Newtonsoft.Json.Linq.JValue((Object)null); + } + // special case optimization for single Item batch + if (singleBatch && (jsonResponse.Id != null || jsonResponse.Error != null)) + { + StringWriter sw = new StringWriter(); + JsonTextWriter writer = new JsonTextWriter(sw); + writer.WriteStartObject(); + if (!string.IsNullOrEmpty(jsonResponse.JsonRpc)) { - if (json.Length > 0) - { - rpc = Newtonsoft.Json.JsonConvert.DeserializeObject(json); - if (rpc == null) - { - response.Result = null; - response.Id = null; - response.Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.")); - } - else - { - response.Id = rpc.Id; - if (rpc.Method == null) - { - response.Result = null; - response.Id = rpc.Id; - response.Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'")); - } - } - } - else - { - response.Result = null; - response.Id = null; - response.Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "The JSON sent is not a valid Request object.")); - } + writer.WritePropertyName("jsonrpc"); writer.WriteValue(jsonResponse.JsonRpc); } - catch (Exception ex) + if (jsonResponse.Error != null) { - response.Result = null; - if (rpc != null) response.Id = rpc.Id; - response.Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", ex)); - var result = Newtonsoft.Json.JsonConvert.SerializeObject(response); - return result; + writer.WritePropertyName("error"); writer.WriteRawValue(JsonConvert.SerializeObject(jsonResponse.Error, settings)); } - - if (response.Error == null - && rpc != null - && rpc.Method != null) + else { - var data = handler.Handle(rpc, _jsonRpcContext); - if (data != null) - { - response.Error = data.Error; - response.Result = data.Result; - var result = ""; - if (response.Id != null)// dont return a result for notifications - { - result = Newtonsoft.Json.JsonConvert.SerializeObject(response); - } - return result; - } + writer.WritePropertyName("result"); writer.WriteRawValue(JsonConvert.SerializeObject(jsonResponse.Result, settings)); } + writer.WritePropertyName("id"); writer.WriteValue(jsonResponse.Id); + writer.WriteEndObject(); + return sw.ToString(); - var err = Newtonsoft.Json.JsonConvert.SerializeObject(response); - - return err; + //return JsonConvert.SerializeObject(jsonResponse); + } + else if (jsonResponse.Id == null && jsonResponse.Error == null) + { + // do nothing + sbResult = new StringBuilder(0); } - else // this is a batch of requests + else { - try + // write out the response + if (i == 0) { - rpcBatch = Newtonsoft.Json.JsonConvert.DeserializeObject(json); - responseBatch = new JsonResponse[rpcBatch.Length]; - - for (int i = 0; i < rpcBatch.Length; i++) - { - responseBatch[i] = new JsonResponse(); - if (rpcBatch[i] == null) - { - responseBatch[i].Result = null; - responseBatch[i].Id = null; - responseBatch[i].Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.")); - } - else - { - responseBatch[i].Id = rpcBatch[i].Id; - if (rpcBatch[i].Method == null) - { - responseBatch[i].Result = null; - responseBatch[i].Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'")); - } - } - } + sbResult = new StringBuilder("["); } - catch (Exception ex) + + sbResult.Append(JsonConvert.SerializeObject(jsonResponse, settings)); + if (i < batch.Length - 1) { - response.Result = null; - if (rpc != null) response.Id = rpc.Id; - response.Error = handler.ProcessParseException(json, new JsonRpcException(-32700, "Parse error", ex)); - var result = Newtonsoft.Json.JsonConvert.SerializeObject(response); - return result; + sbResult.Append(','); } - - // we should have a batch of RPC at this point - var respBuilder = new StringBuilder(); - for (int i = 0; i < rpcBatch.Length; i++) + else if (i == batch.Length - 1) { - if (i == 0) - { - respBuilder.Append("["); - } - - if (rpcBatch[i] == null || rpcBatch[i].Method == null) - { - responseBatch[i].Error = handler.ProcessParseException(json, new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'")); - } - else if (responseBatch[i].Error == null) - { - var data = Handler.GetSessionHandler(_sessionId).Handle(rpcBatch[i], _jsonRpcContext); - if (data != null) - { - responseBatch[i].Error = data.Error; - responseBatch[i].Result = data.Result; - - } - } - // dont return a response for notifications. - if (responseBatch[i].Id != null || responseBatch[i].Error != null) - { - var result = Newtonsoft.Json.JsonConvert.SerializeObject(responseBatch[i]); - respBuilder.Append(result); - if (i != rpcBatch.Length - 1) - { - respBuilder.Append(','); - } - } - - if (i == rpcBatch.Length - 1) - { - respBuilder.Append("]"); - var str = respBuilder.ToString(); - return str; - } + sbResult.Append(']'); } - - // if we made it this far, then there were no items in the array - response.Id = null; - response.Result = null; - response.Error = handler.ProcessParseException(json, new JsonRpcException(3200, "Invalid Request", "Batch of calls was empty.")); - - var err = Newtonsoft.Json.JsonConvert.SerializeObject(response); - - return err; } - }, new Tuple(sessionId, jsonRpc, context)); - return task; + } + return sbResult.ToString(); } private static bool isSingleRpc(string json) @@ -411,5 +186,15 @@ private static bool isSingleRpc(string json) } return true; } + + private static bool isSimpleValueType(object property) + { + if (property == null) + return true; + return property.GetType() == typeof(System.String) || + property.GetType() == typeof(System.Int64) || + property.GetType() == typeof(System.Int32) || + property.GetType() == typeof(System.Int16); + } } } diff --git a/Json-Rpc/JsonRpcService.cs b/Json-Rpc/JsonRpcService.cs index c5a3569..d8ec961 100644 --- a/Json-Rpc/JsonRpcService.cs +++ b/Json-Rpc/JsonRpcService.cs @@ -1,65 +1,22 @@ namespace AustinHarris.JsonRpc { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - using AustinHarris.JsonRpc; - + /// + /// For routing use SessionId + /// public abstract class JsonRpcService { protected JsonRpcService() { - buildService(Handler.DefaultSessionId()); + ServiceBinder.BindService(Handler.DefaultSessionId(), this); } + /// + /// Routing by SessionId + /// + /// protected JsonRpcService(string sessionID) { - buildService(sessionID); - } - - private void buildService(string sessionID) - { - // get the registerMethod. - // Method that matches Func - var regMethod = typeof(Handler).GetMethod("Register"); - - // var assem = Assembly.GetExecutingAssembly(); - // var TypesWithHandlers = assem.GetTypes().Where(f => f.GetCustomAttributes(typeof(JsonRpcAttribute), false).Length > 0); - var item = this.GetType(); - - var methods = item.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(m => m.GetCustomAttributes(typeof(JsonRpcMethodAttribute), false).Length > 0); - foreach (var meth in methods) - { - Dictionary paras = new Dictionary(); - Dictionary defaultValues = new Dictionary(); // dictionary that holds default values for optional params. - - var paramzs = meth.GetParameters(); - - List parameterTypeArray = new List(); - for (int i = 0; i < paramzs.Length; i++) - { - // reflection attribute information for optional parameters - //http://stackoverflow.com/questions/2421994/invoking-methods-with-optional-parameters-through-reflection - paras.Add(paramzs[i].Name, paramzs[i].ParameterType); - - if (paramzs[i].IsOptional) // if the parameter is an optional, add the default value to our default values dictionary. - defaultValues.Add(paramzs[i].Name, paramzs[i].DefaultValue); - } - - var resType = meth.ReturnType; - paras.Add("returns", resType); // add the return type to the generic parameters list. - - var atdata = meth.GetCustomAttributes(typeof(JsonRpcMethodAttribute), false); - foreach (JsonRpcMethodAttribute handlerAttribute in atdata) - { - var methodName = handlerAttribute.JsonMethodName == string.Empty ? meth.Name : handlerAttribute.JsonMethodName; - var newDel = Delegate.CreateDelegate(System.Linq.Expressions.Expression.GetDelegateType(paras.Values.ToArray()), this /*Need to add support for other methods outside of this instance*/, meth); - var handlerSession = Handler.GetSessionHandler(sessionID); - regMethod.Invoke(handlerSession, new object[] { methodName, newDel }); - handlerSession.MetaData.AddService(methodName, paras, defaultValues); - } - } + ServiceBinder.BindService(sessionID, this); } } -} +} \ No newline at end of file diff --git a/Json-Rpc/Properties/AssemblyInfo.cs b/Json-Rpc/Properties/AssemblyInfo.cs deleted file mode 100644 index 802d0fd..0000000 --- a/Json-Rpc/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Json-Rpc.Net Core")] -[assembly: AssemblyDescription("Core functionality for JsonRpc.Net")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Austin Harris")] -[assembly: AssemblyProduct("Json-Rpc.Net Core")] -[assembly: AssemblyCopyright("Austin Harris")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("2f8036b2-223d-4b90-b6a9-fadddeb3ac0d")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("1.0.5.0")] -[assembly: AssemblyFileVersion("1.0.5.0")] diff --git a/Json-Rpc/SMDService.cs b/Json-Rpc/SMDService.cs index 0487a36..fe84bb5 100644 --- a/Json-Rpc/SMDService.cs +++ b/Json-Rpc/SMDService.cs @@ -34,31 +34,37 @@ public SMD () TypeHashes = new List(); } - public void AddService(string method, Dictionary parameters, Dictionary defaultValues) + internal void AddService(string method, Dictionary parameters, Dictionary defaultValues, Delegate dele) { - var newService = new SMDService(transport,"JSON-RPC-2.0",parameters, defaultValues); + var newService = new SMDService(transport,"JSON-RPC-2.0",parameters, defaultValues, dele); Services.Add(method,newService); } public static int AddType(JObject jo) { - var hash = "t_" + jo.ToString().GetHashCode(); + var hash = string.Format("t_{0}", jo.ToString().GetHashCode()); + lock (TypeHashes) - { - var idx = 0; - if (TypeHashes.Contains(hash) == false) - { - TypeHashes.Add(hash); - idx = TypeHashes.IndexOf(hash); - Types.Add(idx, jo); - } + { + if (TypeHashes.Contains(hash)) return TypeHashes.IndexOf(hash); + + TypeHashes.Add(hash); + var idx = TypeHashes.IndexOf(hash); + Types.Add(idx, jo); } + return TypeHashes.IndexOf(hash); } + + public static bool ContainsType(JObject jo) + { + return TypeHashes.Contains(string.Format("t_{0}", jo.ToString().GetHashCode())); + } } public class SMDService { + public Delegate dele; /// /// Defines a service method http://dojotoolkit.org/reference-guide/1.8/dojox/rpc/smd.html /// @@ -66,9 +72,10 @@ public class SMDService /// URL, PATH, JSON, JSON-RPC-1.0, JSON-RPC-1.1, JSON-RPC-2.0 /// /// - public SMDService(string transport, string envelope, Dictionary parameters, Dictionary defaultValues ) + public SMDService(string transport, string envelope, Dictionary parameters, Dictionary defaultValues, Delegate dele) { // TODO: Complete member initialization + this.dele = dele; this.transport = transport; this.envelope = envelope; this.parameters = new SMDAdditionalParameters[parameters.Count-1]; // last param is return type similar to Func<,> @@ -163,11 +170,14 @@ internal static int GetTypeRecursive(Type t) { JObject jo = new JObject(); jo.Add("__name", t.Name.ToLower()); - if (isSimpleType(t)) + + if (isSimpleType(t) || SMD.ContainsType(jo)) { return SMD.AddType(jo); } + var retVal = SMD.AddType(jo); + var genArgs = t.GetGenericArguments(); PropertyInfo[] properties = t.GetProperties(); FieldInfo[] fields = t.GetFields(); @@ -225,7 +235,7 @@ internal static int GetTypeRecursive(Type t) } } - return SMD.AddType(jo); + return retVal; } internal static bool isSimpleType(Type t) diff --git a/Json-Rpc/ServiceBinder.cs b/Json-Rpc/ServiceBinder.cs new file mode 100644 index 0000000..20423a6 --- /dev/null +++ b/Json-Rpc/ServiceBinder.cs @@ -0,0 +1,71 @@ +namespace AustinHarris.JsonRpc +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using AustinHarris.JsonRpc; + + public static class ServiceBinder + { + public static void BindService() where T : new() + { + BindService(Handler.DefaultSessionId()); + } + public static void BindService(string sessionID) where T : new() + { + BindService(sessionID, new T()); + } + + public static void BindService(string sessionID, Object instance) + { + var item = instance.GetType(); // var item = typeof(T); + + var methods = item.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(m => m.GetCustomAttributes(typeof(JsonRpcMethodAttribute), false).Length > 0); + foreach (var meth in methods) + { + Dictionary paras = new Dictionary(); + Dictionary defaultValues = new Dictionary(); // dictionary that holds default values for optional params. + + var paramzs = meth.GetParameters(); + + List parameterTypeArray = new List(); + for (int i = 0; i < paramzs.Length; i++) + { + string paramName; + var paramAttrs = paramzs[i].GetCustomAttributes(typeof(JsonRpcParamAttribute), false); + if (paramAttrs.Length > 0) + { + paramName = ((JsonRpcParamAttribute)paramAttrs[0]).JsonParamName; + if (string.IsNullOrEmpty(paramName)) + { + paramName = paramzs[i].Name; + } + } + else + { + paramName = paramzs[i].Name; + } + // reflection attribute information for optional parameters + //http://stackoverflow.com/questions/2421994/invoking-methods-with-optional-parameters-through-reflection + paras.Add(paramName, paramzs[i].ParameterType); + + if (paramzs[i].IsOptional) // if the parameter is an optional, add the default value to our default values dictionary. + defaultValues.Add(paramName, paramzs[i].DefaultValue); + } + + var resType = meth.ReturnType; + paras.Add("returns", resType); // add the return type to the generic parameters list. + + var atdata = meth.GetCustomAttributes(typeof(JsonRpcMethodAttribute), false); + foreach (JsonRpcMethodAttribute handlerAttribute in atdata) + { + var methodName = handlerAttribute.JsonMethodName == string.Empty ? meth.Name : handlerAttribute.JsonMethodName; + var newDel = Delegate.CreateDelegate(System.Linq.Expressions.Expression.GetDelegateType(paras.Values.ToArray()), instance /*Need to add support for other methods outside of this instance*/, meth); + var handlerSession = Handler.GetSessionHandler(sessionID); + handlerSession.MetaData.AddService(methodName, paras, defaultValues, newDel); + } + } + } + } +} \ No newline at end of file diff --git a/Json-Rpc/packages.config b/Json-Rpc/packages.config deleted file mode 100644 index 12fef57..0000000 --- a/Json-Rpc/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/README.md b/README.md index 629457b..7847e23 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,37 @@ + ![Screenshot](http://i.imgur.com/rxHaXLb.png) json-rpc.net ============ +![Build Master](https://github.com/Astn/JSON-RPC.NET/workflows/Build%20Master/badge.svg) ![NuGet Badge](https://buildstats.info/nuget/AustinHarris.JsonRpc) JSON-RPC.Net is a high performance Json-Rpc 2.0 server, leveraging the popular JSON.NET library. Host in ASP.NET, also supports sockets and pipes, oh my! +## Performance + +These are results from running the TestServer_Console project. + +##### Xeon E-2176M @ 2.70GHz 64.0 GB (Date: Thu Apr 30 17:34:22 2020 -0600) + +``` +Starting benchmark +processed 50 rpc in 137ms for 364.96 rpc/sec +processed 100 rpc in 0ms for ∞ rpc/sec +processed 300 rpc in 1ms for 300,000.00 rpc/sec +processed 1,200 rpc in 7ms for 171,428.57 rpc/sec +processed 6,000 rpc in 26ms for 230,769.23 rpc/sec +processed 36,000 rpc in 166ms for 216,867.47 rpc/sec +processed 252,000 rpc in 1,121ms for 224,799.29 rpc/sec +Finished benchmark... +``` + +## Do you like this? + +[![https://www.buymeacoffee.com/Ekati](https://cdn.buymeacoffee.com/buttons/default-blue.png)](https://www.buymeacoffee.com/Ekati) + + ##### Requirements -* dotnet 4.0 or mono +* dotnet-standard (dotnet core | mono | .net framework) ##### License JSON-RPC.net is licensed under The MIT License (MIT), check the [LICENSE](https://github.com/CoiniumServ/JSON-RPC.NET/blob/master/LICENSE) file for details. @@ -24,12 +49,13 @@ PM> Install-Package AustinHarris.JsonRpc To install JSON-RPC.NET AspNet, run the following command in the Package Manager Console ``` -PM> Install-Package AustinHarris.AspNet +PM> Install-Package AustinHarris.JsonRpc.AspNet ``` -##### Performance -Under ideal conditions > 120k rpc/sec (cpu i7-2600,console server, no IO bottleneck) + + + ##### Getting Started & Documentation diff --git a/TestServer_Console/Program.cs b/TestServer_Console/Program.cs index 8460d12..df3152f 100644 --- a/TestServer_Console/Program.cs +++ b/TestServer_Console/Program.cs @@ -5,6 +5,7 @@ using AustinHarris.JsonRpc; using System.Threading; using System.Diagnostics; +using System.Threading.Tasks; namespace TestServer_Console { @@ -16,36 +17,29 @@ class Program static void Main(string[] args) { - string input = ""; - do + PrintOptions(); + for (string line = Console.ReadLine(); line != "q"; line = Console.ReadLine()) { - input = PrintOptions(); - if (string.IsNullOrWhiteSpace(input)) + if (string.IsNullOrWhiteSpace(line)) Benchmark(); - else if (input.StartsWith("C", StringComparison.CurrentCultureIgnoreCase)) + else if (line.StartsWith("c", StringComparison.CurrentCultureIgnoreCase)) ConsoleInput(); - else - PrintOptions(); - } while (input != "x"); + PrintOptions(); + } } - private static string PrintOptions() + private static void PrintOptions() { Console.WriteLine("Hit Enter to run benchmark"); Console.WriteLine("'c' to start reading console input"); - Console.WriteLine("'x' to exit"); - return Console.ReadLine(); + Console.WriteLine("'q' to quit"); } private static void ConsoleInput() { - var rpcResultHandler = new AsyncCallback(_ => Console.WriteLine(((JsonRpcStateAsync)_).Result)); - for (string line = Console.ReadLine(); !string.IsNullOrEmpty(line); line = Console.ReadLine()) { - var async = new JsonRpcStateAsync(rpcResultHandler, null); - async.JsonRpc = line; - JsonRpcProcessor.Process(async); + JsonRpcProcessor.Process(line).ContinueWith(response => Console.WriteLine( response.Result )); } } @@ -60,25 +54,21 @@ private static void Benchmark() { cnt *= iteration; ctr = 0; + Task[] tasks = new Task[cnt]; var sw = Stopwatch.StartNew(); - AutoResetEvent are = new AutoResetEvent(false); - var rpcResultHandler = new AsyncCallback(_ => - { - if(Interlocked.Increment(ref ctr) == cnt) - { - sw.Stop(); - Console.WriteLine("processed {0} rpc in {1}ms for {2} rpc/sec",cnt,sw.ElapsedMilliseconds, (double)cnt * 1000d / sw.ElapsedMilliseconds); - are.Set(); - } - }); - for (int i = 0; i < cnt; i++) + var sessionid = Handler.DefaultSessionId(); + for (int i = 0; i < cnt; i+=5) { - var async = new JsonRpcStateAsync(rpcResultHandler, null); - async.JsonRpc = "{'method':'add','params':[1,2],'id':1}"; - JsonRpcProcessor.Process(async); + tasks[i] = JsonRpcProcessor.Process(sessionid, "{'method':'add','params':[1,2],'id':1}"); + tasks[i+1] = JsonRpcProcessor.Process(sessionid, "{'method':'addInt','params':[1,7],'id':2}"); + tasks[i+2] = JsonRpcProcessor.Process(sessionid, "{'method':'NullableFloatToNullableFloat','params':[1.23],'id':3}"); + tasks[i+3] = JsonRpcProcessor.Process(sessionid, "{'method':'Test2','params':[3.456],'id':4}"); + tasks[i+4] = JsonRpcProcessor.Process(sessionid, "{'method':'StringMe','params':['Foo'],'id':5}"); } - are.WaitOne(); + Task.WaitAll(tasks); + sw.Stop(); + Console.WriteLine("processed {0:N0} rpc in \t {1:N0}ms for \t {2:N} rpc/sec", cnt, sw.ElapsedMilliseconds, (double)cnt * 1000d / sw.ElapsedMilliseconds); } diff --git a/TestServer_Console/Properties/AssemblyInfo.cs b/TestServer_Console/Properties/AssemblyInfo.cs deleted file mode 100644 index fdd1edf..0000000 --- a/TestServer_Console/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("TestServer_Console")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("TestServer_Console")] -[assembly: AssemblyCopyright("Copyright © 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("5e7696bc-52cc-48f8-a575-40b17165ee20")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/TestServer_Console/TestServer_Console.csproj b/TestServer_Console/TestServer_Console.csproj index 91ea00d..ba5f427 100644 --- a/TestServer_Console/TestServer_Console.csproj +++ b/TestServer_Console/TestServer_Console.csproj @@ -1,83 +1,24 @@ - - - - Debug - x86 - 8.0.30703 - 2.0 - {31AE59FC-B6F6-4AC7-A7B9-1E07630AE42B} - Exe - Properties - TestServer_Console - TestServer_Console - v4.0 - Client - 512 - SAK - SAK - SAK - SAK - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - x86 - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - AnyCPU - bin\Debug\ - - - AnyCPU - bin\Release\ - - - - False - ..\packages\Newtonsoft.Json.6.0.3\lib\net40\Newtonsoft.Json.dll - - - - - - - - - - - - - - - - - {24FC1A2A-0BC3-43A7-9BFE-B628C2C4A307} - AustinHarris.JsonRpc - - - - - - - + + + + Austin Harris + Exe + netcoreapp3.1 + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TestServer_Console/packages.config b/TestServer_Console/packages.config deleted file mode 100644 index 7106c62..0000000 --- a/TestServer_Console/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/TestServer_Console/service.cs b/TestServer_Console/service.cs index c0a09aa..6fc2602 100644 --- a/TestServer_Console/service.cs +++ b/TestServer_Console/service.cs @@ -14,6 +14,12 @@ private double add(double l, double r) return l + r; } + [JsonRpcMethod] + private int addInt(int l, int r) + { + return l + r; + } + [JsonRpcMethod] public float? NullableFloatToNullableFloat(float? a) { @@ -25,5 +31,101 @@ private double add(double l, double r) { return x; } + + [JsonRpcMethod] + public string StringMe(string x) + { + return x; + } + + [JsonRpcMethod] + private double add_1(double l, double r) + { + return l + r; + } + + [JsonRpcMethod] + private int addInt_1(int l, int r) + { + return l + r; + } + + [JsonRpcMethod] + public float? NullableFloatToNullableFloat_1(float? a) + { + return a; + } + + [JsonRpcMethod] + public decimal? Test2_1(decimal x) + { + return x; + } + + [JsonRpcMethod] + public string StringMe_1(string x) + { + return x; + } + + [JsonRpcMethod] + private double add_2(double l, double r) + { + return l + r; + } + + [JsonRpcMethod] + private int addInt_2(int l, int r) + { + return l + r; + } + + [JsonRpcMethod] + public float? NullableFloatToNullableFloat_2(float? a) + { + return a; + } + + [JsonRpcMethod] + public decimal? Test2_2(decimal x) + { + return x; + } + + [JsonRpcMethod] + public string StringMe_2(string x) + { + return x; + } + + [JsonRpcMethod] + private double add_3(double l, double r) + { + return l + r; + } + + [JsonRpcMethod] + private int addInt_3(int l, int r) + { + return l + r; + } + + [JsonRpcMethod] + public float? NullableFloatToNullableFloat_3(float? a) + { + return a; + } + + [JsonRpcMethod] + public decimal? Test2_3(decimal x) + { + return x; + } + + [JsonRpcMethod] + public string StringMe_3(string x) + { + return x; + } } }