Skip to content

Add .Net Standard support - #90

Closed
Astn wants to merge 14 commits into
masterfrom
NetStandard
Closed

Astn wants to merge 14 commits into
masterfrom
NetStandard

Conversation

@Astn

@Astn Astn commented Jan 6, 2018 •

Copy link
Copy Markdown
Owner

This is for issue #89

Todo

Feel free to provide a pull request into this branch for any of the below.

  • Create AustinHarris.JsonRpc.Standard - Targets .Net Standard 2.0
  • Create TestServer_Console.Core - Targets .Net Core 2.0
  • Decouple main library from Json.Net and allow serialization to be injected.
  • Provide examples of getting setup with Json.net
  • Provide examples of getting setup with some alternative (Suggestions?)
  • Figure out the Nuget situation
  • Determine if we can target a lower version of .Net Standard or if it isn't worth the effort

@bonesoul

bonesoul commented Jan 6, 2018

Copy link
Copy Markdown
Collaborator

great work 👍

@Astn

Astn commented Jan 23, 2018

Copy link
Copy Markdown
Owner Author

Initial tests on my Ubuntu 17 workstation are looking promising.

  • E5-1650 v4 @ 3.60GHz
  • 64 GB Mem

During this run cpu topped out at ~ 50% cpu utilization. So there should still be some improvements that can be done.

Starting benchmark
processed 50 rpc in 2ms for 25000 rpc/sec
processed 100 rpc in 0ms for ∞ rpc/sec
processed 300 rpc in 0ms for ∞ rpc/sec
processed 1200 rpc in 4ms for 300000 rpc/sec
processed 6000 rpc in 28ms for 214285.714285714 rpc/sec
processed 36000 rpc in 162ms for 222222.222222222 rpc/sec
processed 252000 rpc in 798ms for 315789.473684211 rpc/sec
processed 2016000 rpc in 4912ms for 410423.45276873 rpc/sec
Finished benchmark...
Hit Enter to run benchmark
'c' to start reading console input
'q' to quit

@Astn Astn self-assigned this Jun 7, 2018
@Astn Astn mentioned this pull request Nov 15, 2018
@haakoo

haakoo commented May 2, 2019

Copy link
Copy Markdown

Any progress or time frame on this issue?

I'm building a .Net Core app (/service) and need to support clean JSON RPC (no headers), and would like to use a library and not roll my own.

@Astn

Astn commented May 3, 2019

Copy link
Copy Markdown
Owner Author

Any progress or time frame on this issue?

I'm building a .Net Core app (/service) and need to support clean JSON RPC (no headers), and would like to use a library and not roll my own.

Nothing recently. I could use a little help reviewing the code, and feedback on if it's ready a beta release.

@Astn

Astn commented Sep 23, 2026

Copy link
Copy Markdown
Owner Author

Superseded by #148, which finishes this upgrade on top of the current master (netstandard2.0/2.1, net8.0, net10.0) and carries it through to the 2.0 serializer redesign. Thanks for the groundwork here; the target list and the package split in #148 follow from it.

@Astn Astn closed this Sep 23, 2026
Astn added a commit that referenced this pull request Sep 23, 2026
…he .NET Standard upgrade from #90)

Finishes the .NET Standard upgrade from #90 (issue #89) on top of master and carries it through to a
2.0 release: a serializer-neutral, byte-first core with three serializer packages and a Kestrel host.

Targets and packaging: core, Newtonsoft and SystemTextJson packages target netstandard2.0, netstandard2.1,
net8.0 and net10.0; AspNetCore targets net8.0 and net10.0; netcoreapp3.1 dropped; SDK pinned by global.json.
CI builds the solution, runs the tests on both frameworks and packs all four packages (2.0.0).

Core: byte-first pipeline (JsonRpcProcessor.Process over ReadOnlySequence/Memory/Span<byte> into an
IBufferWriter<byte>; the string overloads transcode into it). Pluggable JsonRpcSerializer: the built-in
dependency-free serializer, AustinHarris.JsonRpc.Newtonsoft and AustinHarris.JsonRpc.SystemTextJson, resolved
per call, per session, then global, with one wire format fixed by the core. Parser hardening (depth limit,
strict grammar, UTF-8 validation, escaped member names, stable id echo) and dispatch hardening from an
independent review (notifications never answered, batches always arrays, pre-hook re-dispatch, per-invocation
context, hook error boundary, named-parameter validation, async return types rejected, exception details
redacted by default). Config.VersionPolicy for the jsonrpc member.

Hosting: AustinHarris.JsonRpc.AspNetCore with MapJsonRpc on PipeReader/BodyWriter and
JsonRpcConnectionHandler for raw TCP, Unix-socket and named-pipe connections; samples/WasmHost runs the server
inside the browser and benchmarks JSON-RPC against plain Blazor interop, interpreted and AOT.

Benchmarks: TestServer_Console gains sync, Task, Kestrel, compare (StreamJsonRpc and gRPC for .NET on the
same Kestrel) and sweep (every library and transport by connection count) modes. Charts are rendered in
light and dark from benchmarks/charts/benchmarks.json, the one data file behind the README tables, the SVGs
and the interactive explorer page (deployed to GitHub Pages); render.py --check keeps them in agreement in CI.
simdjson evaluated and rejected.

Docs: README rewritten (setup, hosting modes, configuration, benchmarks, upgrading from 1.x),
docs/serializers.md, the reviews and their fix passes in docs/reviews/.

Closes #89. Supersedes #90.
Astn added a commit that referenced this pull request Sep 23, 2026
…he .NET Standard upgrade from #90)

Finishes the .NET Standard upgrade from #90 (issue #89) on top of master and carries it through to a
2.0 release: a serializer-neutral, byte-first core with three serializer packages and a Kestrel host.

Targets and packaging: core, Newtonsoft and SystemTextJson packages target netstandard2.0, netstandard2.1,
net8.0 and net10.0; AspNetCore targets net8.0 and net10.0; netcoreapp3.1 dropped; SDK pinned by global.json.
CI builds the solution, runs the tests on both frameworks and packs all four packages (2.0.0).

Core: byte-first pipeline (JsonRpcProcessor.Process over ReadOnlySequence/Memory/Span<byte> into an
IBufferWriter<byte>; the string overloads transcode into it). Pluggable JsonRpcSerializer: the built-in
dependency-free serializer, AustinHarris.JsonRpc.Newtonsoft and AustinHarris.JsonRpc.SystemTextJson, resolved
per call, per session, then global, with one wire format fixed by the core. Parser hardening (depth limit,
strict grammar, UTF-8 validation, escaped member names, stable id echo) and dispatch hardening from an
independent review (notifications never answered, batches always arrays, pre-hook re-dispatch, per-invocation
context, hook error boundary, named-parameter validation, async return types rejected, exception details
redacted by default). Config.VersionPolicy for the jsonrpc member.

Hosting: AustinHarris.JsonRpc.AspNetCore with MapJsonRpc on PipeReader/BodyWriter and
JsonRpcConnectionHandler for raw TCP, Unix-socket and named-pipe connections; samples/WasmHost runs the server
inside the browser and benchmarks JSON-RPC against plain Blazor interop, interpreted and AOT.

Benchmarks: TestServer_Console gains sync, Task, Kestrel, compare (StreamJsonRpc and gRPC for .NET on the
same Kestrel) and sweep (every library and transport by connection count) modes. Charts are rendered in
light and dark from benchmarks/charts/benchmarks.json, the one data file behind the README tables, the SVGs
and the interactive explorer page (deployed to GitHub Pages); render.py --check keeps them in agreement in CI.
simdjson evaluated and rejected.

Docs: README rewritten (setup, hosting modes, configuration, benchmarks, upgrading from 1.x),
docs/serializers.md, the reviews and their fix passes in docs/reviews/.

Closes #89. Supersedes #90.
Astn added a commit that referenced this pull request Sep 23, 2026
…he .NET Standard upgrade from #90)

Finishes the .NET Standard upgrade from #90 (issue #89) on top of master and carries it through to a
2.0 release: a serializer-neutral, byte-first core with three serializer packages and a Kestrel host.

Targets and packaging: core, Newtonsoft and SystemTextJson packages target netstandard2.0, netstandard2.1,
net8.0 and net10.0; AspNetCore targets net8.0 and net10.0; netcoreapp3.1 dropped; SDK pinned by global.json.
CI builds the solution, runs the tests on both frameworks and packs all four packages (2.0.0).

Core: byte-first pipeline (JsonRpcProcessor.Process over ReadOnlySequence/Memory/Span<byte> into an
IBufferWriter<byte>; the string overloads transcode into it). Pluggable JsonRpcSerializer: the built-in
dependency-free serializer, AustinHarris.JsonRpc.Newtonsoft and AustinHarris.JsonRpc.SystemTextJson, resolved
per call, per session, then global, with one wire format fixed by the core. Parser hardening (depth limit,
strict grammar, UTF-8 validation, escaped member names, stable id echo) and dispatch hardening from an
independent review (notifications never answered, batches always arrays, pre-hook re-dispatch, per-invocation
context, hook error boundary, named-parameter validation, async return types rejected, exception details
redacted by default). Config.VersionPolicy for the jsonrpc member.

Open issues folded in: the request id is readable inside a method (Handler.RpcRequestId /
JsonRpcContext.CurrentRequestId, RpcRequestIdKind, RpcRequestIdRaw) from the invocation frame on demand, at
no cost to methods that do not ask (#56); a parameter value the serializer cannot convert is -32602 with
structured data naming the parameter instead of -32603 (#123); -32601 names the requested method in its
data and reaches the error handler on both paths (#145); async void methods are rejected at registration
and the synchronous contract is documented with the job-ticket pattern (#147); ServiceBinder.BindMethod
registers any delegate without attributes (#6).

Hosting: AustinHarris.JsonRpc.AspNetCore with MapJsonRpc on PipeReader/BodyWriter and
JsonRpcConnectionHandler for raw TCP, Unix-socket and named-pipe connections; samples/WasmHost runs the server
inside the browser and benchmarks JSON-RPC against plain Blazor interop, interpreted and AOT.

Benchmarks: TestServer_Console gains sync, Task, Kestrel, compare (StreamJsonRpc and gRPC for .NET on the
same Kestrel) and sweep (every library and transport by connection count) modes. Charts are rendered in
light and dark from benchmarks/charts/benchmarks.json, the one data file behind the README tables, the SVGs
and the interactive explorer page (deployed to GitHub Pages); render.py --check keeps them in agreement in CI.
simdjson evaluated and rejected.

Docs: README rewritten (setup, hosting modes, configuration, benchmarks, upgrading from 1.x),
docs/serializers.md, the reviews and their fix passes in docs/reviews/.

Closes #89. Supersedes #90.
Closes #56, #123, #145, #147, #6.
Closes #117, #68, #140, #131, #125, #10, #9 (already covered by the 2.0 core; verified against this branch).
Astn added a commit that referenced this pull request Sep 24, 2026
…he .NET Standard upgrade from #90)

Finishes the .NET Standard upgrade from #90 (issue #89) on top of master and carries it through to a
2.0 release: a serializer-neutral, byte-first core with three serializer packages and a Kestrel host.

Targets and packaging: core, Newtonsoft and SystemTextJson packages target netstandard2.0, netstandard2.1,
net8.0 and net10.0; AspNetCore targets net8.0 and net10.0; netcoreapp3.1 dropped; SDK pinned by global.json.
CI builds the solution, runs the tests on both frameworks and packs all four packages (2.0.0).

Core: byte-first pipeline (JsonRpcProcessor.Process over ReadOnlySequence/Memory/Span<byte> into an
IBufferWriter<byte>; the string overloads transcode into it). Pluggable JsonRpcSerializer: the built-in
dependency-free serializer, AustinHarris.JsonRpc.Newtonsoft and AustinHarris.JsonRpc.SystemTextJson, resolved
per call, per session, then global, with one wire format fixed by the core. Parser hardening (depth limit,
strict grammar, UTF-8 validation, escaped member names, stable id echo) and dispatch hardening from an
independent review (notifications never answered, batches always arrays, pre-hook re-dispatch, per-invocation
context, hook error boundary, named-parameter validation, async void rejected, exception details redacted
by default). Config.VersionPolicy for the jsonrpc member.

Open issues folded in: the request id is readable inside a method (Handler.RpcRequestId /
JsonRpcContext.CurrentRequestId, RpcRequestIdKind, RpcRequestIdRaw) from the invocation frame on demand, at
no cost to methods that do not ask (#56); a parameter value the serializer cannot convert is -32602 with
structured data naming the parameter instead of -32603 (#123); -32601 names the requested method in its
data and reaches the error handler on both paths (#145); ServiceBinder.BindMethod registers any delegate
without attributes (#6).

Asynchronous invocation (#147): JsonRpcProcessor.ProcessAsync (byte and string overloads) awaits Task,
Task<T>, ValueTask and ValueTask<T> methods with typed result writing, sequential ordered batches and
cooperative cancellation ([JsonRpcCancellation] receives the processor token). Completed operations run
inline and the byte overloads return Task.CompletedTask when the document completes inline. The synchronous
Process path is unchanged; it refuses an asynchronous registration with -32603 without invoking it, and
async void stays rejected at registration. RpcContextFlow.Flow (default) carries the ambient context, the
request id and RpcSetException across awaits; RpcContextFlow.None opts a method out for zero allocation on
the completed path. Kestrel gets JsonRpcOptions.EnableAsyncMethods for HTTP and ordered raw connections.

Interface binding (#130): ServiceBinder.BindInterface<TInterface>(sessionId, implementation, options)
registers an interface contract, including a tree of interface-typed properties, atomically and returns an
RpcBinding that unbinds it on Dispose. Names come from the contract ([JsonRpcMethod] aliases,
[JsonRpcParam], optional defaults) with Prefix, Separator, camel casing, an Include filter and a NameRule
override; implementation-only methods stay private. The tree is flattened and compiled at registration
through GetInterfaceMap with the receiver typed as the implementation, so interface-bound methods dispatch
at the same cost as class-bound ones. Task and ValueTask members are asynchronous registrations.

Hosting: AustinHarris.JsonRpc.AspNetCore with MapJsonRpc on PipeReader/BodyWriter and
JsonRpcConnectionHandler for raw TCP, Unix-socket and named-pipe connections; samples/WasmHost runs the server
inside the browser and benchmarks JSON-RPC against plain Blazor interop, interpreted and AOT.

Benchmarks: TestServer_Console gains sync, Task, Kestrel, compare (StreamJsonRpc and gRPC for .NET on the
same Kestrel) and sweep (every library and transport by connection count) modes. Charts are rendered in
light and dark from benchmarks/charts/benchmarks.json, the one data file behind the README tables, the SVGs
and the interactive explorer page (deployed to GitHub Pages); render.py --check keeps them in agreement in CI.
simdjson evaluated and rejected. benchmarks/Micro holds BenchmarkDotNet per-request timings with allocation
columns for class-bound, interface-bound and asynchronous dispatch.

Docs: README rewritten (setup, hosting modes, configuration, benchmarks, upgrading from 1.x),
docs/serializers.md, the reviews and their fix passes in docs/reviews/.

Closes #89. Supersedes #90.
Closes #56, #123, #145, #147, #130, #6.
Closes #117, #68, #140, #131, #125, #10, #9 (already covered by the 2.0 core; verified against this branch).
Astn added a commit that referenced this pull request Sep 24, 2026
…he .NET Standard upgrade from #90)

Finishes the .NET Standard upgrade from #90 (issue #89) on top of master and carries it through to a
2.0 release: a serializer-neutral, byte-first core with three serializer packages and a Kestrel host.

Targets and packaging: core, Newtonsoft and SystemTextJson packages target netstandard2.0, netstandard2.1,
net8.0 and net10.0; AspNetCore targets net8.0 and net10.0; netcoreapp3.1 dropped; SDK pinned by global.json.
CI builds the solution, runs the tests on both frameworks and packs all four packages (2.0.0).

Core: byte-first pipeline (JsonRpcProcessor.Process over ReadOnlySequence/Memory/Span<byte> into an
IBufferWriter<byte>; the string overloads transcode into it). Pluggable JsonRpcSerializer: the built-in
dependency-free serializer, AustinHarris.JsonRpc.Newtonsoft and AustinHarris.JsonRpc.SystemTextJson, resolved
per call, per session, then global, with one wire format fixed by the core. Parser hardening (depth limit,
strict grammar, UTF-8 validation, escaped member names, stable id echo) and dispatch hardening from an
independent review (notifications never answered, batches always arrays, pre-hook re-dispatch, per-invocation
context, hook error boundary, named-parameter validation, async void rejected, exception details redacted
by default). Config.VersionPolicy for the jsonrpc member.

Open issues folded in: the request id is readable inside a method (Handler.RpcRequestId /
JsonRpcContext.CurrentRequestId, RpcRequestIdKind, RpcRequestIdRaw) from the invocation frame on demand, at
no cost to methods that do not ask (#56); a parameter value the serializer cannot convert is -32602 with
structured data naming the parameter instead of -32603 (#123); -32601 names the requested method in its
data and reaches the error handler on both paths (#145); ServiceBinder.BindMethod registers any delegate
without attributes (#6).

Asynchronous invocation (#147): JsonRpcProcessor.ProcessAsync (byte and string overloads) awaits Task,
Task<T>, ValueTask and ValueTask<T> methods with typed result writing, sequential ordered batches and
cooperative cancellation ([JsonRpcCancellation] receives the processor token). Completed operations run
inline and the byte overloads return Task.CompletedTask when the document completes inline. The synchronous
Process path is unchanged; it refuses an asynchronous registration with -32603 without invoking it, and
async void stays rejected at registration. RpcContextFlow.None (default) keeps the ambient context for the
synchronous part of the method and costs nothing extra on the completed path; RpcContextFlow.Flow opts a
method in to the context, the request id and RpcSetException across awaits, at a per-invocation allocation. Kestrel gets JsonRpcOptions.EnableAsyncMethods for HTTP and ordered raw connections.

Interface binding (#130): ServiceBinder.BindInterface<TInterface>(sessionId, implementation, options)
registers an interface contract, including a tree of interface-typed properties, atomically and returns an
RpcBinding that unbinds it on Dispose. Names come from the contract ([JsonRpcMethod] aliases,
[JsonRpcParam], optional defaults) with Prefix, Separator, camel casing, an Include filter and a NameRule
override; implementation-only methods stay private. The tree is flattened and compiled at registration
through GetInterfaceMap with the receiver typed as the implementation, so interface-bound methods dispatch
at the same cost as class-bound ones. Task and ValueTask members are asynchronous registrations.

Hosting: AustinHarris.JsonRpc.AspNetCore with MapJsonRpc on PipeReader/BodyWriter and
JsonRpcConnectionHandler for raw TCP, Unix-socket and named-pipe connections; samples/WasmHost runs the server
inside the browser and benchmarks JSON-RPC against plain Blazor interop, interpreted and AOT.

Benchmarks: TestServer_Console gains sync, Task, Kestrel, compare (StreamJsonRpc and gRPC for .NET on the
same Kestrel) and sweep (every library and transport by connection count) modes. Charts are rendered in
light and dark from benchmarks/charts/benchmarks.json, the one data file behind the README tables, the SVGs
and the interactive explorer page (deployed to GitHub Pages); render.py --check keeps them in agreement in CI.
simdjson evaluated and rejected. benchmarks/Micro holds BenchmarkDotNet per-request timings with allocation
columns for class-bound, interface-bound and asynchronous dispatch.

Docs: README rewritten (setup, hosting modes, configuration, benchmarks, upgrading from 1.x),
docs/serializers.md, the reviews and their fix passes in docs/reviews/.

Closes #89. Supersedes #90.
Closes #56, #123, #145, #147, #130, #6.
Closes #117, #68, #140, #131, #125, #10, #9 (already covered by the 2.0 core; verified against this branch).
Astn added a commit that referenced this pull request Sep 24, 2026
2.0: byte-first core, pluggable serializers, Kestrel host (finishes the .NET Standard upgrade from #90)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants