AustinHarris.JsonRpc
2.0.1
dotnet add package AustinHarris.JsonRpc --version 2.0.1
NuGet\Install-Package AustinHarris.JsonRpc -Version 2.0.1
<PackageReference Include="AustinHarris.JsonRpc" Version="2.0.1" />
<PackageVersion Include="AustinHarris.JsonRpc" Version="2.0.1" />
<PackageReference Include="AustinHarris.JsonRpc" />
paket add AustinHarris.JsonRpc --version 2.0.1
#r "nuget: AustinHarris.JsonRpc, 2.0.1"
#:package AustinHarris.JsonRpc@2.0.1
#addin nuget:?package=AustinHarris.JsonRpc&version=2.0.1
#tool nuget:?package=AustinHarris.JsonRpc&version=2.0.1
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.
The built-in tokenizer is a port of jsmn by Serge A. Zaitsev (MIT); the notice ships in the package as THIRD-PARTY-NOTICES.txt.
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
dotnet add package AustinHarris.JsonRpc
Coming from 1.x? Read What is new in 2.0 and Upgrading from 1.x first.
Getting started
Declare a service
Save this as server.cs, a .NET 10 file-based app: one C# file with no project file.
The #:sdk and #:package directives select the web SDK and package.
ServiceBinder.BindMethod registers lambdas served by Kestrel at /rpc.
#:sdk Microsoft.NET.Sdk.Web
#:package AustinHarris.JsonRpc.AspNetCore@2.0.1
using AustinHarris.JsonRpc;
using AustinHarris.JsonRpc.AspNetCore;
ServiceBinder.BindMethod("add", (double l, double r) => l + r);
ServiceBinder.BindMethod("greet", (string who) => "hello " + who);
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddJsonRpc();
var app = builder.Build();
app.MapJsonRpc("/rpc");
app.Run();
Run dotnet run server.cs; Kestrel prints its listening URL.
Use dotnet run server.cs -- --urls http://127.0.0.1:5077 to pin it for this request from another terminal:
curl -s -X POST http://127.0.0.1:5077/rpc -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"add","params":[1,2],"id":1}'
{"jsonrpc":"2.0","result":3.0,"id":1}
On .NET 8, use the same code in Program.cs in an ordinary ASP.NET Core project, install with dotnet add package AustinHarris.JsonRpc.AspNetCore, and drop the two #: lines.
For a service class, create CalculatorService.cs.
Derive from JsonRpcService and mark exposed methods with [JsonRpcMethod].
Constructing the service registers its methods in the default session.
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.
Optional parameter defaults are honoured; [JsonRpcParam("name")] overrides a parameter's JSON name.
Keep the service instance alive; it serves concurrent requests, so its state must be thread-safe.
Both examples use the default session (Handler.DefaultSessionId()).
Lambdas and classes can be mixed in one session when their method names differ; both examples register add, so keep one of them.
The next step drives CalculatorService in process, without a transport.
A method is a callable identified by the method member of a request; its implementation is a delegate, a [JsonRpcMethod] member of a class, or a member of a bound interface.
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.
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.
var output = new ArrayBufferWriter<byte>();
JsonRpcProcessor.Process(Handler.DefaultSessionId(), """{"method":"add","params":[2,3],"id":3}"""u8, 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:
{"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.
A """..."""u8 literal is a ReadOnlySpan<byte> (C# 11 and later).
A bare byte[] is ambiguous between the memory and span overloads on C# 12 and 13; pass it as AsSpan() there.
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 benchmark job.
The 2.0 runs used the built-in serializer on a Hugging Face Jobs cpu-performance host (AMD EPYC 7R13, 32 cores) with .NET 10, Release and Server GC.
Each range is the low and high over the job's runs; the ratios are of the medians.
| Path | RPC/s | Against 1.2.3 |
|---|---|---|
1.2.3, Task<string> Process(string), thread pool, best batch size |
1.29 M to 2.41 M | |
| 2.0, the same string API and the same loop | 9.83 M to 11.1 M | 6.0× |
2.0, Process(bytes), 32 dedicated threads |
44.2 M to 45.7 M | 24.3× |
2.0, ProcessAsync(bytes), 32 awaited workers |
36.3 M to 40.5 M | 20.7× |
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 figure is 18.5 M RPC/s on loopback, with clients and server on the same machine.
See the benchmark tables for conditions and the benchmark explorer for the data.
Companion packages
Install only the integrations your host needs. Use matching package versions.
AustinHarris.JsonRpc.Newtonsoft: Json.NET converters, contract resolvers,[JsonProperty],JsonSerializerSettingsand lenient input.AustinHarris.JsonRpc.SystemTextJson:System.Text.Jsonconversion withJsonSerializerOptions, reading and writing UTF-8 values.AustinHarris.JsonRpc.AspNetCore: 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
JsonSerializerSettingsand settings-based compatibility helpers;JsonRequest.Paramsfollows the selected serializer's object model. - Review string overloads, especially calls with a positional null context.
Name the
contextargument 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 covers every API and wire change, and What is new in 2.0 is the full changelog.
Documentation
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Memory (>= 4.6.3)
- System.Threading.Tasks.Extensions (>= 4.5.0)
-
.NETStandard 2.1
- No dependencies.
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (4)
Showing the top 4 NuGet packages that depend on AustinHarris.JsonRpc:
| Package | Downloads |
|---|---|
|
Casper.Net.Sdk
C# SDK For the Casper Network |
|
|
AustinHarris.JsonRpc.SystemTextJson
System.Text.Json serializer for AustinHarris.JsonRpc. Reads UTF-8 parameters and writes results directly to the response buffer, configured with JsonSerializerOptions. |
|
|
AustinHarris.JsonRpc.Newtonsoft
Json.NET serializer for AustinHarris.JsonRpc. Uses JsonSerializerSettings for converters, contract resolvers and lenient JSON input. |
|
|
AustinHarris.JsonRpc.AspNetCore
ASP.NET Core hosting for AustinHarris.JsonRpc. Adds HTTP endpoints and raw Kestrel connections over TCP, Unix sockets and named pipes, with dependency injection. |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on AustinHarris.JsonRpc:
| Repository | Stars |
|---|---|
|
bonesoul/CoiniumServ
Next-gen crypto currency mining pool software
|
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.1 | 194 | 9/28/2026 |
| 2.0.0 | 169 | 9/28/2026 |
| 2.0.0-preview.3 | 73 | 9/28/2026 |
| 2.0.0-preview.2 | 66 | 9/28/2026 |
| 2.0.0-preview.1 | 66 | 9/25/2026 |
| 1.2.3 | 59,151 | 9/11/2021 |
| 1.2.2 | 31,384 | 5/22/2020 |
| 1.2.2-ci-112095285-8 | 631 | 5/22/2020 |
| 1.2.1.2 | 852 | 5/22/2020 |
| 1.2.1.2-ci-111992021-7 | 614 | 5/22/2020 |
| 1.2.0.1 | 1,932 | 5/1/2020 |
| 1.2.0.1-ci-92709240-5 | 667 | 5/1/2020 |
| 1.2.0.1-ci-92708299-4 | 654 | 5/1/2020 |
| 1.2.0.1-ci-92695812-2 | 638 | 5/1/2020 |
| 1.2.0.1-ci-92679453-22 | 658 | 5/1/2020 |
| 1.2.0.1-ci-111987561-6 | 617 | 5/22/2020 |
| 1.1.70 | 58,332 | 7/31/2017 |
| 1.1.63 | 90,032 | 11/6/2016 |
| 1.1.62 | 1,647 | 11/6/2016 |
| 1.0.4.52 | 33,770 | 11/6/2016 |
2.0.1: adds the jsmn copyright and permission notice (THIRD-PARTY-NOTICES.txt) to the package; no code change. 2.0.0: the request pipeline is built around UTF-8 bytes (ReadOnlySequence, ReadOnlyMemory or ReadOnlySpan in, IBufferWriter out), the JSON serializer is pluggable with the built-in serializer as the default and Json.NET and System.Text.Json as packages, and Task and ValueTask methods are supported again through ProcessAsync with cooperative cancellation. Document and batch limits are on by default (JsonRpcLimits), reserved method names are refused at registration, unknown named parameters are rejected, an error handler receives the exception the method threw, and the four assemblies are strong-named with one key that stays fixed from here on. Six times the throughput of 1.2.3 through the 1.x string API and twenty-four times through the byte entry points, measured on a 32-core Hugging Face Jobs host (see the README). InProcessClient is removed; three legacy members are obsolete at warning level with diagnostic ids JSONRPC0001 to JSONRPC0003. 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