From 1f99f7e2f2576af9261ef5eb1f04be19194c70af Mon Sep 17 00:00:00 2001 From: Austin Harris Date: Thu, 24 Sep 2026 21:24:33 -0600 Subject: [PATCH 1/6] Publish to nuget.org with Trusted Publishing instead of a stored API key The master workflow now requests an OIDC token, exchanges it through NuGet/login for a one-hour API key, and pushes with that. The NugetKey secret is no longer read. The nuget.org policy is bound to this repository and to the workflow file name, so the file keeps its name. --- .github/workflows/build_publish_master.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_publish_master.yml b/.github/workflows/build_publish_master.yml index 5c6cebf..cb59a9f 100644 --- a/.github/workflows/build_publish_master.yml +++ b/.github/workflows/build_publish_master.yml @@ -5,6 +5,14 @@ on: - "**/*.md" branches: [ master ] +# Publishing uses nuget.org Trusted Publishing: the job requests an OIDC token from GitHub, NuGet/login exchanges +# it for an API key that lives one hour, and the push uses that key. No long-lived NuGet secret is stored here. +# The nuget.org policy is bound to this repository and to this file's name (build_publish_master.yml); renaming +# the file or moving the push to another workflow needs a new policy on nuget.org. +permissions: + id-token: write + contents: read + jobs: build: @@ -28,9 +36,16 @@ jobs: run: dotnet build AustinHarris.JsonRpc.sln --configuration Release --no-restore - name: Test run: dotnet test AustinHarris.JsonRpcTestN --configuration Release --no-build + # The key is requested after the tests so it is fresh for the push (it expires after one hour). `user` is the + # nuget.org profile that owns the packages and the trusted publishing policy. + - name: NuGet login (OIDC to a temporary API key) + uses: NuGet/login@v1 + id: nuget-login + with: + user: AustinHarris # Publish all four packages: the core and the three companions (Json.NET, System.Text.Json, ASP.NET Core). - name: publish nuget version change run: | for project in Json-Rpc AustinHarris.JsonRpc.Newtonsoft AustinHarris.JsonRpc.SystemTextJson AustinHarris.JsonRpc.AspNetCore; do - dotnet nuget push "$project/bin/Release/"*.nupkg --skip-duplicate --source "https://api.nuget.org/v3/index.json" --api-key ${{ secrets.NugetKey }} # API key for the NuGet feed + dotnet nuget push "$project/bin/Release/"*.nupkg --skip-duplicate --source "https://api.nuget.org/v3/index.json" --api-key "${{ steps.nuget-login.outputs.NUGET_API_KEY }}" done From 04c8fc4a7c78784a4c66f359e82b3414a1e0600e Mon Sep 17 00:00:00 2001 From: Austin Harris Date: Thu, 24 Sep 2026 21:26:05 -0600 Subject: [PATCH 2/6] 2.0 goes out as 2.0.0-preview.1; pull requests no longer push packages VersionSuffix preview.1 on the four packages (a --version-suffix on the command line still overrides it). The README says to install with --prerelease and what a preview promises; the changelog heading names the preview. The pull-request workflow's non-fatal push of ci-suffixed packages is gone: the trusted publishing policy is bound to the master workflow, so that push could only fail. --- .github/workflows/build_pull_request.yml | 14 +++----------- .../AustinHarris.JsonRpc.AspNetCore.csproj | 2 +- .../AustinHarris.JsonRpc.Newtonsoft.csproj | 2 +- .../AustinHarris.JsonRpc.SystemTextJson.csproj | 2 +- CHANGELOG.md | 2 +- Json-Rpc/AustinHarris.JsonRpc.csproj | 2 +- README.md | 5 ++++- 7 files changed, 12 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index e22a198..62975b2 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -29,16 +29,8 @@ jobs: # Building the solution packs every package project (GeneratePackageOnBuild); `dotnet pack` on the # solution would trip NU5026 with GeneratePackageOnBuild, so the packages come from the build. - name: Build - run: dotnet build AustinHarris.JsonRpc.sln --configuration Release --no-restore --version-suffix ci-${{ github.run_id }}-${{ github.run_number }} + run: dotnet build AustinHarris.JsonRpc.sln --configuration Release --no-restore - name: Test run: dotnet test AustinHarris.JsonRpcTestN --configuration Release --no-build - # Publish all four pre-release packages: the core and the three companions (Json.NET, System.Text.Json, ASP.NET Core). - # Non-fatal: the build and tests are the pull-request verdict; a rejected key (403) or a fork's missing secret - # shows as a warning here and fails loudly in the master workflow instead. - - name: publish nuget version change - if: ${{ matrix.os == 'ubuntu-latest' }} - continue-on-error: true - run: | - for project in Json-Rpc AustinHarris.JsonRpc.Newtonsoft AustinHarris.JsonRpc.SystemTextJson AustinHarris.JsonRpc.AspNetCore; do - dotnet nuget push "$project/bin/Release/"*.nupkg --skip-duplicate --source "https://api.nuget.org/v3/index.json" --api-key ${{ secrets.NugetKey }} # API key for the NuGet feed - done + # Pull requests do not publish. Packages go out from the master workflow through Trusted Publishing, whose + # nuget.org policy is bound to build_publish_master.yml; nothing else can push. diff --git a/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj b/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj index 0ca9106..c071ad6 100644 --- a/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj +++ b/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj @@ -6,8 +6,8 @@ Json-Rpc.Net ASP.NET Core host ASP.NET Core / Kestrel hosting for JSON-RPC.Net: MapJsonRpc endpoint (PipeReader in, BodyWriter out, no strings), a raw Kestrel ConnectionHandler for JSON-RPC over TCP, and DI registration of services. 2.0.0 + preview.1 https://github.com/Astn/JSON-RPC.NET/blob/master/CHANGELOG.md - $(VersionSuffix) Austin Harris https://github.com/Astn/JSON-RPC.NET https://github.com/Astn/JSON-RPC.NET diff --git a/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj b/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj index 3eacf84..9d88499 100644 --- a/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj +++ b/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj @@ -6,8 +6,8 @@ Json-Rpc.Net Json.NET serializer Json.NET (Newtonsoft.Json) serializer for JSON-RPC.Net. Lenient parsing and full Json.NET conversion semantics; pass JsonSerializerSettings to control it. 2.0.0 + preview.1 https://github.com/Astn/JSON-RPC.NET/blob/master/CHANGELOG.md - $(VersionSuffix) Austin Harris https://github.com/Astn/JSON-RPC.NET https://github.com/Astn/JSON-RPC.NET diff --git a/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj b/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj index 5035c86..b371d1d 100644 --- a/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj +++ b/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj @@ -6,8 +6,8 @@ Json-Rpc.Net System.Text.Json serializer System.Text.Json serializer for JSON-RPC.Net. Utf8JsonReader/Utf8JsonWriter end to end; pass JsonSerializerOptions to control it. 2.0.0 + preview.1 https://github.com/Astn/JSON-RPC.NET/blob/master/CHANGELOG.md - $(VersionSuffix) Austin Harris https://github.com/Astn/JSON-RPC.NET https://github.com/Astn/JSON-RPC.NET diff --git a/CHANGELOG.md b/CHANGELOG.md index d229ddb..fea6bfa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ move a 1.x server, and the package pages on NuGet link here. Versions follow [Semantic Versioning](https://semver.org/) for the public API and the documented wire behaviour: a breaking change to either means a new major version. -## 2.0.0 (unreleased) +## 2.0.0 (in preview: `2.0.0-preview.1`) ### Added diff --git a/Json-Rpc/AustinHarris.JsonRpc.csproj b/Json-Rpc/AustinHarris.JsonRpc.csproj index a6b3721..c0b68fc 100644 --- a/Json-Rpc/AustinHarris.JsonRpc.csproj +++ b/Json-Rpc/AustinHarris.JsonRpc.csproj @@ -6,7 +6,7 @@ Json-Rpc.Net Core JSON-RPC.Net is a high performance JSON-RPC 2.0 server for .NET Standard 2.0+ and modern .NET. Bytes in, bytes out, no JSON library dependency: the built-in serializer needs nothing, and Json.NET or System.Text.Json plug in through the companion packages. Host it in ASP.NET Core / Kestrel, a console app, sockets, pipes - anything that can hand you UTF-8 or a string. 2.0.0 - $(VersionSuffix) + preview.1 Austin Harris https://github.com/Astn/JSON-RPC.NET https://github.com/Astn/JSON-RPC.NET diff --git a/README.md b/README.md index da41d8f..093440a 100644 --- a/README.md +++ b/README.md @@ -60,9 +60,11 @@ The core uses no reflection emit, so it runs under the WebAssembly interpreter a ## Installation ``` -dotnet add package AustinHarris.JsonRpc +dotnet add package AustinHarris.JsonRpc --prerelease ``` +2.0 is published as `2.0.0-preview.1`; without `--prerelease`, NuGet resolves to the last 1.x release. + Add `AustinHarris.JsonRpc.Newtonsoft` or `AustinHarris.JsonRpc.SystemTextJson` if you want that serializer, and `AustinHarris.JsonRpc.AspNetCore` to host in Kestrel. ## Getting started @@ -652,6 +654,7 @@ Most 1.x services run unchanged. Read the first list before you build, and the s - **Versioning.** The 2.x packages follow [Semantic Versioning](https://semver.org/) for the public API and the wire behaviour documented here: a breaking change to either arrives only in a new major version. - **Releases.** The four packages are built from one repository, carry one version number and are released together; use matching versions. There is no release cadence. +- **Previews.** 2.0 ships as `2.0.0-preview.N` first. A preview is complete and tested, but the public API may still change between previews; the stable 2.0.0 follows once the API has settled. - **Tested** means the `net8.0` and `net10.0` test runs on Windows and Linux listed under [Requirements](#requirements). Other runtimes can load the `netstandard` assets and are not tested. - **Trimming** is unsupported until the library is annotated and that is validated in CI. - **1.x** receives no further releases. From 441b479f4711c3fda60be74d1f47c781e031b4fc Mon Sep 17 00:00:00 2001 From: Austin Harris Date: Thu, 24 Sep 2026 21:28:01 -0600 Subject: [PATCH 3/6] Package project URLs point at the documentation site The four packages' PackageProjectUrl is the published site (the package's own page for the three companions); RepositoryUrl stays on GitHub. --- .../AustinHarris.JsonRpc.AspNetCore.csproj | 2 +- .../AustinHarris.JsonRpc.Newtonsoft.csproj | 2 +- .../AustinHarris.JsonRpc.SystemTextJson.csproj | 2 +- Json-Rpc/AustinHarris.JsonRpc.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj b/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj index c071ad6..fab08ea 100644 --- a/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj +++ b/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj @@ -9,7 +9,7 @@ preview.1 https://github.com/Astn/JSON-RPC.NET/blob/master/CHANGELOG.md Austin Harris - https://github.com/Astn/JSON-RPC.NET + https://astn.github.io/JSON-RPC.NET/aspnetcore.html https://github.com/Astn/JSON-RPC.NET git MIT diff --git a/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj b/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj index 9d88499..36a3403 100644 --- a/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj +++ b/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj @@ -9,7 +9,7 @@ preview.1 https://github.com/Astn/JSON-RPC.NET/blob/master/CHANGELOG.md Austin Harris - https://github.com/Astn/JSON-RPC.NET + https://astn.github.io/JSON-RPC.NET/newtonsoft.html https://github.com/Astn/JSON-RPC.NET git MIT diff --git a/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj b/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj index b371d1d..1f21e6b 100644 --- a/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj +++ b/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj @@ -9,7 +9,7 @@ preview.1 https://github.com/Astn/JSON-RPC.NET/blob/master/CHANGELOG.md Austin Harris - https://github.com/Astn/JSON-RPC.NET + https://astn.github.io/JSON-RPC.NET/systemtextjson.html https://github.com/Astn/JSON-RPC.NET git MIT diff --git a/Json-Rpc/AustinHarris.JsonRpc.csproj b/Json-Rpc/AustinHarris.JsonRpc.csproj index c0b68fc..5ffb293 100644 --- a/Json-Rpc/AustinHarris.JsonRpc.csproj +++ b/Json-Rpc/AustinHarris.JsonRpc.csproj @@ -8,7 +8,7 @@ 2.0.0 preview.1 Austin Harris - https://github.com/Astn/JSON-RPC.NET + https://astn.github.io/JSON-RPC.NET/ https://github.com/Astn/JSON-RPC.NET git MIT From fc520ec98c7c0efb5d9962fdc21ca7101d96e8d7 Mon Sep 17 00:00:00 2001 From: Austin Harris Date: Thu, 24 Sep 2026 21:33:27 -0600 Subject: [PATCH 4/6] Remove the Windows Phone 7 client and its test app Windows Phone 7 is no longer supported; the two projects were outside the solution and nothing in 2.0 built from them. --- .../AustinHarris.JsonRpc.Client.WP7.csproj | 109 ------------- .../Properties/AssemblyInfo.cs | 35 ----- AustinHarris.JsonRpc.Client.WP7/client.cs | 148 ------------------ AustinHarris.JsonRpc.Client.WP7Test/App.xaml | 19 --- .../App.xaml.cs | 142 ----------------- .../ApplicationIcon.png | Bin 1881 -> 0 bytes ...AustinHarris.JsonRpc.Client.WP7Test.csproj | 147 ----------------- .../Background.png | Bin 3521 -> 0 bytes .../MainPage.xaml | 45 ------ .../MainPage.xaml.cs | 49 ------ .../Properties/AppManifest.xml | 6 - .../Properties/AssemblyInfo.cs | 35 ----- .../Properties/WMAppManifest.xml | 48 ------ .../SplashScreenImage.jpg | Bin 9417 -> 0 bytes README.md | 2 +- 15 files changed, 1 insertion(+), 784 deletions(-) delete mode 100644 AustinHarris.JsonRpc.Client.WP7/AustinHarris.JsonRpc.Client.WP7.csproj delete mode 100644 AustinHarris.JsonRpc.Client.WP7/Properties/AssemblyInfo.cs delete mode 100644 AustinHarris.JsonRpc.Client.WP7/client.cs delete mode 100644 AustinHarris.JsonRpc.Client.WP7Test/App.xaml delete mode 100644 AustinHarris.JsonRpc.Client.WP7Test/App.xaml.cs delete mode 100644 AustinHarris.JsonRpc.Client.WP7Test/ApplicationIcon.png delete mode 100644 AustinHarris.JsonRpc.Client.WP7Test/AustinHarris.JsonRpc.Client.WP7Test.csproj delete mode 100644 AustinHarris.JsonRpc.Client.WP7Test/Background.png delete mode 100644 AustinHarris.JsonRpc.Client.WP7Test/MainPage.xaml delete mode 100644 AustinHarris.JsonRpc.Client.WP7Test/MainPage.xaml.cs delete mode 100644 AustinHarris.JsonRpc.Client.WP7Test/Properties/AppManifest.xml delete mode 100644 AustinHarris.JsonRpc.Client.WP7Test/Properties/AssemblyInfo.cs delete mode 100644 AustinHarris.JsonRpc.Client.WP7Test/Properties/WMAppManifest.xml delete mode 100644 AustinHarris.JsonRpc.Client.WP7Test/SplashScreenImage.jpg diff --git a/AustinHarris.JsonRpc.Client.WP7/AustinHarris.JsonRpc.Client.WP7.csproj b/AustinHarris.JsonRpc.Client.WP7/AustinHarris.JsonRpc.Client.WP7.csproj deleted file mode 100644 index fee5804..0000000 --- a/AustinHarris.JsonRpc.Client.WP7/AustinHarris.JsonRpc.Client.WP7.csproj +++ /dev/null @@ -1,109 +0,0 @@ - - - - Debug - AnyCPU - 10.0.20506 - 2.0 - {BFF21670-9DEB-4E36-95F4-96FC9DC740A2} - {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - AustinHarris.JsonRpc.Client.WP7 - AustinHarris.JsonRpc.Client.WP7 - v8.0 - - - - - WindowsPhone - false - true - true - SAK - SAK - SAK - SAK - - - - - 4.0 - 11.0 - - - true - full - false - Bin\Debug - DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE - true - true - prompt - 4 - - - pdbonly - true - Bin\Release - TRACE;SILVERLIGHT;WINDOWS_PHONE - true - true - prompt - 4 - - - - Bin\x86\Debug - true - full - false - - - - Bin\x86\Release - pdbonly - true - - - - Bin\ARM\Debug - true - full - false - - - - Bin\ARM\Release - pdbonly - true - - - - ..\packages\Newtonsoft.Json.4.5.1\lib\sl4-windowsphone71\Newtonsoft.Json.dll - - - ..\packages\Rx-Main.1.0.11226\lib\SL3-WP\System.Reactive.dll - - - - - JsonRequest.cs - - - JsonResponse.cs - - - - - - - - - \ No newline at end of file diff --git a/AustinHarris.JsonRpc.Client.WP7/Properties/AssemblyInfo.cs b/AustinHarris.JsonRpc.Client.WP7/Properties/AssemblyInfo.cs deleted file mode 100644 index d3f69ab..0000000 --- a/AustinHarris.JsonRpc.Client.WP7/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +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.JsonRpc.Client.WP7")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("AustinHarris.JsonRpc.Client.WP7")] -[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("913c7d78-8983-4ebb-9a6b-fe5cb4001abf")] - -// 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 Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/AustinHarris.JsonRpc.Client.WP7/client.cs b/AustinHarris.JsonRpc.Client.WP7/client.cs deleted file mode 100644 index 108ea44..0000000 --- a/AustinHarris.JsonRpc.Client.WP7/client.cs +++ /dev/null @@ -1,148 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using Newtonsoft.Json.Linq; -using AustinHarris.JsonRpc; -using System.Linq; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using System.Reactive.Concurrency; - -namespace AustinHarris.JsonRpc -{ - public class JsonRpcClient - { - private static object idLock = new object(); - private static int id = 0; - public Uri ServiceEndpoint = null; - - public JsonRpcClient(Uri serviceEndpoint) - { - ServiceEndpoint = serviceEndpoint; - } - - private static Stream CopyAndClose(Stream inputStream) - { - const int readSize = 256; - byte[] buffer = new byte[readSize]; - MemoryStream ms = new MemoryStream(); - - int count = inputStream.Read(buffer, 0, readSize); - while (count > 0) - { - ms.Write(buffer, 0, count); - count = inputStream.Read(buffer, 0, readSize); - } - ms.Position = 0; - inputStream.Close(); - return ms; - } - - public IObservable> Invoke(string method, object arg, IScheduler scheduler) - { - var req = new AustinHarris.JsonRpc.JsonRequest() - { - Method = method, - Params = new object[] { arg } - }; - return Invoke(req, scheduler); - } - - public IObservable> Invoke(string method, object[] args, IScheduler scheduler) - { - var req = new AustinHarris.JsonRpc.JsonRequest() - { - Method = method, - Params = args - }; - return Invoke(req,scheduler); - } - - public IObservable> Invoke(JsonRequest jsonRpc, IScheduler scheduler) - { - var subj = new Subject>(); - - int myId; - lock (idLock) - { - myId = ++id; - } - jsonRpc.Id = myId.ToString(); - - WebRequest req = null; - try - { - req = HttpWebRequest.CreateHttp(new Uri(ServiceEndpoint + "?callid=" + myId.ToString())); - req.Method = "Post"; - req.ContentType = "application/json-rpc"; - } - catch (Exception ex) - { - return Observable.Throw>(ex); - } - - var ar = req.BeginGetRequestStream(new AsyncCallback((iar) => - { - HttpWebRequest request = null; - - try - { - request = (HttpWebRequest)iar.AsyncState; - var json = Newtonsoft.Json.JsonConvert.SerializeObject(jsonRpc); - var reqStream = req.EndGetRequestStream(iar); - using (var stream = new StreamWriter(reqStream)) - { - stream.Write(json); - stream.Flush(); - stream.Close(); - } - } - catch (Exception ex) - { - subj.OnError(ex); - } - - var rar = req.BeginGetResponse(new AsyncCallback((riar) => - { - JsonResponse rjson = null; - string sstream = ""; - try - { - var request1 = (HttpWebRequest)riar.AsyncState; - var resp = (HttpWebResponse)request1.EndGetResponse(riar); - var respStream = resp.GetResponseStream(); - using (var rstream = new StreamReader(CopyAndClose(respStream))) - { - sstream = rstream.ReadToEnd(); - } - - rjson = Newtonsoft.Json.JsonConvert.DeserializeObject>(sstream); - } - catch (Exception ex) - { - subj.OnError(ex); - return; - } - - try - { - if (rjson == null) - { - JObject jo = Newtonsoft.Json.JsonConvert.DeserializeObject(sstream) as JObject; - subj.OnError(new Exception(jo["Error"].ToString())); - return; - } - } - catch (Exception) - { } - - subj.OnNext(rjson); - subj.OnCompleted(); - }), request); - }), req); - - return subj; - } - } -} diff --git a/AustinHarris.JsonRpc.Client.WP7Test/App.xaml b/AustinHarris.JsonRpc.Client.WP7Test/App.xaml deleted file mode 100644 index 0eb20ff..0000000 --- a/AustinHarris.JsonRpc.Client.WP7Test/App.xaml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/AustinHarris.JsonRpc.Client.WP7Test/App.xaml.cs b/AustinHarris.JsonRpc.Client.WP7Test/App.xaml.cs deleted file mode 100644 index cf90a39..0000000 --- a/AustinHarris.JsonRpc.Client.WP7Test/App.xaml.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Navigation; -using System.Windows.Shapes; -using Microsoft.Phone.Controls; -using Microsoft.Phone.Shell; - -namespace AustinHarris.JsonRpc.Client.WP7Test -{ - public partial class App : Application - { - /// - /// Provides easy access to the root frame of the Phone Application. - /// - /// The root frame of the Phone Application. - public PhoneApplicationFrame RootFrame { get; private set; } - - /// - /// Constructor for the Application object. - /// - public App() - { - // Global handler for uncaught exceptions. - UnhandledException += Application_UnhandledException; - - // Standard Silverlight initialization - InitializeComponent(); - - // Phone-specific initialization - InitializePhoneApplication(); - - // Show graphics profiling information while debugging. - if (System.Diagnostics.Debugger.IsAttached) - { - // Display the current frame rate counters. - Application.Current.Host.Settings.EnableFrameRateCounter = true; - - // Show the areas of the app that are being redrawn in each frame. - //Application.Current.Host.Settings.EnableRedrawRegions = true; - - // Enable non-production analysis visualization mode, - // which shows areas of a page that are handed off to GPU with a colored overlay. - //Application.Current.Host.Settings.EnableCacheVisualization = true; - - // Disable the application idle detection by setting the UserIdleDetectionMode property of the - // application's PhoneApplicationService object to Disabled. - // Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run - // and consume battery power when the user is not using the phone. - PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled; - } - - } - - // Code to execute when the application is launching (eg, from Start) - // This code will not execute when the application is reactivated - private void Application_Launching(object sender, LaunchingEventArgs e) - { - } - - // Code to execute when the application is activated (brought to foreground) - // This code will not execute when the application is first launched - private void Application_Activated(object sender, ActivatedEventArgs e) - { - } - - // Code to execute when the application is deactivated (sent to background) - // This code will not execute when the application is closing - private void Application_Deactivated(object sender, DeactivatedEventArgs e) - { - } - - // Code to execute when the application is closing (eg, user hit Back) - // This code will not execute when the application is deactivated - private void Application_Closing(object sender, ClosingEventArgs e) - { - } - - // Code to execute if a navigation fails - private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e) - { - if (System.Diagnostics.Debugger.IsAttached) - { - // A navigation has failed; break into the debugger - System.Diagnostics.Debugger.Break(); - } - } - - // Code to execute on Unhandled Exceptions - private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) - { - if (System.Diagnostics.Debugger.IsAttached) - { - // An unhandled exception has occurred; break into the debugger - System.Diagnostics.Debugger.Break(); - } - } - - #region Phone application initialization - - // Avoid double-initialization - private bool phoneApplicationInitialized = false; - - // Do not add any additional code to this method - private void InitializePhoneApplication() - { - if (phoneApplicationInitialized) - return; - - // Create the frame but don't set it as RootVisual yet; this allows the splash - // screen to remain active until the application is ready to render. - RootFrame = new PhoneApplicationFrame(); - RootFrame.Navigated += CompleteInitializePhoneApplication; - - // Handle navigation failures - RootFrame.NavigationFailed += RootFrame_NavigationFailed; - - // Ensure we don't initialize again - phoneApplicationInitialized = true; - } - - // Do not add any additional code to this method - private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e) - { - // Set the root visual to allow the application to render - if (RootVisual != RootFrame) - RootVisual = RootFrame; - - // Remove this handler since it is no longer needed - RootFrame.Navigated -= CompleteInitializePhoneApplication; - } - - #endregion - } -} \ No newline at end of file diff --git a/AustinHarris.JsonRpc.Client.WP7Test/ApplicationIcon.png b/AustinHarris.JsonRpc.Client.WP7Test/ApplicationIcon.png deleted file mode 100644 index 5859393ca1056103ba35d225773352a9fa3ab754..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1881 zcmV-f2d4OmP)GXLPE9uD;d|3K9jFs0^O3no;*#kUHY6H}PH_^L3*aj} zl+rSw?L`W0p^tkju#a}u3PxyqFY3}?ZpgV`?z#P)?|kQbU67g4(Jt>MC@$|ToYbAv zoz$Jwoz$JwUyrEBh@^xBYY9T32$%4g4Eozd9YH8m>Im7iz@UwrH+y+`StMa0!Jlv1 zOs9{eP8~IOLbaYWZ(elNbZg1v$&=#~5`=udMY3Y~^2n$tPDrTrV}g_vPDsd`qdqj` z?(SZ2=x{`MxJ4Ea7yy62*t!)g2L{u*+?5%tV8G+?EYFApOLBK?H(-W0sdbrL7RKcs zEi7D+mK#@=wJ2&3^B#Z6SE|tW^ z&fa_A0KDdD7g}CkuGQ%*uYy_6tlm5}8JiaBN~M03ks%g~tMA@5>&#%lv|6osRa0w$GfX-lmv6;tg7E35t(xdFTQCUeAbpwWpTg5+|K7IY# zwbIg(hK5FUUmu3O*mrLl?KRUayoa}&LPcB<-$|3+(JUi7*{UTR~?sv$M1P1N>*rj)mLHrKNHON-lLA!%9m^1R@cPXUv=l zmwktfMx&WuVn$tE?SL(YK0XhFAR`119z6nm6Brlagxr7dz}8t~Yn@7=%#V+Eb8|(} zt{zpd`CNjX*sbr;=t5DIS`Dt#+slj1W=)+krM;u$iMZ8K>adS$jr!2xBjD^>TUvBF z9d0yoxm*IZ?l;-5Ain@y6NACvgojsGRpsU7j%^L&Y-U7+haE2}3J&Fvoey?)v}dhb zCu#eKuxQ%SD*0;n9-YaBlZv8a$Hv3kwrJWRlMUc_^1_AW@h&SVIeq4*!NEa-a~Q~4 z+oV!0nTl_2YVx!S#tzx~^ayTn&@|YYz@VU6F)=fuXV94}i1{Q@*QnG@O^x-nwNi;h z*`t)BXsbkOr-$)j`>g(C&HN({S~o10_f z;%IdG#4O<1vuEG#-(Pg%q)ef3=$L{Rf85e?x28HGf*TMRL^f|}YwPyhobszzVFAQ= zm~N%=UR|9)Ab@0*RDI`VXWyx=A<{WQ0h*baId@(Hx%~+Wg~envH8%FDRE|=IfS_Gc9lLglmM*of63B)(jlMWFl^Yh` z-PHwg&`!V3goKDr=Y)nNCGiA8A;+rnCkfqM=&e6)R#x6>e)2@4>Few7cQpMPZm{_I z@>5c?^YUI_#W{jAr%qkC_-ltu?lLq)WR>)^Tj}QN>OSs3Z67*1WyCi#!0z{cbAY@o z006~x)1!xywl>13BNU2g3IFKvB5+=0+j?T+{J*NJA&d|~9YF+(7w2r-hRPK^N~OV| z*K2jK7)uw$abO06sz<3-X}VB_(P)g1kH1%6r&4Pit&*rzYH08@48w6FjvxpyMqH5G z+#G(IkSOXBu{bAtE4UNjJv2Dv?d^r*xNNN6#<*(JR_RN|$7Zqo{R0Rz5+7e*D63_1 z1<}onQAk;|C^{yFKD+Wz{HrNFFf|SuX0K6dp!F8pg;@r>Y=rsCpr)?Z@)E?>v3>(o$ zrqR3^&og+a=b!w5N57jd;8|i|GIMu#V_YC94Rc^kd-O#lzDi#4-5>B z`F?^uj5UIS0&A+OHhi}J_wsTa!}NN6eQllj6z=lWJG4TH)* z?`+z*0Yy=!W5up*A7no6n!nw*wo>MkzI-d?@orCP?%cM_FCIaX9;>6gpovZ%<&lG0MhzAcYIoOgsb z0n|ss&CTu6!-opA%OZibfuXl|${hS;XMd^jw!!)D4NmG#>Q3rT>i;k5{|Ybw$j9Fp Tu#Z&K00000NkvXXu0mjfnP|DN diff --git a/AustinHarris.JsonRpc.Client.WP7Test/AustinHarris.JsonRpc.Client.WP7Test.csproj b/AustinHarris.JsonRpc.Client.WP7Test/AustinHarris.JsonRpc.Client.WP7Test.csproj deleted file mode 100644 index 0e22e65..0000000 --- a/AustinHarris.JsonRpc.Client.WP7Test/AustinHarris.JsonRpc.Client.WP7Test.csproj +++ /dev/null @@ -1,147 +0,0 @@ - - - - Debug - AnyCPU - 10.0.20506 - 2.0 - {0838766E-01BD-4B62-9F0B-2C1FB3B39DBD} - {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - AustinHarris.JsonRpc.Client.WP7Test - AustinHarris.JsonRpc.Client.WP7Test - v8.0 - - - - - WindowsPhone - true - - - true - true - AustinHarris.JsonRpc.Client.WP7Test_$(Configuration)_$(Platform).xap - Properties\AppManifest.xml - AustinHarris.JsonRpc.Client.WP7Test.App - true - true - SAK - SAK - SAK - SAK - - - - - 4.0 - 11.0 - - - true - full - false - Bin\Debug - DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE - true - true - prompt - 4 - - - pdbonly - true - Bin\Release - TRACE;SILVERLIGHT;WINDOWS_PHONE - true - true - prompt - 4 - - - - Bin\x86\Debug - true - full - false - - - - Bin\x86\Release - pdbonly - true - - - - Bin\ARM\Debug - true - full - false - - - - Bin\ARM\Release - pdbonly - true - - - - ..\packages\Rx-Main.1.0.11226\lib\SL3-WP\System.Reactive.dll - - - - - App.xaml - - - MainPage.xaml - - - - - - Designer - MSBuild:Compile - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - MSBuild:Compile - Designer - - - - - - Designer - - - - - PreserveNewest - - - PreserveNewest - - - - - - {BFF21670-9DEB-4E36-95F4-96FC9DC740A2} - AustinHarris.JsonRpc.Client.WP7 - - - - - - - \ No newline at end of file diff --git a/AustinHarris.JsonRpc.Client.WP7Test/Background.png b/AustinHarris.JsonRpc.Client.WP7Test/Background.png deleted file mode 100644 index e46f21d9407f1ae4d6fedcf793778f32bae3f06d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3521 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 diff --git a/AustinHarris.JsonRpc.Client.WP7Test/MainPage.xaml b/AustinHarris.JsonRpc.Client.WP7Test/MainPage.xaml deleted file mode 100644 index 4b513ff..0000000 --- a/AustinHarris.JsonRpc.Client.WP7Test/MainPage.xaml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/AustinHarris.JsonRpc.Client.WP7Test/MainPage.xaml.cs b/AustinHarris.JsonRpc.Client.WP7Test/MainPage.xaml.cs deleted file mode 100644 index e4488a4..0000000 --- a/AustinHarris.JsonRpc.Client.WP7Test/MainPage.xaml.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Shapes; -using Microsoft.Phone.Controls; -using System.Reactive.Concurrency; - -namespace AustinHarris.JsonRpc.Client.WP7Test -{ - public partial class MainPage : PhoneApplicationPage - { - // Constructor - public MainPage() - { - InitializeComponent(); - } - JsonResponse response; - Exception ex; - bool done; - protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) - { - base.OnNavigatedTo(e); - JsonRpcClient client = new JsonRpcClient(new Uri("http://localhost:49718/json.rpc")); - var request = client.Invoke("internal.echo", "hi", Scheduler.ThreadPool); - - request.Subscribe( - response => - { - this.response = response; - }, - error => - { - ex = error; - }, - () => - { - done = true; - } - ); - } - } -} \ No newline at end of file diff --git a/AustinHarris.JsonRpc.Client.WP7Test/Properties/AppManifest.xml b/AustinHarris.JsonRpc.Client.WP7Test/Properties/AppManifest.xml deleted file mode 100644 index 6712a11..0000000 --- a/AustinHarris.JsonRpc.Client.WP7Test/Properties/AppManifest.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/AustinHarris.JsonRpc.Client.WP7Test/Properties/AssemblyInfo.cs b/AustinHarris.JsonRpc.Client.WP7Test/Properties/AssemblyInfo.cs deleted file mode 100644 index f27f7fa..0000000 --- a/AustinHarris.JsonRpc.Client.WP7Test/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +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.JsonRpc.Client.WP7Test")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("AustinHarris.JsonRpc.Client.WP7Test")] -[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("9172e0a2-66d0-48b4-987f-a656d1634bb3")] - -// 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 Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/AustinHarris.JsonRpc.Client.WP7Test/Properties/WMAppManifest.xml b/AustinHarris.JsonRpc.Client.WP7Test/Properties/WMAppManifest.xml deleted file mode 100644 index 37010b4..0000000 --- a/AustinHarris.JsonRpc.Client.WP7Test/Properties/WMAppManifest.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - ApplicationIcon.png - - - - - - - - - - - - - - - - - - - - - - - - - Background.png - 0 - Background.png - AustinHarris.JsonRpc.Client.WP7Test - - - - - false - - - - - - - - - - \ No newline at end of file diff --git a/AustinHarris.JsonRpc.Client.WP7Test/SplashScreenImage.jpg b/AustinHarris.JsonRpc.Client.WP7Test/SplashScreenImage.jpg deleted file mode 100644 index 353b1927b9d397aac7f23098e427739615db19fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9417 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 UfQSJR10n`Q4E%c;KnlnH2jCM6ivR!s diff --git a/README.md b/README.md index 093440a..1b6620a 100644 --- a/README.md +++ b/README.md @@ -672,7 +672,7 @@ dotnet test AustinHarris.JsonRpcTestN The test suite runs its protocol cases once per serializer (built-in, Json.NET, System.Text.Json) plus the parser, dispatch, version-policy and Kestrel integration tests, on both `net8.0` and `net10.0`. Building a package project in Release produces its NuGet package in `bin/Release/`. The WebAssembly sample builds without the `wasm-tools` workload; add it for AOT. -`AustinHarris.JsonRpc.Client`, `AustinHarris.JsonRpc.Client.WP7`, `AustinHarris.JsonRpc.AspNet`, `JsonRpcTest` and `TestClient` are 1.x projects that are still in the tree but outside the solution; nothing in 2.0 is built from them. +`AustinHarris.JsonRpc.Client`, `AustinHarris.JsonRpc.AspNet`, `JsonRpcTest` and `TestClient` are 1.x projects that are still in the tree but outside the solution; nothing in 2.0 is built from them. ### Charts From a7860da87bd8dd9c0dd8468a5eadd86d6d8b1698 Mon Sep 17 00:00:00 2001 From: Austin Harris Date: Thu, 24 Sep 2026 21:45:23 -0600 Subject: [PATCH 5/6] Packages: XML docs, symbols, icon, framework tags, release notes; the upgrade guide gets its own page Every package now ships its XML documentation (CS1591 silenced), a Source Link symbols package built with ContinuousIntegrationBuild on master, the site favicon as its icon, tags naming the target frameworks, and release notes that say what 2.0 is and link to the What is new and Upgrading from 1.x pages on the documentation site. The README's Upgrading from 1.x section moves to docs/upgrading.md (the README keeps a summary and a link) so the site has an upgrading.html to land on, and CHANGELOG.md is published as changelog.html. One ambiguous cref in ServiceBinder fixed on the way. --- .github/workflows/build_publish_master.yml | 4 +- .../AustinHarris.JsonRpc.AspNetCore.csproj | 12 +++++- .../AustinHarris.JsonRpc.Newtonsoft.csproj | 12 +++++- ...AustinHarris.JsonRpc.SystemTextJson.csproj | 12 +++++- CHANGELOG.md | 4 +- Json-Rpc/AustinHarris.JsonRpc.csproj | 12 +++++- Json-Rpc/ServiceBinder.cs | 2 +- README.md | 32 +--------------- docs/serializers.md | 2 +- docs/upgrading.md | 35 ++++++++++++++++++ icon.png | Bin 0 -> 6049 bytes site/build.py | 4 ++ 12 files changed, 87 insertions(+), 44 deletions(-) create mode 100644 docs/upgrading.md create mode 100644 icon.png diff --git a/.github/workflows/build_publish_master.yml b/.github/workflows/build_publish_master.yml index cb59a9f..1a6a319 100644 --- a/.github/workflows/build_publish_master.yml +++ b/.github/workflows/build_publish_master.yml @@ -32,8 +32,10 @@ jobs: run: dotnet restore AustinHarris.JsonRpc.sln # Building the solution packs every package project (GeneratePackageOnBuild); `dotnet pack` on the # solution would trip NU5026 with GeneratePackageOnBuild, so the packages come from the build. + # ContinuousIntegrationBuild makes the build deterministic and lets Source Link map the symbols package + # (.snupkg, pushed alongside each .nupkg) back to this commit on GitHub. - name: Build - run: dotnet build AustinHarris.JsonRpc.sln --configuration Release --no-restore + run: dotnet build AustinHarris.JsonRpc.sln --configuration Release --no-restore -p:ContinuousIntegrationBuild=true - name: Test run: dotnet test AustinHarris.JsonRpcTestN --configuration Release --no-build # The key is requested after the tests so it is fresh for the push (it expires after one hour). `user` is the diff --git a/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj b/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj index fab08ea..04a339e 100644 --- a/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj +++ b/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj @@ -7,23 +7,31 @@ ASP.NET Core / Kestrel hosting for JSON-RPC.Net: MapJsonRpc endpoint (PipeReader in, BodyWriter out, no strings), a raw Kestrel ConnectionHandler for JSON-RPC over TCP, and DI registration of services. 2.0.0 preview.1 - https://github.com/Astn/JSON-RPC.NET/blob/master/CHANGELOG.md + 2.0.0-preview.1, released with the core package. What is new: https://astn.github.io/JSON-RPC.NET/changelog.html. Upgrading from 1.x: https://astn.github.io/JSON-RPC.NET/upgrading.html Austin Harris https://astn.github.io/JSON-RPC.NET/aspnetcore.html https://github.com/Astn/JSON-RPC.NET git MIT README.md - json-rpc;jsonrpc;json;rpc;server;aspnetcore;kestrel;pipelines + json-rpc;jsonrpc;json;rpc;server;aspnetcore;asp.net-core;kestrel;pipelines;tcp;net8.0;net10.0 net8.0;net10.0 latest disable + true + $(NoWarn);CS1591 + true + snupkg + true + true + icon.png true AustinHarris.JsonRpc.AspNetCore + diff --git a/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj b/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj index 36a3403..1fec2c9 100644 --- a/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj +++ b/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj @@ -7,23 +7,31 @@ Json.NET (Newtonsoft.Json) serializer for JSON-RPC.Net. Lenient parsing and full Json.NET conversion semantics; pass JsonSerializerSettings to control it. 2.0.0 preview.1 - https://github.com/Astn/JSON-RPC.NET/blob/master/CHANGELOG.md + 2.0.0-preview.1, released with the core package. What is new: https://astn.github.io/JSON-RPC.NET/changelog.html. Upgrading from 1.x: https://astn.github.io/JSON-RPC.NET/upgrading.html Austin Harris https://astn.github.io/JSON-RPC.NET/newtonsoft.html https://github.com/Astn/JSON-RPC.NET git MIT README.md - json-rpc;jsonrpc;json;rpc;server;json.net;newtonsoft + json-rpc;jsonrpc;json;rpc;server;json.net;newtonsoft;serializer;netstandard2.0;netstandard2.1;net8.0;net10.0 netstandard2.0;netstandard2.1;net8.0;net10.0 latest true + true + $(NoWarn);CS1591 + true + snupkg + true + true + icon.png true AustinHarris.JsonRpc.Newtonsoft + diff --git a/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj b/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj index 1f21e6b..583d3a1 100644 --- a/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj +++ b/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj @@ -7,22 +7,30 @@ System.Text.Json serializer for JSON-RPC.Net. Utf8JsonReader/Utf8JsonWriter end to end; pass JsonSerializerOptions to control it. 2.0.0 preview.1 - https://github.com/Astn/JSON-RPC.NET/blob/master/CHANGELOG.md + 2.0.0-preview.1, released with the core package. What is new: https://astn.github.io/JSON-RPC.NET/changelog.html. Upgrading from 1.x: https://astn.github.io/JSON-RPC.NET/upgrading.html Austin Harris https://astn.github.io/JSON-RPC.NET/systemtextjson.html https://github.com/Astn/JSON-RPC.NET git MIT README.md - json-rpc;jsonrpc;json;rpc;server;system.text.json + json-rpc;jsonrpc;json;rpc;server;system.text.json;serializer;netstandard2.0;netstandard2.1;net8.0;net10.0 netstandard2.0;netstandard2.1;net8.0;net10.0 latest + true + $(NoWarn);CS1591 + true + snupkg + true + true + icon.png true AustinHarris.JsonRpc.SystemTextJson + diff --git a/CHANGELOG.md b/CHANGELOG.md index fea6bfa..5f05bef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,8 @@ The four packages (`AustinHarris.JsonRpc`, `AustinHarris.JsonRpc.Newtonsoft`, `AustinHarris.JsonRpc.SystemTextJson`, `AustinHarris.JsonRpc.AspNetCore`) share one version number and are released together. This file is the record -of what changed in each version; the README's [Upgrading from 1.x](README.md#upgrading-from-1x) explains how to -move a 1.x server, and the package pages on NuGet link here. +of what changed in each version; [Upgrading from 1.x](docs/upgrading.md) explains how to move a 1.x server, and +the package pages on NuGet link here. Versions follow [Semantic Versioning](https://semver.org/) for the public API and the documented wire behaviour: a breaking change to either means a new major version. diff --git a/Json-Rpc/AustinHarris.JsonRpc.csproj b/Json-Rpc/AustinHarris.JsonRpc.csproj index 5ffb293..2540c8f 100644 --- a/Json-Rpc/AustinHarris.JsonRpc.csproj +++ b/Json-Rpc/AustinHarris.JsonRpc.csproj @@ -13,15 +13,23 @@ git MIT README.md - json-rpc;jsonrpc;json;rpc;server;netstandard;kestrel;pipelines;system.text.json;json.net;fast - https://github.com/Astn/JSON-RPC.NET/blob/master/CHANGELOG.md + json-rpc;jsonrpc;json;rpc;server;netstandard;netstandard2.0;netstandard2.1;net8.0;net10.0;kestrel;pipelines;system.text.json;json.net;fast + 2.0.0-preview.1: the request pipeline rebuilt around UTF-8 bytes, the JSON serializer pluggable, Task and ValueTask methods supported again, about ten times the throughput of 1.2.3 on the same machine. What is new: https://astn.github.io/JSON-RPC.NET/changelog.html. Upgrading from 1.x: https://astn.github.io/JSON-RPC.NET/upgrading.html netstandard2.0;netstandard2.1;net8.0;net10.0 latest + true + $(NoWarn);CS1591 + true + snupkg + true + true + icon.png true + diff --git a/Json-Rpc/ServiceBinder.cs b/Json-Rpc/ServiceBinder.cs index 62b3b36..f797161 100644 --- a/Json-Rpc/ServiceBinder.cs +++ b/Json-Rpc/ServiceBinder.cs @@ -33,7 +33,7 @@ public static void BindMethod(string name, Delegate implementation, string[] par /// when given (null entries keep the lambda's own name), else by the /// lambda's parameter names, else arg1, arg2... for a delegate whose names are not recoverable. /// (keyed by JSON name) make those parameters optional. The name must be free: - /// re-registering a name is an error, unlike attribute binding; unbind it first with . + /// re-registering a name is an error, unlike attribute binding; unbind it first with . /// Task and ValueTask delegates require ProcessAsync; async void is rejected. /// controls ambient context across awaits. /// diff --git a/README.md b/README.md index 1b6620a..8c73a25 100644 --- a/README.md +++ b/README.md @@ -618,37 +618,7 @@ Under the previous harness (one pass per batch, workstation GC) the two-million ## Upgrading from 1.x -Most 1.x services run unchanged. Read the first list before you build, and the second before you deploy next to existing clients. - -### Changes that break the build - -- **Serializer.** `JsonRpcProcessor.Process(…, JsonSerializerSettings)` is gone from the core. Use `Config.SetSerializer(new NewtonsoftJsonRpcSerializer(settings))` from the Newtonsoft package, or the helper overloads there that take the settings. -- **Overloads.** The default-session string overloads that take a serializer take it first: `Process(serializer, json, context)` and `ProcessSync(serializer, json, context)`. `ProcessSync(sessionId, json, context, serializer)` makes `context` required, so `ProcessSync(json, null)` still means the default session. `Process` and `ProcessAsync` do not: `Process(json, null)` no longer compiles (it is ambiguous with the `JsonRpcStateAsync` overload), and `ProcessAsync(json, null)` binds to the session overload with `json` as the session id and a null document, which throws `ArgumentNullException`. Write `Process(json)`, `Process(json, context: null)` or `ProcessAsync(json, context: null)`. -- **DTOs.** `JsonRequest`, `JsonResponse` and `JsonRpcException` are plain DTOs without Json.NET attributes. `JsonRequest.Params` is the active serializer's object model, so cast to `JObject`/`JArray` only when the Json.NET serializer is active. -- **SMD.** `SMD.Services` is an `SMDServiceCollection` (an `IDictionary`) instead of a `Dictionary`, and its setter is gone. Every mutation through it updates the dispatch table at once, so a removed method is unreachable immediately. `SMD.Types` is now `Dictionary>` and a process-wide registry (it was reset whenever a session was created). - -### Changes clients will see on the wire - -- **Version member.** The `jsonrpc` member is checked (`Config.VersionPolicy`, default `Lenient`): a missing member is still accepted, but `"jsonrpc":"1.0"` or a non-string value is now `-32600`. Set `Ignore` for the 1.x behaviour. -- **Parse errors.** Requests nested deeper than 64 levels are `-32700` (configurable per serializer, see [Nesting depth](#nesting-depth)). Invalid UTF-8 and non-strict JSON (unless the serializer is lenient) are `-32700` as well. -- **Batches.** The empty-batch error code is the spec's `-32600` (it was `3200`). Batches made only of notifications produce an empty response instead of `[]` with a dangling comma. A batch always answers with a JSON array when it produces at least one response; a one-request batch is no longer unwrapped to a bare response object. -- **Notifications.** A notification (a request without an `id`) never gets a wire response, whatever its outcome: method not found, binding failure or an exception in the method produce nothing on the wire (the error handler still runs server-side). An invalid request object is not a notification and still gets `-32600` with `"id":null`. -- **Exceptions.** An unhandled exception is `-32603` with `data: null` by default; 1.x sent the exception's type, message and stack trace. `Config.IncludeExceptionDetails = true` sends the full description; an error handler can author something in between. See [Exception disclosure](#exception-disclosure). -- **Conversion errors.** A parameter value the serializer cannot convert (`"abc"` for an `int`, `"not-a-guid"` for a `Guid`) is `-32602` with `data = {"reason":"conversion","parameter":…,"index":…,"expectedType":…}`; it was `-32603` with the exception. An exception of the same type thrown inside the method is still `-32603`. A type the built-in serializer cannot handle at all stays `-32603` (now a `NotSupportedException`). -- **Method not found.** `-32601`'s `data` is `{"method":""}` instead of the fixed sentence, and a method-not-found error for a notification now reaches the error handler (the wire still gets nothing). -- **Named parameters.** They are checked against the method's parameter list: a supplied name that matches no parameter, or a name supplied twice, is `-32602` (it used to be ignored, so `optional(int a = 9)` called with `{"typo":4}` returned 9). Defaults fill only the names that are absent. -- **Dates and non-finite numbers.** `DateTime` and `DateTimeOffset` are written the way Json.NET writes them by every serializer (fraction only when non-zero, `Z`/offset/nothing by `Kind`); `NaN` and the infinities are written as the quoted strings `"NaN"`, `"Infinity"`, `"-Infinity"` and read back from them. - -### Behaviour inside your server - -- **Async methods.** Task-returning methods are supported again through `ProcessAsync`, together with `ValueTask` and `ValueTask`. Synchronous `Process`/`ProcessSync` reject them at call time without invoking them. `async void` remains rejected at registration. See [Asynchronous methods and cancellation](#asynchronous-methods-and-cancellation). -- **Request id.** The invocation frame also carries the request id: `Handler.RpcRequestId()` / `JsonRpcContext.CurrentRequestId()`, `Handler.RpcRequestIdKind()` and `Handler.RpcRequestIdRaw()`, see [The request id](#the-request-id). -- **Binding.** `ServiceBinder.BindMethod(sessionId, name, delegate)` registers any delegate; it refuses a name that is already registered, unlike `Handler.RegisterFuction`, which keeps replacing silently. -- **Pre-process handlers.** A pre-process handler may replace `JsonRequest.Method`, `Params` or `Id`; the replaced request is what gets dispatched (as in 1.x). Assign a new `Params` value rather than editing the serializer's object model in place: a request the handler leaves untouched is dispatched straight from the request bytes. -- **Context.** `JsonRpcContext.Current()` / `Handler.RpcContext()` and `JsonRpcContext.SetException` are per invocation: a method that synchronously processes another request through `JsonRpcProcessor` gets its own context and exception state back afterwards. -- **Sessions.** A request for a session id that was never registered no longer creates the session; it answers `-32601`. Bind services or call `Handler.GetSessionHandler(sessionId)` before serving a session. `Config.SetBeforeProcessHandler(sessionId, …)` is now `Config.SetPreProcessHandler(sessionId, …)` (the old name still compiles, with an obsolete warning), and `Config.SetPostProcessHandler(sessionId, …)` exists. -- **`JsonRpcService`.** The AspNetCore host binds a subclass to the configured session even when that is the default session; a subclass can pass `base(false)` to skip binding itself. -- **`Handler.Handle(JsonRequest)`** still works; it round-trips the request through the serializer and the boxed path. +Most 1.x services run unchanged. [Upgrading from 1.x](docs/upgrading.md) lists the changes that break the build, the changes clients will see on the wire and the behaviour changes inside your server. Read the first list before you build and the second before you deploy next to existing clients. [CHANGELOG.md](CHANGELOG.md) is the record of every change per version. ## Versioning and support diff --git a/docs/serializers.md b/docs/serializers.md index b31e000..4e0142b 100644 --- a/docs/serializers.md +++ b/docs/serializers.md @@ -163,4 +163,4 @@ constructor, throws `NotSupportedException` from `Read` (it was `JsonRpcBindExce on the wire. For the complete list of protocol, error, batching, async, context and metadata changes, see -[Upgrading from 1.x](../README.md#upgrading-from-1x) in the main README. +[Upgrading from 1.x](upgrading.md). diff --git a/docs/upgrading.md b/docs/upgrading.md new file mode 100644 index 0000000..158866d --- /dev/null +++ b/docs/upgrading.md @@ -0,0 +1,35 @@ +# Upgrading from 1.x + +Most 1.x services run unchanged. Read the first list before you build, and the second before you deploy next to existing clients. + +## Changes that break the build + +- **Serializer.** `JsonRpcProcessor.Process(…, JsonSerializerSettings)` is gone from the core. Use `Config.SetSerializer(new NewtonsoftJsonRpcSerializer(settings))` from the Newtonsoft package, or the helper overloads there that take the settings. +- **Overloads.** The default-session string overloads that take a serializer take it first: `Process(serializer, json, context)` and `ProcessSync(serializer, json, context)`. `ProcessSync(sessionId, json, context, serializer)` makes `context` required, so `ProcessSync(json, null)` still means the default session. `Process` and `ProcessAsync` do not: `Process(json, null)` no longer compiles (it is ambiguous with the `JsonRpcStateAsync` overload), and `ProcessAsync(json, null)` binds to the session overload with `json` as the session id and a null document, which throws `ArgumentNullException`. Write `Process(json)`, `Process(json, context: null)` or `ProcessAsync(json, context: null)`. +- **DTOs.** `JsonRequest`, `JsonResponse` and `JsonRpcException` are plain DTOs without Json.NET attributes. `JsonRequest.Params` is the active serializer's object model, so cast to `JObject`/`JArray` only when the Json.NET serializer is active. +- **SMD.** `SMD.Services` is an `SMDServiceCollection` (an `IDictionary`) instead of a `Dictionary`, and its setter is gone. Every mutation through it updates the dispatch table at once, so a removed method is unreachable immediately. `SMD.Types` is now `Dictionary>` and a process-wide registry (it was reset whenever a session was created). + +## Changes clients will see on the wire + +- **Version member.** The `jsonrpc` member is checked (`Config.VersionPolicy`, default `Lenient`): a missing member is still accepted, but `"jsonrpc":"1.0"` or a non-string value is now `-32600`. Set `Ignore` for the 1.x behaviour. +- **Parse errors.** Requests nested deeper than 64 levels are `-32700` (configurable per serializer, see [Nesting depth](../README.md#nesting-depth)). Invalid UTF-8 and non-strict JSON (unless the serializer is lenient) are `-32700` as well. +- **Batches.** The empty-batch error code is the spec's `-32600` (it was `3200`). Batches made only of notifications produce an empty response instead of `[]` with a dangling comma. A batch always answers with a JSON array when it produces at least one response; a one-request batch is no longer unwrapped to a bare response object. +- **Notifications.** A notification (a request without an `id`) never gets a wire response, whatever its outcome: method not found, binding failure or an exception in the method produce nothing on the wire (the error handler still runs server-side). An invalid request object is not a notification and still gets `-32600` with `"id":null`. +- **Exceptions.** An unhandled exception is `-32603` with `data: null` by default; 1.x sent the exception's type, message and stack trace. `Config.IncludeExceptionDetails = true` sends the full description; an error handler can author something in between. See [Exception disclosure](../README.md#exception-disclosure). +- **Conversion errors.** A parameter value the serializer cannot convert (`"abc"` for an `int`, `"not-a-guid"` for a `Guid`) is `-32602` with `data = {"reason":"conversion","parameter":…,"index":…,"expectedType":…}`; it was `-32603` with the exception. An exception of the same type thrown inside the method is still `-32603`. A type the built-in serializer cannot handle at all stays `-32603` (now a `NotSupportedException`). +- **Method not found.** `-32601`'s `data` is `{"method":""}` instead of the fixed sentence, and a method-not-found error for a notification now reaches the error handler (the wire still gets nothing). +- **Named parameters.** They are checked against the method's parameter list: a supplied name that matches no parameter, or a name supplied twice, is `-32602` (it used to be ignored, so `optional(int a = 9)` called with `{"typo":4}` returned 9). Defaults fill only the names that are absent. +- **Dates and non-finite numbers.** `DateTime` and `DateTimeOffset` are written the way Json.NET writes them by every serializer (fraction only when non-zero, `Z`/offset/nothing by `Kind`); `NaN` and the infinities are written as the quoted strings `"NaN"`, `"Infinity"`, `"-Infinity"` and read back from them. + +## Behaviour inside your server + +- **Async methods.** Task-returning methods are supported again through `ProcessAsync`, together with `ValueTask` and `ValueTask`. Synchronous `Process`/`ProcessSync` reject them at call time without invoking them. `async void` remains rejected at registration. See [Asynchronous methods and cancellation](../README.md#asynchronous-methods-and-cancellation). +- **Request id.** The invocation frame also carries the request id: `Handler.RpcRequestId()` / `JsonRpcContext.CurrentRequestId()`, `Handler.RpcRequestIdKind()` and `Handler.RpcRequestIdRaw()`, see [The request id](../README.md#the-request-id). +- **Binding.** `ServiceBinder.BindMethod(sessionId, name, delegate)` registers any delegate; it refuses a name that is already registered, unlike `Handler.RegisterFuction`, which keeps replacing silently. +- **Pre-process handlers.** A pre-process handler may replace `JsonRequest.Method`, `Params` or `Id`; the replaced request is what gets dispatched (as in 1.x). Assign a new `Params` value rather than editing the serializer's object model in place: a request the handler leaves untouched is dispatched straight from the request bytes. +- **Context.** `JsonRpcContext.Current()` / `Handler.RpcContext()` and `JsonRpcContext.SetException` are per invocation: a method that synchronously processes another request through `JsonRpcProcessor` gets its own context and exception state back afterwards. +- **Sessions.** A request for a session id that was never registered no longer creates the session; it answers `-32601`. Bind services or call `Handler.GetSessionHandler(sessionId)` before serving a session. `Config.SetBeforeProcessHandler(sessionId, …)` is now `Config.SetPreProcessHandler(sessionId, …)` (the old name still compiles, with an obsolete warning), and `Config.SetPostProcessHandler(sessionId, …)` exists. +- **`JsonRpcService`.** The AspNetCore host binds a subclass to the configured session even when that is the default session; a subclass can pass `base(false)` to skip binding itself. +- **`Handler.Handle(JsonRequest)`** still works; it round-trips the request through the serializer and the boxed path. + +Every change is recorded per version in the [changelog](../CHANGELOG.md). diff --git a/icon.png b/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ad9f08d10fe8fedea123c280f98831653b33a972 GIT binary patch literal 6049 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 YCA!jU3EWRW=^ape@KC8#(K7Hq08}0r(EtDd literal 0 HcmV?d00001 diff --git a/site/build.py b/site/build.py index c769182..28a5e88 100644 --- a/site/build.py +++ b/site/build.py @@ -45,6 +45,10 @@ PAGES = [ ("index.html", "README.md", "JSON-RPC.NET", "Overview", "Guide", "A high performance JSON-RPC 2.0 server for .NET: bytes in, bytes out, pluggable serializers, Kestrel hosting."), + ("changelog.html", "CHANGELOG.md", "What is new", "What is new", "Guide", + "Release notes for every version: what 2.0 adds, changes, removes and fixes, and the 1.x history."), + ("upgrading.html", "docs/upgrading.md", "Upgrading from 1.x", "Upgrading from 1.x", "Guide", + "What a 1.x server must change to build against 2.0, what clients will see on the wire, and what behaves differently inside the server."), ("serializers.html", "docs/serializers.md", "Serializers", "Serializers", "Guide", "How the built-in, Json.NET and System.Text.Json serializers differ, and how to configure or write one."), ("aspnetcore.html", "AustinHarris.JsonRpc.AspNetCore/README.md", "ASP.NET Core hosting", "ASP.NET Core hosting", "Packages", From 9a821e44fa83d0aba3c1ab2eb11e267e3e901c92 Mon Sep 17 00:00:00 2001 From: Austin Harris Date: Thu, 24 Sep 2026 21:47:02 -0600 Subject: [PATCH 6/6] A README written for the package pages The core package shipped the repository README, which nuget.org renders without its HTML, relative links or images. Json-Rpc/README.md is written for that page: what the library is, the prerelease install line, the quick start from the repository README, the 1.2.3-versus-2.0 table with the headline chart from raw.githubusercontent.com, the companion packages, a short Upgrading from 1.x summary, and absolute links to the documentation site. It points a 1.x user at the What is new and Upgrading pages right after the install line, which is what Visual Studio shows when it opens the README on install. The companion READMEs open the same way, and the four package descriptions are shorter. --- .../AustinHarris.JsonRpc.AspNetCore.csproj | 2 +- AustinHarris.JsonRpc.AspNetCore/README.md | 17 +- .../AustinHarris.JsonRpc.Newtonsoft.csproj | 2 +- AustinHarris.JsonRpc.Newtonsoft/README.md | 18 ++- ...AustinHarris.JsonRpc.SystemTextJson.csproj | 2 +- AustinHarris.JsonRpc.SystemTextJson/README.md | 16 +- Json-Rpc/AustinHarris.JsonRpc.csproj | 4 +- Json-Rpc/README.md | 150 ++++++++++++++++++ 8 files changed, 184 insertions(+), 27 deletions(-) create mode 100644 Json-Rpc/README.md diff --git a/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj b/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj index 04a339e..3869014 100644 --- a/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj +++ b/AustinHarris.JsonRpc.AspNetCore/AustinHarris.JsonRpc.AspNetCore.csproj @@ -4,7 +4,7 @@ Austin Harris Austin Harris Json-Rpc.Net ASP.NET Core host - ASP.NET Core / Kestrel hosting for JSON-RPC.Net: MapJsonRpc endpoint (PipeReader in, BodyWriter out, no strings), a raw Kestrel ConnectionHandler for JSON-RPC over TCP, and DI registration of services. + ASP.NET Core hosting for AustinHarris.JsonRpc. Adds HTTP endpoints and raw Kestrel connections over TCP, Unix sockets and named pipes, with dependency injection. 2.0.0 preview.1 2.0.0-preview.1, released with the core package. What is new: https://astn.github.io/JSON-RPC.NET/changelog.html. Upgrading from 1.x: https://astn.github.io/JSON-RPC.NET/upgrading.html diff --git a/AustinHarris.JsonRpc.AspNetCore/README.md b/AustinHarris.JsonRpc.AspNetCore/README.md index 16aba34..97b8f9d 100644 --- a/AustinHarris.JsonRpc.AspNetCore/README.md +++ b/AustinHarris.JsonRpc.AspNetCore/README.md @@ -1,14 +1,17 @@ -# AustinHarris.JsonRpc.AspNetCore +# `AustinHarris.JsonRpc.AspNetCore` -Hosts [JSON-RPC.Net](https://github.com/Astn/JSON-RPC.NET) in ASP.NET Core. The core processes requests as -UTF-8 bytes, so the HTTP endpoint reads the body with `PipeReader` and writes straight into -`Response.BodyWriter`; nothing is turned into a string on the way through. A `ConnectionHandler` does the -same for JSON-RPC over a raw Kestrel connection (TCP, Unix socket, named pipe). +`AustinHarris.JsonRpc.AspNetCore` hosts +[`AustinHarris.JsonRpc`](https://www.nuget.org/packages/AustinHarris.JsonRpc) 2.0 in ASP.NET Core +and registers services through dependency injection. +Choose it for an HTTP endpoint or raw Kestrel connections over TCP, Unix sockets or named pipes. + +The HTTP endpoint reads with `PipeReader` and writes to `Response.BodyWriter` +without converting the document to a string. ## Install -``` -dotnet add package AustinHarris.JsonRpc.AspNetCore +```sh +dotnet add package AustinHarris.JsonRpc.AspNetCore --prerelease ``` Targets `net8.0` and `net10.0`; depends on the `AustinHarris.JsonRpc` core package and the ASP.NET Core shared diff --git a/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj b/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj index 1fec2c9..22d3b2a 100644 --- a/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj +++ b/AustinHarris.JsonRpc.Newtonsoft/AustinHarris.JsonRpc.Newtonsoft.csproj @@ -4,7 +4,7 @@ Austin Harris Austin Harris Json-Rpc.Net Json.NET serializer - Json.NET (Newtonsoft.Json) serializer for JSON-RPC.Net. Lenient parsing and full Json.NET conversion semantics; pass JsonSerializerSettings to control it. + Json.NET serializer for AustinHarris.JsonRpc. Uses JsonSerializerSettings for converters, contract resolvers and lenient JSON input. 2.0.0 preview.1 2.0.0-preview.1, released with the core package. What is new: https://astn.github.io/JSON-RPC.NET/changelog.html. Upgrading from 1.x: https://astn.github.io/JSON-RPC.NET/upgrading.html diff --git a/AustinHarris.JsonRpc.Newtonsoft/README.md b/AustinHarris.JsonRpc.Newtonsoft/README.md index 07b305b..6e5c0fd 100644 --- a/AustinHarris.JsonRpc.Newtonsoft/README.md +++ b/AustinHarris.JsonRpc.Newtonsoft/README.md @@ -1,14 +1,16 @@ -# AustinHarris.JsonRpc.Newtonsoft +# `AustinHarris.JsonRpc.Newtonsoft` -Json.NET (Newtonsoft.Json) serializer for [JSON-RPC.Net](https://github.com/Astn/JSON-RPC.NET) 2.0. +`AustinHarris.JsonRpc.Newtonsoft` adds Json.NET serialization to +[`AustinHarris.JsonRpc`](https://www.nuget.org/packages/AustinHarris.JsonRpc) 2.0. +Choose it when your models rely on Json.NET converters, contract resolvers or `[JsonProperty]`, +or when clients send non-strict JSON. -The core package (`AustinHarris.JsonRpc`) parses the JSON-RPC envelope itself and ships a built-in serializer for -parameters and results that needs no JSON library. Install this package when you want Json.NET to do the value -conversions: its converters, contract resolvers, `[JsonProperty]` attributes, date/float handling, and its -tolerance for non-strict JSON. +Configure parameter and result conversion with `JsonSerializerSettings`. -``` -dotnet add package AustinHarris.JsonRpc.Newtonsoft +## Install + +```sh +dotnet add package AustinHarris.JsonRpc.Newtonsoft --prerelease ``` Targets `netstandard2.0`, `netstandard2.1`, `net8.0` and `net10.0`; depends on Newtonsoft.Json 13.0.4 and the diff --git a/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj b/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj index 583d3a1..2f69a74 100644 --- a/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj +++ b/AustinHarris.JsonRpc.SystemTextJson/AustinHarris.JsonRpc.SystemTextJson.csproj @@ -4,7 +4,7 @@ Austin Harris Austin Harris Json-Rpc.Net System.Text.Json serializer - System.Text.Json serializer for JSON-RPC.Net. Utf8JsonReader/Utf8JsonWriter end to end; pass JsonSerializerOptions to control it. + System.Text.Json serializer for AustinHarris.JsonRpc. Reads UTF-8 parameters and writes results directly to the response buffer, configured with JsonSerializerOptions. 2.0.0 preview.1 2.0.0-preview.1, released with the core package. What is new: https://astn.github.io/JSON-RPC.NET/changelog.html. Upgrading from 1.x: https://astn.github.io/JSON-RPC.NET/upgrading.html diff --git a/AustinHarris.JsonRpc.SystemTextJson/README.md b/AustinHarris.JsonRpc.SystemTextJson/README.md index b0aee69..03d4d52 100644 --- a/AustinHarris.JsonRpc.SystemTextJson/README.md +++ b/AustinHarris.JsonRpc.SystemTextJson/README.md @@ -1,15 +1,17 @@ -# AustinHarris.JsonRpc.SystemTextJson +# `AustinHarris.JsonRpc.SystemTextJson` -System.Text.Json serializer for [JSON-RPC.Net](https://github.com/Astn/JSON-RPC.NET) 2.0. The core parses the -JSON-RPC envelope (method / params / id) itself and asks the serializer only to convert values: request -parameters arrive as the raw UTF-8 bytes of one JSON value and go straight into `JsonSerializer.Deserialize` -(no transcoding, no copies); results are written with a per-thread cached `Utf8JsonWriter` directly into the +`AustinHarris.JsonRpc.SystemTextJson` adds `System.Text.Json` serialization to +[`AustinHarris.JsonRpc`](https://www.nuget.org/packages/AustinHarris.JsonRpc) 2.0. +Choose it when your application already uses `JsonSerializerOptions` and `System.Text.Json` converters. + +Request parameters arrive as the raw UTF-8 bytes of one JSON value and go straight into `JsonSerializer.Deserialize`, +with no transcoding and no copies. Results are written with a per-thread cached `Utf8JsonWriter` directly into the response buffer. ## Install -``` -dotnet add package AustinHarris.JsonRpc.SystemTextJson +```sh +dotnet add package AustinHarris.JsonRpc.SystemTextJson --prerelease ``` Targets `netstandard2.0`, `netstandard2.1`, `net8.0` and `net10.0`; depends on System.Text.Json 10.0.3 and the diff --git a/Json-Rpc/AustinHarris.JsonRpc.csproj b/Json-Rpc/AustinHarris.JsonRpc.csproj index 2540c8f..f704c10 100644 --- a/Json-Rpc/AustinHarris.JsonRpc.csproj +++ b/Json-Rpc/AustinHarris.JsonRpc.csproj @@ -4,7 +4,7 @@ Austin Harris Austin Harris Json-Rpc.Net Core - JSON-RPC.Net is a high performance JSON-RPC 2.0 server for .NET Standard 2.0+ and modern .NET. Bytes in, bytes out, no JSON library dependency: the built-in serializer needs nothing, and Json.NET or System.Text.Json plug in through the companion packages. Host it in ASP.NET Core / Kestrel, a console app, sockets, pipes - anything that can hand you UTF-8 or a string. + High-throughput JSON-RPC 2.0 server library for .NET Standard 2.0 through .NET 10: UTF-8 bytes in and out, no JSON library dependency, with Json.NET, System.Text.Json and ASP.NET Core hosting as companion packages. 2.0.0 preview.1 Austin Harris @@ -28,7 +28,7 @@ - + diff --git a/Json-Rpc/README.md b/Json-Rpc/README.md new file mode 100644 index 0000000..69b1037 --- /dev/null +++ b/Json-Rpc/README.md @@ -0,0 +1,150 @@ +# `AustinHarris.JsonRpc` + +`AustinHarris.JsonRpc` is a JSON-RPC 2.0 server library for .NET. +Give it a UTF-8 request document and receive the response document: bytes in, bytes out. +It handles parsing, method dispatch, parameter binding, batches and error responses. +You supply the transport. + +The core has no JSON library dependency. +Its built-in serializer works on its own; companion packages add Json.NET, +`System.Text.Json` or ASP.NET Core hosting. + +Targets `netstandard2.0`, `netstandard2.1`, `net8.0` and `net10.0`. +This is a server library, with no client proxies or server-to-client calls. + +## Install + +2.0 is a prerelease. Include `--prerelease` when installing: + +```sh +dotnet add package AustinHarris.JsonRpc --prerelease +``` + +Coming from 1.x? Read [What is new in 2.0](https://astn.github.io/JSON-RPC.NET/changelog.html) and [Upgrading from 1.x](https://astn.github.io/JSON-RPC.NET/upgrading.html) first. + +## Getting started + +### Declare a service + +Create `CalculatorService.cs` with the service below. +Derive from `JsonRpcService` and mark exposed methods with `[JsonRpcMethod]`. +Constructing the service registers its methods in the default session. + +```csharp +using AustinHarris.JsonRpc; + +public class CalculatorService : JsonRpcService +{ + [JsonRpcMethod] // exposed as "add" + private double add(double l, double r) => l + r; + + [JsonRpcMethod("multiply")] // exposed under an explicit name + public int Multiply(int l, int r) => l * r; + + [JsonRpcMethod] + public string StringMe(string x) => x; +} +``` + +Methods can be `private`. Parameters can be positional or named. +Keep the service instance alive; it serves concurrent requests, so its state must be thread-safe. + +### Process requests + +Put this code in `Program.cs` in a console project targeting `net8.0` or `net10.0`. +It calls the service through both string overloads and the byte entry point. +The string overloads transcode into the byte pipeline. + +```csharp +using System; +using System.Buffers; +using System.Text; +using AustinHarris.JsonRpc; + +var service = new CalculatorService(); // binds itself to the default session; keep a reference + +// Strings, asynchronous invocation. +string response = await JsonRpcProcessor.ProcessAsync("{\"jsonrpc\":\"2.0\",\"method\":\"add\",\"params\":[1,2],\"id\":1}"); +// {"jsonrpc":"2.0","result":3.0,"id":1} + +// Strings, synchronous, on the calling thread. Named parameters. +string sync = JsonRpcProcessor.ProcessSync("{\"method\":\"multiply\",\"params\":{\"l\":6,\"r\":7},\"id\":2}"); +// {"jsonrpc":"2.0","result":42,"id":2} + +// Bytes: the native path. The string overloads transcode into it. +byte[] request = Encoding.UTF8.GetBytes("{\"method\":\"add\",\"params\":[2,3],\"id\":3}"); +var output = new ArrayBufferWriter(); +JsonRpcProcessor.Process(Handler.DefaultSessionId(), request.AsSpan(), output); +Console.WriteLine(Encoding.UTF8.GetString(output.WrittenSpan)); // nothing is written for a notification +``` + +The string responses appear in the comments above. The byte call prints: + +```json +{"jsonrpc":"2.0","result":5.0,"id":3} +``` + +A batch returns an array when it contains calls that need responses. +A notification has no `id` and produces no response. +Pass a `byte[]` as `AsSpan()` to select the span overload. + +Use `JsonRpcProcessor.ProcessAsync` for methods returning `Task` or `ValueTask`. +The synchronous entry points do not await those methods. + +## Performance + +These results compare 1.2.3 and 2.0 with the same five requests on the same machine in one session. +The 2.0 runs used the built-in serializer on an AMD Ryzen 7 7800X3D with .NET 10, Release and Server GC. + +![JSON-RPC.Net 1.2.3 and 2.0 throughput through the string and byte entry points](https://raw.githubusercontent.com/Astn/JSON-RPC.NET/master/benchmarks/charts/headline-1x-vs-2.svg) + +| Path | RPC/s | Against 1.2.3 | +| --- | ---: | ---: | +| 1.2.3, `Task Process(string)`, thread pool, best batch size | 3.08 M | | +| 2.0, the same string API and the same loop | 13.3 M | 4.3× | +| 2.0, `Process(bytes)`, 16 dedicated threads | 31.7 M | 10.3× | +| 2.0, `ProcessAsync(bytes)`, 16 awaited workers | 32.1 M | 10.4× | + +These measurements cover the library without a transport. +The asynchronous byte row uses methods that complete inline. +For Kestrel TCP with 256 requests in flight per connection and `EnableAsyncMethods = false`, +the measured range is 14.3 M to 16.5 M RPC/s on loopback, with clients and server on the same machine. + +See the [benchmark tables](https://astn.github.io/JSON-RPC.NET/#benchmarks) for conditions +and the [benchmark explorer](https://astn.github.io/JSON-RPC.NET/benchmarks/charts/explorer.html) for the data. + +## Companion packages + +Install only the integrations your host needs. Use matching package versions. + +- [`AustinHarris.JsonRpc.Newtonsoft`](https://astn.github.io/JSON-RPC.NET/newtonsoft.html): Json.NET converters, contract resolvers, `[JsonProperty]`, `JsonSerializerSettings` and lenient input. +- [`AustinHarris.JsonRpc.SystemTextJson`](https://astn.github.io/JSON-RPC.NET/systemtextjson.html): `System.Text.Json` conversion with `JsonSerializerOptions`, reading and writing UTF-8 values. +- [`AustinHarris.JsonRpc.AspNetCore`](https://astn.github.io/JSON-RPC.NET/aspnetcore.html): HTTP endpoints, raw Kestrel connections over TCP, Unix sockets or named pipes, and dependency injection. + +## Upgrading from 1.x + +Most service methods can stay as they are. Review these changes before switching: + +- Json.NET is now a companion package. Use it for `JsonSerializerSettings` and settings-based + compatibility helpers; `JsonRequest.Params` follows the selected serializer's object model. +- Review string overloads, especially calls with a positional null context. + Name the `context` argument explicitly; serializer-taking overloads have changed. +- Check client-visible behaviour: notifications never return responses, responding batches stay arrays, + and version values, named parameters and conversion failures are validated. +- Unhandled exceptions now return internal errors with exception details hidden by default. + +[Upgrading from 1.x](https://astn.github.io/JSON-RPC.NET/upgrading.html) covers every API and wire change, and +[What is new in 2.0](https://astn.github.io/JSON-RPC.NET/changelog.html) is the full changelog. + +## Documentation + +- [Server guide](https://astn.github.io/JSON-RPC.NET/) +- [Hosting](https://astn.github.io/JSON-RPC.NET/#hosting) +- [Configuration](https://astn.github.io/JSON-RPC.NET/#configuration) +- [Errors and exception handling](https://astn.github.io/JSON-RPC.NET/#errors) +- [Asynchronous methods and cancellation](https://astn.github.io/JSON-RPC.NET/#asynchronous-methods-and-cancellation) +- [Security and host responsibilities](https://astn.github.io/JSON-RPC.NET/#security) +- [What is new](https://astn.github.io/JSON-RPC.NET/changelog.html) +- [Upgrading from 1.x](https://astn.github.io/JSON-RPC.NET/upgrading.html) +- [Source repository](https://github.com/Astn/JSON-RPC.NET) +- [MIT license](https://github.com/Astn/JSON-RPC.NET/blob/master/LICENSE)