├── .azuredevops
└── dependabot.yml
├── .config
└── dotnet-tools.json
├── .devcontainer
├── Dockerfile
└── devcontainer.json
├── .editorconfig
├── .gitattributes
├── .github
├── .editorconfig
├── actions
│ └── publish-artifacts
│ │ └── action.yaml
├── renovate.json
└── workflows
│ ├── docs.yml
│ ├── docs_validate.yml
│ └── libtemplate-update.yml
├── .gitignore
├── .prettierrc.yaml
├── .vscode
├── extensions.json
├── settings.json
└── tasks.json
├── BannedSymbols.txt
├── CONTRIBUTING.md
├── Directory.Build.props
├── Directory.Build.rsp
├── Directory.Build.targets
├── Directory.Packages.props
├── LICENSE
├── README.md
├── SECURITY.md
├── StreamJsonRpc.sln
├── azure-pipelines.yml
├── azure-pipelines
├── Archive-SourceCode.ps1
├── BuildStageVariables.yml
├── CredScanSuppressions.json
├── Get-InsertionPRId.ps1
├── GlobalVariables.yml
├── Install-NuGetPackage.ps1
├── Merge-CodeCoverage.ps1
├── NuGetSbom.props
├── OptProf.yml
├── OptProf_part2.yml
├── PoliCheckExclusions.xml
├── PostPRMessage.ps1
├── TSAOptions.json
├── WIFtoPATauth.yml
├── apiscan.yml
├── archive-sourcecode.yml
├── build.yml
├── dotnet.yml
├── falsepositives.gdnsuppress
├── install-dependencies.yml
├── libtemplate-update.yml
├── microbuild.after.yml
├── microbuild.before.yml
├── no_authenticode.txt
├── no_strongname.txt
├── official.yml
├── prepare-insertion-stages.yml
├── publish-codecoverage.yml
├── publish-symbols.yml
├── publish_artifacts.ps1
├── release-deployment-prep.yml
├── release.yml
├── schedule-only-steps.yml
├── unofficial.yml
├── vs-insertion.yml
└── vs-validation.yml
├── azurepipelines-coverage.yml
├── docfx
├── .gitignore
├── docfx.json
├── docs
│ ├── connecting.md
│ ├── disconnecting.md
│ ├── dynamicproxy.md
│ ├── exceptions.md
│ ├── extensibility.md
│ ├── getting-started.md
│ ├── joinableTaskFactory.md
│ ├── recvrequest.md
│ ├── remotetargets.md
│ ├── resiliency.md
│ ├── security.md
│ ├── sendrequest.md
│ ├── testing.md
│ ├── toc.yml
│ ├── tracecontext.md
│ ├── troubleshooting.md
│ └── vs.md
├── exotic_types
│ ├── asyncenumerable.md
│ ├── disposable.md
│ ├── general_marshaled_objects.md
│ ├── general_marshaled_objects_2.md
│ ├── index.md
│ ├── observer.md
│ ├── oob_streams.md
│ ├── progresssupport.md
│ ├── rpc_marshalable_objects.md
│ └── toc.yml
├── index.md
└── toc.yml
├── global.json
├── init.cmd
├── init.ps1
├── loc
└── lcl
│ ├── CHS
│ └── StreamJsonRpc.dll.lcl
│ ├── CHT
│ └── StreamJsonRpc.dll.lcl
│ ├── CSY
│ └── StreamJsonRpc.dll.lcl
│ ├── DEU
│ └── StreamJsonRpc.dll.lcl
│ ├── ESN
│ └── StreamJsonRpc.dll.lcl
│ ├── FRA
│ └── StreamJsonRpc.dll.lcl
│ ├── ITA
│ └── StreamJsonRpc.dll.lcl
│ ├── JPN
│ └── StreamJsonRpc.dll.lcl
│ ├── KOR
│ └── StreamJsonRpc.dll.lcl
│ ├── PLK
│ └── StreamJsonRpc.dll.lcl
│ ├── PTB
│ └── StreamJsonRpc.dll.lcl
│ ├── RUS
│ └── StreamJsonRpc.dll.lcl
│ └── TRK
│ └── StreamJsonRpc.dll.lcl
├── nuget.config
├── settings.VisualStudio.json
├── src
├── .editorconfig
├── AssemblyInfo.cs
├── AssemblyInfo.vb
├── Directory.Build.props
├── Directory.Build.targets
├── OptProf.targets
├── PackageIcon.png
├── StreamJsonRpc
│ ├── ActivityTracingStrategy.cs
│ ├── AwaitExtensions.cs
│ ├── CommonMethodNameTransforms.cs
│ ├── CorrelationManagerTracingStrategy.cs
│ ├── DisposableAction.cs
│ ├── EventArgs
│ │ ├── DisconnectedReason.cs
│ │ └── JsonRpcDisconnectedEventArgs.cs
│ ├── ExceptionProcessing.cs
│ ├── ExceptionSettings.cs
│ ├── Exceptions
│ │ ├── BadRpcHeaderException.cs
│ │ ├── ConnectionLostException.cs
│ │ ├── LocalRpcException.cs
│ │ ├── RemoteInvocationException.cs
│ │ ├── RemoteMethodNotFoundException.cs
│ │ ├── RemoteRpcException.cs
│ │ ├── RemoteSerializationException.cs
│ │ ├── RpcArgumentDeserializationException.cs
│ │ ├── UnexpectedEmptyEnumerableResponseException.cs
│ │ └── UnrecognizedJsonRpcMessageException.cs
│ ├── FormatterBase.cs
│ ├── HeaderDelimitedMessageHandler.cs
│ ├── Hex.cs
│ ├── IActivityTracingStrategy.cs
│ ├── ICancellationStrategy.cs
│ ├── IJsonRpcAsyncMessageFormatter.cs
│ ├── IJsonRpcAsyncMessageTextFormatter.cs
│ ├── IJsonRpcClientProxy.cs
│ ├── IJsonRpcClientProxyInternal.cs
│ ├── IJsonRpcInstanceContainer.cs
│ ├── IJsonRpcMessageFactory.cs
│ ├── IJsonRpcMessageFormatter.cs
│ ├── IJsonRpcMessageHandler.cs
│ ├── IJsonRpcMessageTextFormatter.cs
│ ├── IRpcMarshaledContext.cs
│ ├── JsonMessageFormatter.cs
│ ├── JsonRpc.cs
│ ├── JsonRpcEnumerableSettings.cs
│ ├── JsonRpcEventSource.cs
│ ├── JsonRpcExtensions.cs
│ ├── JsonRpcProxyOptions.cs
│ ├── JsonRpcTargetOptions.cs
│ ├── LengthHeaderMessageHandler.cs
│ ├── MessageHandlerBase.cs
│ ├── MessagePackFormatter.cs
│ ├── NewLineDelimitedMessageHandler.cs
│ ├── OptProf.targets
│ ├── PipeMessageHandler.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Protocol
│ │ ├── CommonErrorData.cs
│ │ ├── Constants.cs
│ │ ├── IJsonRpcMessageWithId.cs
│ │ ├── JsonRpcError.cs
│ │ ├── JsonRpcErrorCode.cs
│ │ ├── JsonRpcMessage.cs
│ │ ├── JsonRpcRequest.cs
│ │ ├── JsonRpcResult.cs
│ │ └── TraceParent.cs
│ ├── ProxyGeneration.cs
│ ├── README.md
│ ├── Reflection
│ │ ├── CodeGenHelpers.cs
│ │ ├── ExceptionSerializationHelpers.cs
│ │ ├── IJsonRpcFormatterCallbacks.cs
│ │ ├── IJsonRpcFormatterState.cs
│ │ ├── IJsonRpcFormatterTracingCallbacks.cs
│ │ ├── IJsonRpcMessageBufferManager.cs
│ │ ├── IJsonRpcTracingCallbacks.cs
│ │ ├── JsonRpcIgnoreAttribute.cs
│ │ ├── JsonRpcMessageEventArgs.cs
│ │ ├── JsonRpcMethodAttribute.cs
│ │ ├── JsonRpcResponseEventArgs.cs
│ │ ├── MessageFormatterDuplexPipeTracker.cs
│ │ ├── MessageFormatterEnumerableTracker.cs
│ │ ├── MessageFormatterProgressTracker.cs
│ │ ├── MessageFormatterRpcMarshaledContextTracker.cs
│ │ ├── MethodSignature.cs
│ │ ├── MethodSignatureAndTarget.cs
│ │ ├── RpcMarshalableAttribute.cs
│ │ ├── RpcMarshalableOptionalInterfaceAttribute.cs
│ │ ├── RpcTargetInfo.cs
│ │ ├── TargetMethod.cs
│ │ └── TrackerHelpers.cs
│ ├── RequestId.cs
│ ├── RequestIdJsonConverter.cs
│ ├── Resources.resx
│ ├── RpcMarshaledContext.cs
│ ├── SharedUtilities.cs
│ ├── SkipClrVisibilityChecks.cs
│ ├── StandardCancellationStrategy.cs
│ ├── StreamJsonRpc.csproj
│ ├── StreamMessageHandler.cs
│ ├── SystemTextJsonFormatter.cs
│ ├── Utilities.cs
│ ├── WebSocketMessageHandler.cs
│ ├── net8.0
│ │ ├── PublicAPI.Shipped.txt
│ │ └── PublicAPI.Unshipped.txt
│ ├── netstandard2.0
│ │ ├── PublicAPI.Shipped.txt
│ │ └── PublicAPI.Unshipped.txt
│ └── netstandard2.1
│ │ ├── PublicAPI.Shipped.txt
│ │ └── PublicAPI.Unshipped.txt
└── VSInsertionMetadata
│ ├── ProfilingInputs.props
│ ├── StreamJsonRpc.VSInsertionMetadata.proj
│ └── VSInsertionMetadata.targets
├── stylecop.json
├── test
├── .editorconfig
├── Benchmarks
│ ├── .gitignore
│ ├── Benchmarks.csproj
│ ├── InvokeBenchmarks.cs
│ ├── NotifyBenchmarks.cs
│ ├── Program.cs
│ ├── ShortLivedConnectionBenchmarks.cs
│ └── run.cmd
├── Directory.Build.props
├── Directory.Build.targets
├── StreamJsonRpc.Tests.ExternalAssembly
│ ├── AssemblyInfo.cs
│ ├── IInternalGenericInterface.cs
│ ├── IPublicNestedInInternalInterface.cs
│ ├── ISomeInternalProxyInterface.cs
│ ├── InternalStruct.cs
│ ├── SomeOtherInternalType.cs
│ └── StreamJsonRpc.Tests.ExternalAssembly.csproj
└── StreamJsonRpc.Tests
│ ├── .editorconfig
│ ├── ActivityTracingStrategyTests.cs
│ ├── AssemblyLoadTests.cs
│ ├── AsyncEnumerableJsonTests.cs
│ ├── AsyncEnumerableJsonTypeHandlingTests.cs
│ ├── AsyncEnumerableMessagePackTests.cs
│ ├── AsyncEnumerableSystemTextJsonTests.cs
│ ├── AsyncEnumerableTests.cs
│ ├── CollectingTraceListener.cs
│ ├── CommonErrorDataTests.cs
│ ├── CommonMethodNameTransformsTests.cs
│ ├── CorrelationManagerTracingStrategyTests.cs
│ ├── CustomCancellationStrategyJsonTypeHandlingTests.cs
│ ├── CustomCancellationStrategyTests.cs
│ ├── DirectMessageHandler.cs
│ ├── DisposableProxyJsonTests.cs
│ ├── DisposableProxyMessagePackTests.cs
│ ├── DisposableProxySystemTextJsonTests.cs
│ ├── DisposableProxyTests.cs
│ ├── DuplexPipeMarshalingJsonTests.cs
│ ├── DuplexPipeMarshalingMessagePackTests.cs
│ ├── DuplexPipeMarshalingSystemTextJsonTests.cs
│ ├── DuplexPipeMarshalingTests.cs
│ ├── ExceptionSettingsTests.cs
│ ├── Exceptions
│ ├── RemoteInvocationExceptionTests.cs
│ └── RpcArgumentDeserializationExceptionTests.cs
│ ├── FormatterTestBase.cs
│ ├── FullDuplexStream.cs
│ ├── HeaderDelimitedMessageHandlerTests.cs
│ ├── InteropTestBase.cs
│ ├── JsonContractResolverTests.cs
│ ├── JsonMessageFormatterTests.cs
│ ├── JsonRpcClient10InteropTests.cs
│ ├── JsonRpcClient20InteropJsonTypeHandlingTests.cs
│ ├── JsonRpcClient20InteropTests.cs
│ ├── JsonRpcCustomRequestIdTests.cs
│ ├── JsonRpcDelegatedDispatchAndSendTests.cs
│ ├── JsonRpcEnumerableSettingsTests.cs
│ ├── JsonRpcExtensionsTests.cs
│ ├── JsonRpcJsonHeadersTests.cs
│ ├── JsonRpcJsonHeadersTypeHandlingTests.cs
│ ├── JsonRpcMessagePackLengthTests.cs
│ ├── JsonRpcMethodAttributeTests.cs
│ ├── JsonRpcProxyGenerationTests.cs
│ ├── JsonRpcRawStreamTests.cs
│ ├── JsonRpcRemoteTargetJsonMessageFormatterTests.cs
│ ├── JsonRpcRemoteTargetMessagePackFormatterTests.cs
│ ├── JsonRpcRemoteTargetSystemTextJsonFormatterTests.cs
│ ├── JsonRpcRemoteTargetTests.cs
│ ├── JsonRpcServerInteropTests.cs
│ ├── JsonRpcSystemTextJsonHeadersTests.cs
│ ├── JsonRpcTargetOptionsTests.cs
│ ├── JsonRpcTests.cs
│ ├── JsonRpcWithFatalExceptionsTests.cs
│ ├── JsonRpcWithMessageFactoryTests.cs
│ ├── LengthHeaderMessageHandlerTests.cs
│ ├── LocalRpcExceptionTests.cs
│ ├── MarshalableProxyJsonTests.cs
│ ├── MarshalableProxyMessagePackTests.cs
│ ├── MarshalableProxySystemTextJsonTests.cs
│ ├── MarshalableProxyTests.cs
│ ├── MessageHeaderTests.cs
│ ├── MessagePackFormatterTests.cs
│ ├── NewLineDelimitedMessageHandlerTests.cs
│ ├── ObserverMarshalingJsonTests.cs
│ ├── ObserverMarshalingMessagePackTests.cs
│ ├── ObserverMarshalingSystemTextJsonTests.cs
│ ├── ObserverMarshalingTests.cs
│ ├── PerfTests.cs
│ ├── Protocol
│ └── JsonRpcRequestTests.cs
│ ├── RequestIdTests.cs
│ ├── RpcOrderPreservingSynchronizationContext.cs
│ ├── Samples
│ └── HttpClientMessageHandler.cs
│ ├── SpecialCaseTests.cs
│ ├── StreamJsonRpc.Tests.csproj
│ ├── StreamMessageHandlerTests.cs
│ ├── SystemTextJsonFormatterTests.cs
│ ├── TargetObjectEventsJsonTests.cs
│ ├── TargetObjectEventsMessagePackTests.cs
│ ├── TargetObjectEventsSystemTextJsonTests.cs
│ ├── TargetObjectEventsTests.cs
│ ├── TestBase.cs
│ ├── Usings.cs
│ ├── WebSocketMessageHandlerJsonTests.cs
│ ├── WebSocketMessageHandlerMessagePackTests.cs
│ ├── WebSocketMessageHandlerSystemTextJsonTests.cs
│ ├── WebSocketMessageHandlerTests.cs
│ ├── WrappedStream.cs
│ ├── XunitTraceListener.cs
│ └── xunit.runner.json
├── tools
├── Check-DotNetRuntime.ps1
├── Check-DotNetSdk.ps1
├── Convert-PDB.ps1
├── Get-ArtifactsStagingDirectory.ps1
├── Get-CodeCovTool.ps1
├── Get-LibTemplateBasis.ps1
├── Get-NuGetTool.ps1
├── Get-ProcDump.ps1
├── Get-SymbolFiles.ps1
├── Get-TempToolsPath.ps1
├── Install-DotNetSdk.ps1
├── Install-NuGetCredProvider.ps1
├── MergeFrom-Template.ps1
├── Prepare-Legacy-Symbols.ps1
├── Set-EnvVars.ps1
├── artifacts
│ ├── APIScanInputs.ps1
│ ├── LocBin.ps1
│ ├── VSInsertion.ps1
│ ├── Variables.ps1
│ ├── _all.ps1
│ ├── _stage_all.ps1
│ ├── build_logs.ps1
│ ├── coverageResults.ps1
│ ├── deployables.ps1
│ ├── projectAssetsJson.ps1
│ ├── symbols.ps1
│ ├── testResults.ps1
│ └── test_symbols.ps1
├── dotnet-test-cloud.ps1
├── publish-CodeCov.ps1
├── test.runsettings
└── variables
│ ├── BusinessGroupName.ps1
│ ├── DotNetSdkVersion.ps1
│ ├── FailsOnMonoFilter.ps1
│ ├── InsertJsonValues.ps1
│ ├── InsertPropsValues.ps1
│ ├── InsertTargetBranch.ps1
│ ├── InsertVersionsValues.ps1
│ ├── LocLanguages.ps1
│ ├── ProfilingInputsDropName.ps1
│ ├── ShouldSkipOptimize.ps1
│ ├── SymbolsFeatureName.ps1
│ ├── VstsDropNames.ps1
│ ├── _all.ps1
│ └── _define.ps1
└── version.json
/.azuredevops/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Please see the documentation for all configuration options:
2 | # https://eng.ms/docs/products/dependabot/configuration/version_updates
3 |
4 | version: 2
5 | updates:
6 | - package-ecosystem: nuget
7 | directory: /
8 | schedule:
9 | interval: monthly
10 |
--------------------------------------------------------------------------------
/.config/dotnet-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "isRoot": true,
4 | "tools": {
5 | "powershell": {
6 | "version": "7.5.0",
7 | "commands": [
8 | "pwsh"
9 | ],
10 | "rollForward": false
11 | },
12 | "dotnet-coverage": {
13 | "version": "17.14.2",
14 | "commands": [
15 | "dotnet-coverage"
16 | ],
17 | "rollForward": false
18 | },
19 | "nbgv": {
20 | "version": "3.7.115",
21 | "commands": [
22 | "nbgv"
23 | ],
24 | "rollForward": false
25 | },
26 | "docfx": {
27 | "version": "2.78.3",
28 | "commands": [
29 | "docfx"
30 | ],
31 | "rollForward": false
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/.devcontainer/Dockerfile:
--------------------------------------------------------------------------------
1 | # Refer to https://hub.docker.com/_/microsoft-dotnet-sdk for available versions
2 | FROM mcr.microsoft.com/dotnet/sdk:9.0.203-noble@sha256:2c9a4956a61fc45d9111fb36ec9fb86932e4842af9eb9bc9306bf8757f53674d
3 |
4 | # Installing mono makes `dotnet test` work without errors even for net472.
5 | # But installing it takes a long time, so it's excluded by default.
6 | #RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
7 | #RUN echo "deb https://download.mono-project.com/repo/ubuntu stable-bionic main" | tee /etc/apt/sources.list.d/mono-official-stable.list
8 | #RUN apt-get update
9 | #RUN DEBIAN_FRONTEND=noninteractive apt-get install -y mono-devel
10 |
11 | # Clear the NUGET_XMLDOC_MODE env var so xml api doc files get unpacked, allowing a rich experience in Intellisense.
12 | # See https://github.com/dotnet/dotnet-docker/issues/2790 for a discussion on this, where the prioritized use case
13 | # was *not* devcontainers, sadly.
14 | ENV NUGET_XMLDOC_MODE=
15 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Dev space",
3 | "dockerFile": "Dockerfile",
4 | "customizations": {
5 | "vscode": {
6 | "settings": {
7 | "terminal.integrated.shell.linux": "/usr/bin/pwsh"
8 | },
9 | "extensions": [
10 | "ms-azure-devops.azure-pipelines",
11 | "ms-dotnettools.csharp",
12 | "k--kato.docomment",
13 | "editorconfig.editorconfig",
14 | "esbenp.prettier-vscode",
15 | "pflannery.vscode-versionlens",
16 | "davidanson.vscode-markdownlint",
17 | "dotjoshjohnson.xml",
18 | "ms-vscode-remote.remote-containers",
19 | "ms-azuretools.vscode-docker",
20 | "tintoy.msbuild-project-tools"
21 | ]
22 | }
23 | },
24 | "postCreateCommand": "./init.ps1 -InstallLocality machine"
25 | }
26 |
--------------------------------------------------------------------------------
/.github/.editorconfig:
--------------------------------------------------------------------------------
1 | [renovate.json*]
2 | indent_style = tab
3 |
--------------------------------------------------------------------------------
/.github/actions/publish-artifacts/action.yaml:
--------------------------------------------------------------------------------
1 | name: Publish artifacts
2 | description: Publish artifacts
3 |
4 | runs:
5 | using: composite
6 | steps:
7 | - name: 📥 Collect artifacts
8 | run: tools/artifacts/_stage_all.ps1
9 | shell: pwsh
10 | if: always()
11 |
12 | # TODO: replace this hard-coded list with a loop that utilizes the NPM package at
13 | # https://github.com/actions/toolkit/tree/main/packages/artifact (or similar) to push the artifacts.
14 |
15 | - name: 📢 Upload project.assets.json files
16 | if: always()
17 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
18 | with:
19 | name: projectAssetsJson-${{ runner.os }}
20 | path: ${{ runner.temp }}/_artifacts/projectAssetsJson
21 | continue-on-error: true
22 | - name: 📢 Upload variables
23 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
24 | with:
25 | name: variables-${{ runner.os }}
26 | path: ${{ runner.temp }}/_artifacts/Variables
27 | continue-on-error: true
28 | - name: 📢 Upload build_logs
29 | if: always()
30 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
31 | with:
32 | name: build_logs-${{ runner.os }}
33 | path: ${{ runner.temp }}/_artifacts/build_logs
34 | continue-on-error: true
35 | - name: 📢 Upload testResults
36 | if: always()
37 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
38 | with:
39 | name: testResults-${{ runner.os }}
40 | path: ${{ runner.temp }}/_artifacts/testResults
41 | continue-on-error: true
42 | - name: 📢 Upload coverageResults
43 | if: always()
44 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
45 | with:
46 | name: coverageResults-${{ runner.os }}
47 | path: ${{ runner.temp }}/_artifacts/coverageResults
48 | continue-on-error: true
49 | - name: 📢 Upload symbols
50 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
51 | with:
52 | name: symbols-${{ runner.os }}
53 | path: ${{ runner.temp }}/_artifacts/symbols
54 | continue-on-error: true
55 | - name: 📢 Upload deployables
56 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
57 | with:
58 | name: deployables-${{ runner.os }}
59 | path: ${{ runner.temp }}/_artifacts/deployables
60 | if: always()
61 |
--------------------------------------------------------------------------------
/.github/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "github>microsoft/vs-renovate-presets:microbuild",
5 | "github>microsoft/vs-renovate-presets:vs_main_dependencies",
6 | "github>microsoft/vs-renovate-presets:dotnet_packages_LTS"
7 | ],
8 | "packageRules": [
9 | {
10 | "matchPackageNames": ["Microsoft.AspNetCore.TestHost"],
11 | "allowedVersions": "<2.3"
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/.github/workflows/docs.yml:
--------------------------------------------------------------------------------
1 | name: 📚 Docs
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
9 | permissions:
10 | actions: read
11 | pages: write
12 | id-token: write
13 | contents: read
14 |
15 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
16 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
17 | concurrency:
18 | group: pages
19 | cancel-in-progress: false
20 |
21 | jobs:
22 | publish-docs:
23 | environment:
24 | name: github-pages
25 | url: ${{ steps.deployment.outputs.page_url }}
26 | runs-on: ubuntu-latest
27 | steps:
28 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
29 | with:
30 | fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
31 | - name: ⚙ Install prerequisites
32 | run: ./init.ps1 -UpgradePrerequisites
33 |
34 | - run: dotnet docfx docfx/docfx.json
35 | name: 📚 Generate documentation
36 |
37 | - name: Upload artifact
38 | uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3
39 | with:
40 | path: docfx/_site
41 |
42 | - name: Deploy to GitHub Pages
43 | id: deployment
44 | uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
45 |
--------------------------------------------------------------------------------
/.github/workflows/docs_validate.yml:
--------------------------------------------------------------------------------
1 | name: 📃 Docfx Validate
2 |
3 | on:
4 | pull_request:
5 | workflow_dispatch:
6 | push:
7 | branches:
8 | - main
9 | - microbuild
10 |
11 | jobs:
12 | build:
13 | name: 📚 Doc validation
14 | runs-on: ubuntu-24.04
15 | steps:
16 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
17 | with:
18 | fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
19 | - name: 🔗 Markup Link Checker (mlc)
20 | uses: becheran/mlc@c925f90a9a25e16e4c4bfa29058f6f9ffa9f0d8c # v0.21.0
21 | with:
22 | args: --do-not-warn-for-redirect-to https://learn.microsoft.com*,https://dotnet.microsoft.com/*,https://dev.azure.com/*,https://app.codecov.io/*,https://microsoft.github.io/vs-threading/* -p docfx -i https://aka.ms/onboardsupport,https://aka.ms/spot,https://msrc.microsoft.com/*,https://www.microsoft.com/msrc*,https://microsoft.com/msrc*
23 | - name: ⚙ Install prerequisites
24 | run: |
25 | ./init.ps1 -UpgradePrerequisites
26 | dotnet --info
27 | shell: pwsh
28 | - name: 📚 Verify docfx build
29 | run: dotnet docfx docfx/docfx.json --warningsAsErrors --disableGitFeatures
30 | if: runner.os == 'Linux'
31 |
--------------------------------------------------------------------------------
/.prettierrc.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/vs-streamjsonrpc/23f1c7d9ff245fef4b7beb7703b97fa1bc7476b2/.prettierrc.yaml
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
4 | // List of extensions which should be recommended for users of this workspace.
5 | "recommendations": [
6 | "ms-azure-devops.azure-pipelines",
7 | "ms-dotnettools.csharp",
8 | "k--kato.docomment",
9 | "editorconfig.editorconfig",
10 | "esbenp.prettier-vscode",
11 | "pflannery.vscode-versionlens",
12 | "davidanson.vscode-markdownlint",
13 | "dotjoshjohnson.xml",
14 | "ms-vscode-remote.remote-containers",
15 | "ms-azuretools.vscode-docker",
16 | "tintoy.msbuild-project-tools"
17 | ],
18 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
19 | "unwantedRecommendations": []
20 | }
21 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.trimTrailingWhitespace": true,
3 | "files.insertFinalNewline": true,
4 | "files.trimFinalNewlines": true,
5 | "azure-pipelines.1ESPipelineTemplatesSchemaFile": true,
6 | "omnisharp.enableEditorConfigSupport": true,
7 | "omnisharp.enableRoslynAnalyzers": true,
8 | "dotnet.defaultSolution": "StreamJsonRpc.sln",
9 | "dotnet.completion.showCompletionItemsFromUnimportedNamespaces": true,
10 | "editor.formatOnSave": true,
11 | "[xml]": {
12 | "editor.wordWrap": "off"
13 | },
14 | // Treat these files as Azure Pipelines files
15 | "files.associations": {
16 | "**/azure-pipelines/**/*.yml": "azure-pipelines",
17 | "azure-pipelines.yml": "azure-pipelines"
18 | },
19 | // Use Prettier as the default formatter for Azure Pipelines files.
20 | // Needs to be explicitly configured: https://github.com/Microsoft/azure-pipelines-vscode#document-formatting
21 | "[azure-pipelines]": {
22 | "editor.defaultFormatter": "esbenp.prettier-vscode",
23 | "editor.formatOnSave": false // enable this when they conform
24 | },
25 | }
26 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build",
6 | "command": "dotnet",
7 | "type": "process",
8 | "args": [
9 | "build",
10 | "${workspaceFolder}",
11 | "/property:GenerateFullPaths=true",
12 | "/consoleloggerparameters:NoSummary"
13 | ],
14 | "problemMatcher": "$msCompile"
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/BannedSymbols.txt:
--------------------------------------------------------------------------------
1 | M:Newtonsoft.Json.JsonSerializer.CreateDefault(); depends on JsonConvert.DefaultSettings
2 | M:Newtonsoft.Json.Linq.JObject.FromObject(System.Object); depends on JsonConvert.DefaultSettings
3 | M:Newtonsoft.Json.Linq.JToken.FromObject(System.Object); depends on JsonConvert.DefaultSettings
4 | M:Newtonsoft.Json.Linq.JToken.ToObject(System.Type); depends on JsonConvert.DefaultSettings
5 | M:Newtonsoft.Json.Linq.JToken.ToObject``1; depends on JsonConvert.DefaultSettings
6 |
--------------------------------------------------------------------------------
/Directory.Build.rsp:
--------------------------------------------------------------------------------
1 | #------------------------------------------------------------------------------
2 | # This file contains command-line options that MSBuild will process as part of
3 | # every build, unless the "/noautoresponse" switch is specified.
4 | #
5 | # MSBuild processes the options in this file first, before processing the
6 | # options on the command line. As a result, options on the command line can
7 | # override the options in this file. However, depending on the options being
8 | # set, the overriding can also result in conflicts.
9 | #
10 | # NOTE: The "/noautoresponse" switch cannot be specified in this file, nor in
11 | # any response file that is referenced by this file.
12 | #------------------------------------------------------------------------------
13 | /nr:false
14 | /m
15 | /verbosity:minimal
16 | /clp:Summary;ForceNoAlign
17 |
--------------------------------------------------------------------------------
/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 13
5 | 16.9
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | StreamJsonRpc
2 | Copyright (c) Microsoft Corporation
3 | All rights reserved.
4 |
5 | MIT License
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vs-StreamJsonRpc
2 |
3 | [](https://codecov.io/gh/Microsoft/vs-streamjsonrpc)
4 |
5 | ## StreamJsonRpc
6 |
7 | [](https://www.nuget.org/packages/StreamJsonRpc)
8 | [](https://dev.azure.com/azure-public/vside/_build/latest?definitionId=13)
9 |
10 | StreamJsonRpc is a cross-platform, .NET portable library that implements the
11 | [JSON-RPC][JSONRPC] wire protocol.
12 |
13 | It works over [Stream](https://docs.microsoft.com/dotnet/api/system.io.stream), [WebSocket](https://docs.microsoft.com/dotnet/api/system.net.websockets.websocket), or System.IO.Pipelines pipes, independent of the underlying transport.
14 |
15 | Bonus features beyond the JSON-RPC spec include:
16 |
17 | 1. Request cancellation
18 | 1. .NET Events as notifications
19 | 1. Dynamic client proxy generation
20 | 1. Support for [compact binary serialization](https://microsoft.github.io/vs-streamjsonrpc/docs/extensibility.html) via MessagePack
21 | 1. Pluggable architecture for custom message handling and formatting.
22 |
23 | Learn about the use cases for JSON-RPC and how to use this library from our [documentation](https://microsoft.github.io/vs-streamjsonrpc/).
24 |
25 | [JSONRPC]: https://www.jsonrpc.org/
26 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | batch: true
3 | branches:
4 | include:
5 | - main
6 | - 'v*.*'
7 | - 'validate/*'
8 | paths:
9 | exclude:
10 | - doc/
11 | - '*.md'
12 | - .vscode/
13 | - .github/
14 | - azure-pipelines/release.yml
15 |
16 | parameters:
17 | - name: EnableMacOSBuild
18 | displayName: Build on macOS
19 | type: boolean
20 | default: false # macOS is often bogged down in Azure Pipelines
21 | - name: RunTests
22 | displayName: Run tests
23 | type: boolean
24 | default: true
25 |
26 | variables:
27 | - template: /azure-pipelines/BuildStageVariables.yml@self
28 |
29 | jobs:
30 | - template: azure-pipelines/build.yml
31 | parameters:
32 | Is1ESPT: false
33 | EnableMacOSBuild: ${{ parameters.EnableMacOSBuild }}
34 | RunTests: ${{ parameters.RunTests }}
35 | ShouldSkipOptimize: false
36 |
--------------------------------------------------------------------------------
/azure-pipelines/BuildStageVariables.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
3 | BuildConfiguration: Release
4 | NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages/
5 | codecov_token: 9a7c2ba3-0a4b-4479-96e8-3bfd01a982f6
6 |
--------------------------------------------------------------------------------
/azure-pipelines/CredScanSuppressions.json:
--------------------------------------------------------------------------------
1 | {
2 | "tool": "Credential Scanner",
3 | "suppressions": [
4 | {
5 | "folder": "testResults-Windows",
6 | "_justification": "Test logs never include credentials, but false positives abound."
7 | },
8 | {
9 | "folder": "test_logs",
10 | "_justification": "Test logs never include credentials, but false positives abound."
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/azure-pipelines/Get-InsertionPRId.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .SYNOPSIS
3 | Look up the pull request URL of the insertion PR.
4 | #>
5 | $stagingFolder = $env:BUILD_STAGINGDIRECTORY
6 | if (!$stagingFolder) {
7 | $stagingFolder = $env:SYSTEM_DEFAULTWORKINGDIRECTORY
8 | if (!$stagingFolder) {
9 | Write-Error "This script must be run in an Azure Pipeline."
10 | exit 1
11 | }
12 | }
13 | $markdownFolder = Join-Path $stagingFolder (Join-Path 'MicroBuild' 'Output')
14 | $markdownFile = Join-Path $markdownFolder 'PullRequestUrl.md'
15 | if (!(Test-Path $markdownFile)) {
16 | Write-Error "This script should be run after the MicroBuildInsertVsPayload task."
17 | exit 2
18 | }
19 |
20 | $insertionPRUrl = Get-Content $markdownFile
21 | if (!($insertionPRUrl -match 'https:.+?/pullrequest/(\d+)')) {
22 | Write-Error "Failed to parse pull request URL: $insertionPRUrl"
23 | exit 3
24 | }
25 |
26 | $Matches[1]
27 |
--------------------------------------------------------------------------------
/azure-pipelines/GlobalVariables.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | # These variables are required for MicroBuild tasks
3 | TeamName: VS Core - Extensibility
4 | TeamEmail: vsideexeng@microsoft.com
5 | # These variables influence insertion pipelines
6 | ContainsVsix: false # This should be true when the repo builds a VSIX that should be inserted to VS.
7 |
--------------------------------------------------------------------------------
/azure-pipelines/Install-NuGetPackage.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .SYNOPSIS
3 | Installs a NuGet package.
4 | .PARAMETER PackageID
5 | The Package ID to install.
6 | .PARAMETER Version
7 | The version of the package to install. If unspecified, the latest stable release is installed.
8 | .PARAMETER Source
9 | The package source feed to find the package to install from.
10 | .PARAMETER PackagesDir
11 | The directory to install the package to. By default, it uses the Packages folder at the root of the repo.
12 | .PARAMETER ConfigFile
13 | The nuget.config file to use. By default, it uses :/nuget.config.
14 | .OUTPUTS
15 | System.String. The path to the installed package.
16 | #>
17 | [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Low')]
18 | Param(
19 | [Parameter(Position=1,Mandatory=$true)]
20 | [string]$PackageId,
21 | [Parameter()]
22 | [string]$Version,
23 | [Parameter()]
24 | [string]$Source,
25 | [Parameter()]
26 | [switch]$Prerelease,
27 | [Parameter()]
28 | [string]$PackagesDir="$PSScriptRoot\..\packages",
29 | [Parameter()]
30 | [string]$ConfigFile="$PSScriptRoot\..\nuget.config",
31 | [Parameter()]
32 | [ValidateSet('Quiet','Normal','Detailed')]
33 | [string]$Verbosity='normal'
34 | )
35 |
36 | $nugetPath = & "$PSScriptRoot\..\tools\Get-NuGetTool.ps1"
37 |
38 | try {
39 | Write-Verbose "Installing $PackageId..."
40 | $nugetArgs = "Install",$PackageId,"-OutputDirectory",$PackagesDir,'-ConfigFile',$ConfigFile
41 | if ($Version) { $nugetArgs += "-Version",$Version }
42 | if ($Source) { $nugetArgs += "-FallbackSource",$Source }
43 | if ($Prerelease) { $nugetArgs += "-Prerelease" }
44 | $nugetArgs += '-Verbosity',$Verbosity
45 |
46 | if ($PSCmdlet.ShouldProcess($PackageId, 'nuget install')) {
47 | $p = Start-Process $nugetPath $nugetArgs -NoNewWindow -Wait -PassThru
48 | if ($null -ne $p.ExitCode -and $p.ExitCode -ne 0) { throw }
49 | }
50 |
51 | # Provide the path to the installed package directory to our caller.
52 | Write-Output (Get-ChildItem "$PackagesDir\$PackageId.*")[0].FullName
53 | } finally {
54 | Pop-Location
55 | }
56 |
--------------------------------------------------------------------------------
/azure-pipelines/Merge-CodeCoverage.ps1:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env pwsh
2 |
3 | <#
4 | .SYNOPSIS
5 | Merges code coverage reports.
6 | .PARAMETER Path
7 | The path(s) to search for Cobertura code coverage reports.
8 | .PARAMETER Format
9 | The format for the merged result. The default is Cobertura
10 | .PARAMETER OutputDir
11 | The directory the merged result will be written to. The default is `coveragereport` in the root of this repo.
12 | #>
13 | [CmdletBinding()]
14 | Param(
15 | [Parameter(Mandatory=$true)]
16 | [string[]]$Path,
17 | [ValidateSet('Badges', 'Clover', 'Cobertura', 'CsvSummary', 'Html', 'Html_Dark', 'Html_Light', 'HtmlChart', 'HtmlInline', 'HtmlInline_AzurePipelines', 'HtmlInline_AzurePipelines_Dark', 'HtmlInline_AzurePipelines_Light', 'HtmlSummary', 'JsonSummary', 'Latex', 'LatexSummary', 'lcov', 'MarkdownSummary', 'MHtml', 'PngChart', 'SonarQube', 'TeamCitySummary', 'TextSummary', 'Xml', 'XmlSummary')]
18 | [string]$Format='Cobertura',
19 | [string]$OutputFile=("$PSScriptRoot/../coveragereport/merged.cobertura.xml")
20 | )
21 |
22 | $RepoRoot = [string](Resolve-Path $PSScriptRoot/..)
23 | Push-Location $RepoRoot
24 | try {
25 | Write-Verbose "Searching $Path for *.cobertura.xml files"
26 | $reports = Get-ChildItem -Recurse $Path -Filter *.cobertura.xml
27 |
28 | if ($reports) {
29 | $reports |% { $_.FullName } |% {
30 | # In addition to replacing {reporoot}, we also normalize on one kind of slash so that the report aggregates data for a file whether data was collected on Windows or not.
31 | $xml = [xml](Get-Content -LiteralPath $_)
32 | $xml.coverage.packages.package.classes.class |? { $_.filename} |% {
33 | $_.filename = $_.filename.Replace('{reporoot}', $RepoRoot).Replace([IO.Path]::AltDirectorySeparatorChar, [IO.Path]::DirectorySeparatorChar)
34 | }
35 |
36 | $xml.Save($_)
37 | }
38 |
39 | $Inputs = $reports |% { Resolve-Path -relative $_.FullName }
40 |
41 | if ((Split-Path $OutputFile) -and -not (Test-Path (Split-Path $OutputFile))) {
42 | New-Item -Type Directory -Path (Split-Path $OutputFile) | Out-Null
43 | }
44 |
45 | & dotnet dotnet-coverage merge $Inputs -o $OutputFile -f cobertura
46 | } else {
47 | Write-Error "No reports found to merge."
48 | }
49 | } finally {
50 | Pop-Location
51 | }
52 |
--------------------------------------------------------------------------------
/azure-pipelines/NuGetSbom.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | 2
5 |
6 |
7 |
--------------------------------------------------------------------------------
/azure-pipelines/PoliCheckExclusions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | NODE_MODULES|.STORE
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/azure-pipelines/PostPRMessage.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding(SupportsShouldProcess = $true)]
2 | param(
3 | [Parameter(Mandatory=$true)]
4 | $AccessToken,
5 | [Parameter(Mandatory=$true)]
6 | $Markdown,
7 | [ValidateSet('Active','ByDesign','Closed','Fixed','Pending','Unknown','WontFix')]
8 | $CommentState='Active'
9 | )
10 |
11 | # See https://docs.microsoft.com/en-us/dotnet/api/microsoft.teamfoundation.sourcecontrol.webapi.commentthreadstatus?view=azure-devops-dotnet
12 | if ($CommentState -eq 'Active') {
13 | $StatusCode = 1
14 | } elseif ($CommentState -eq 'ByDesign') {
15 | $StatusCode = 5
16 | } elseif ($CommentState -eq 'Closed') {
17 | $StatusCode = 4
18 | } elseif ($CommentState -eq 'Fixed') {
19 | $StatusCode = 2
20 | } elseif ($CommentState -eq 'Pending') {
21 | $StatusCode = 6
22 | } elseif ($CommentState -eq 'Unknown') {
23 | $StatusCode = 0
24 | } elseif ($CommentState -eq 'WontFix') {
25 | $StatusCode = 3
26 | }
27 |
28 | # Build the JSON body up
29 | $body = ConvertTo-Json @{
30 | comments = @(@{
31 | parentCommentId = 0
32 | content = $Markdown
33 | commentType = 1
34 | })
35 | status = $StatusCode
36 | }
37 |
38 | Write-Verbose "Posting JSON payload: `n$Body"
39 |
40 | # Post the message to the Pull Request
41 | # https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20request%20threads?view=azure-devops-rest-5.1
42 | $url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/git/repositories/$($env:BUILD_REPOSITORY_NAME)/pullRequests/$($env:SYSTEM_PULLREQUEST_PULLREQUESTID)/threads?api-version=5.1"
43 | if ($PSCmdlet.ShouldProcess($url, 'Post comment via REST call')) {
44 | try {
45 | if (!$env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI) {
46 | Write-Error "Posting to the pull request requires that the script is running in an Azure Pipelines context."
47 | exit 1
48 | }
49 | Write-Host "Posting PR comment to: $url"
50 | Invoke-RestMethod -Uri $url -Method POST -Headers @{Authorization = "Bearer $AccessToken"} -Body $Body -ContentType application/json
51 | }
52 | catch {
53 | Write-Error $_
54 | Write-Error $_.Exception.Message
55 | exit 2
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/azure-pipelines/TSAOptions.json:
--------------------------------------------------------------------------------
1 | {
2 | "tsaVersion": "TsaV2",
3 | "codebase": "NewOrUpdate",
4 | "codebaseName": "StreamJsonRpc",
5 | "tsaStamp": "DevDiv",
6 | "tsaEnvironment": "PROD",
7 | "notificationAliases": [
8 | "vsidemicrobuild@microsoft.com"
9 | ],
10 | "codebaseAdmins": [
11 | "REDMOND\\andarno"
12 | ],
13 | "instanceUrl": "https://devdiv.visualstudio.com",
14 | "projectName": "DevDiv",
15 | "areaPath": "DevDiv\\VS Core\\Extensibility\\StreamJsonRpc",
16 | "iterationPath": "DevDiv",
17 | "alltools": true,
18 | "repositoryName": "vs-StreamJsonRpc"
19 | }
20 |
--------------------------------------------------------------------------------
/azure-pipelines/WIFtoPATauth.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: deadPATServiceConnectionId # The GUID of the PAT-based service connection whose access token must be replaced.
3 | type: string
4 | - name: wifServiceConnectionName # The name of the WIF service connection to use to get the access token.
5 | type: string
6 | - name: resource # The scope for which the access token is requested.
7 | type: string
8 | default: 499b84ac-1321-427f-aa17-267ca6975798 # Azure Artifact feeds (any of them)
9 |
10 | steps:
11 | - task: AzureCLI@2
12 | displayName: 🔏 Authenticate with WIF service connection
13 | inputs:
14 | azureSubscription: ${{ parameters.wifServiceConnectionName }}
15 | scriptType: pscore
16 | scriptLocation: inlineScript
17 | inlineScript: |
18 | $accessToken = az account get-access-token --query accessToken --resource '${{ parameters.resource }}' -o tsv
19 | # Set the access token as a secret, so it doesn't get leaked in the logs
20 | Write-Host "##vso[task.setsecret]$accessToken"
21 | # Override the apitoken of the nuget service connection, for the duration of this stage
22 | Write-Host "##vso[task.setendpoint id=${{ parameters.deadPATServiceConnectionId }};field=authParameter;key=apitoken]$accessToken"
23 |
--------------------------------------------------------------------------------
/azure-pipelines/apiscan.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: windowsPool
3 | type: object
4 | - name: RealSign
5 | type: boolean
6 |
7 | jobs:
8 | - job: apiscan
9 | displayName: APIScan
10 | dependsOn: Windows
11 | pool: ${{ parameters.windowsPool }}
12 | timeoutInMinutes: 120
13 | templateContext:
14 | ${{ if not(parameters.RealSign) }}:
15 | mb:
16 | signing: # if the build is test-signed, install the signing plugin so that CSVTestSignPolicy.xml is available
17 | enabled: true
18 | zipSources: false
19 | signType: test
20 | outputs:
21 | - output: pipelineArtifact
22 | displayName: 📢 collect apiscan artifact
23 | targetPath: $(Pipeline.Workspace)/.gdn/.r/apiscan/001/Logs
24 | artifactName: apiscan-logs
25 | condition: succeededOrFailed()
26 | variables:
27 | - name: SymbolsFeatureName
28 | value: $[ dependencies.Windows.outputs['SetPipelineVariables.SymbolsFeatureName'] ]
29 | - name: NBGV_MajorMinorVersion
30 | value: $[ dependencies.Windows.outputs['nbgv.NBGV_MajorMinorVersion'] ]
31 | - ${{ if eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9') }}:
32 | # https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/25351/APIScan-step-by-step-guide-to-setting-up-a-Pipeline
33 | - group: VSEng sponsored APIScan # Expected to provide ApiScanClientId
34 | steps:
35 | # We need TSAOptions.json
36 | - checkout: self
37 | fetchDepth: 1
38 |
39 | - download: current
40 | artifact: APIScanInputs
41 | displayName: 🔻 Download APIScanInputs artifact
42 |
43 | - task: APIScan@2
44 | displayName: 🔍 Run APIScan
45 | inputs:
46 | softwareFolder: $(Pipeline.Workspace)/APIScanInputs
47 | softwareName: $(SymbolsFeatureName)
48 | softwareVersionNum: $(NBGV_MajorMinorVersion)
49 | isLargeApp: false
50 | toolVersion: Latest
51 | preserveLogsFolder: true
52 | env:
53 | AzureServicesAuthConnectionString: runAs=App;AppId=$(ApiScanClientId)
54 |
55 | # File bugs when APIScan finds issues
56 | - task: TSAUpload@2
57 | displayName: 🪳 TSA upload
58 | inputs:
59 | GdnPublishTsaOnboard: True
60 | GdnPublishTsaConfigFile: $(Build.SourcesDirectory)\azure-pipelines\TSAOptions.json
61 | condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
62 |
--------------------------------------------------------------------------------
/azure-pipelines/falsepositives.gdnsuppress:
--------------------------------------------------------------------------------
1 | {
2 | "version": "latest",
3 | "suppressionSets": {
4 | "falsepositives": {
5 | "name": "falsepositives",
6 | "createdDate": "2021-12-04 13:44:31Z",
7 | "lastUpdatedDate": "2021-12-04 13:44:31Z"
8 | }
9 | },
10 | "results": {
11 | "1a16aa9483f5e231d7752acab742c307290e6984e855810f9799f02f6ecef7ce": {
12 | "signature": "1a16aa9483f5e231d7752acab742c307290e6984e855810f9799f02f6ecef7ce",
13 | "alternativeSignatures": [
14 | "ad8debd5159bf5995c89a18408ab058ab4a168f17d7a5aaffb1d94a1a5d99cfc"
15 | ],
16 | "target": "streamjsonrpc/release/netstandard2.0/streamjsonrpc.dll",
17 | "memberOf": [
18 | "falsepositives"
19 | ],
20 | "tool": "apiscan",
21 | "ruleId": "documentationnotfound",
22 | "justification": null,
23 | "createdDate": "2021-12-04 13:44:31Z",
24 | "expirationDate": null,
25 | "type": null
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/azure-pipelines/install-dependencies.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: initArgs
3 | type: string
4 | default: ''
5 | - name: needsAzurePublicFeeds
6 | type: boolean
7 | default: true # If nuget.config pulls from the azure-public account, we need to authenticate when building on the devdiv account.
8 |
9 | steps:
10 | - ${{ if and(parameters.needsAzurePublicFeeds, eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9')) }}:
11 | - template: WIFtoPATauth.yml
12 | parameters:
13 | wifServiceConnectionName: azure-public/vside package pull
14 | deadPATServiceConnectionId: 46f0d4d4-9fff-4c58-a1ab-3b8f97e3b78a # azure-public/msft_consumption_public
15 |
16 | - task: NuGetAuthenticate@1
17 | displayName: 🔏 Authenticate NuGet feeds
18 | inputs:
19 | ${{ if and(parameters.needsAzurePublicFeeds, eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9')) }}:
20 | nuGetServiceConnections: azure-public/msft_consumption_public
21 |
22 | - powershell: |
23 | $AccessToken = '$(System.AccessToken)' # Avoid specifying the access token directly on the init.ps1 command line to avoid it showing up in errors
24 | .\init.ps1 -AccessToken $AccessToken ${{ parameters['initArgs'] }} -UpgradePrerequisites -NoNuGetCredProvider
25 | dotnet --info
26 |
27 | # Print mono version if it is present.
28 | if (Get-Command mono -ErrorAction SilentlyContinue) {
29 | mono --version
30 | }
31 | displayName: ⚙ Install prerequisites
32 |
33 | - powershell: tools/variables/_define.ps1
34 | failOnStderr: true
35 | displayName: ⚙ Set pipeline variables based on source
36 | name: SetPipelineVariables
37 |
--------------------------------------------------------------------------------
/azure-pipelines/microbuild.after.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: EnableOptProf
3 | type: boolean
4 | default: false
5 | - name: IsOptProf
6 | type: boolean
7 | default: false
8 | - name: SkipCodesignVerify
9 | type: boolean
10 |
11 | steps:
12 | - ${{ if not(parameters.SkipCodesignVerify) }}: # skip CodesignVerify on validation builds because we don't even test-sign nupkg's.
13 | - task: MicroBuildCodesignVerify@3
14 | displayName: 🔍 Verify Signed Files
15 | inputs:
16 | ApprovalListPathForSigs: $(Build.SourcesDirectory)\azure-pipelines\no_strongname.txt
17 | ApprovalListPathForCerts: $(Build.SourcesDirectory)\azure-pipelines\no_authenticode.txt
18 | TargetFolders: |
19 | $(Build.SourcesDirectory)/bin/Packages/$(BuildConfiguration)
20 | condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
21 |
22 | - ${{ if parameters.IsOptProf }}:
23 | - task: ms-vscs-artifact.build-tasks.artifactDropTask-1.artifactDropTask@0
24 | inputs:
25 | dropServiceURI: https://devdiv.artifacts.visualstudio.com
26 | buildNumber: $(ProfilingInputsDropName)
27 | sourcePath: $(Build.ArtifactStagingDirectory)\OptProf\ProfilingInputs
28 | toLowerCase: false
29 | usePat: true
30 | displayName: 📢 Publish to Artifact Services - ProfilingInputs
31 | condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
32 |
33 | - task: PublishBuildArtifacts@1
34 | inputs:
35 | PathtoPublish: $(Build.ArtifactStagingDirectory)/InsertionOutputs
36 | ArtifactName: InsertionOutputs
37 | ArtifactType: Container
38 | displayName: 📢 Publish InsertionOutputs as Azure DevOps artifacts
39 |
--------------------------------------------------------------------------------
/azure-pipelines/microbuild.before.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: EnableLocalization
3 | type: boolean
4 | default: false
5 | - name: EnableOptProf
6 | type: boolean
7 | default: false
8 | - name: IsOptProf
9 | type: boolean
10 | default: false
11 | - name: ShouldSkipOptimize
12 | type: boolean
13 | default: false
14 | - name: RealSign
15 | type: boolean
16 |
17 | steps:
18 | - ${{ if and(not(parameters.IsOptProf), ne(variables['Build.Reason'], 'PullRequest')) }}:
19 | # notice@0 requires CG detection to run first, and non-default branches don't inject it automatically.
20 | - ${{ if ne(variables['Build.SourceBranch'], 'refs/heads/main') }}:
21 | - task: ComponentGovernanceComponentDetection@0
22 | displayName: 🔍 Component Detection
23 |
24 | - task: notice@0
25 | displayName: 🛠️ Generate NOTICE file
26 | inputs:
27 | outputfile: $(System.DefaultWorkingDirectory)/obj/NOTICE
28 | outputformat: text
29 | retryCountOnTaskFailure: 3 # fails when the cloud service is overloaded
30 | continueOnError: ${{ not(parameters.RealSign) }} # Tolerate failures when we're not building something that may ship.
31 |
32 | - ${{ if parameters.IsOptProf }}:
33 | # We have to install these plugins ourselves for Optprof runs because those pipelines haven't migrated to 1ES PT yet.
34 | - task: MicroBuildOptProfPlugin@6
35 | inputs:
36 | ProfilingInputsDropName: $(ProfilingInputsDropName)
37 | OptimizationInputsLookupMethod: DropPrefix
38 | DropNamePrefix: OptimizationInputs/$(System.TeamProject)/$(Build.Repository.Name)
39 | ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }}
40 | AccessToken: $(System.AccessToken)
41 | displayName: 🔧 Install OptProf Plugin
42 |
43 | - task: MicroBuildSigningPlugin@4
44 | inputs:
45 | signType: Real
46 | zipSources: false
47 | displayName: 🔧 Install MicroBuild Signing Plugin
48 |
49 | - ${{ if parameters.EnableLocalization }}:
50 | - task: MicroBuildLocalizationPlugin@4
51 | inputs:
52 | languages: $(LocLanguages)
53 | displayName: 🔧 Install MicroBuild Localization Plugin
54 |
--------------------------------------------------------------------------------
/azure-pipelines/no_authenticode.txt:
--------------------------------------------------------------------------------
1 | bin\packages\release\vsix\_manifest\manifest.cat,sbom signed
2 | bin\packages\release\vsix\_manifest\spdx_2.2\manifest.cat,sbom signed
3 |
--------------------------------------------------------------------------------
/azure-pipelines/no_strongname.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/vs-streamjsonrpc/23f1c7d9ff245fef4b7beb7703b97fa1bc7476b2/azure-pipelines/no_strongname.txt
--------------------------------------------------------------------------------
/azure-pipelines/publish-codecoverage.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: EnableMacOSBuild
3 | type: boolean
4 | - name: EnableLinuxBuild
5 | type: boolean
6 |
7 | steps:
8 | - download: current
9 | artifact: coverageResults-Windows
10 | displayName: 🔻 Download Windows code coverage results
11 | continueOnError: true
12 | - ${{ if parameters.EnableLinuxBuild }}:
13 | - download: current
14 | artifact: coverageResults-Linux
15 | displayName: 🔻 Download Linux code coverage results
16 | continueOnError: true
17 | - ${{ if parameters.EnableMacOSBuild }}:
18 | - download: current
19 | artifact: coverageResults-macOS
20 | displayName: 🔻 Download macOS code coverage results
21 | continueOnError: true
22 | - powershell: azure-pipelines/Merge-CodeCoverage.ps1 -Path '$(Pipeline.Workspace)' -OutputFile coveragereport/merged.cobertura.xml -Format Cobertura -Verbose
23 | displayName: ⚙ Merge coverage
24 | - task: PublishCodeCoverageResults@2
25 | displayName: 📢 Publish code coverage results to Azure DevOps
26 | inputs:
27 | summaryFileLocation: coveragereport/merged.cobertura.xml
28 | failIfCoverageEmpty: true
29 |
--------------------------------------------------------------------------------
/azure-pipelines/publish-symbols.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: EnableMacOSBuild
3 | type: boolean
4 | - name: EnableLinuxBuild
5 | type: boolean
6 |
7 | steps:
8 | - task: DownloadPipelineArtifact@2
9 | inputs:
10 | artifact: symbols-Windows
11 | path: $(Pipeline.Workspace)/symbols/Windows
12 | displayName: 🔻 Download Windows symbols
13 | continueOnError: true
14 | - ${{ if parameters.EnableLinuxBuild }}:
15 | - task: DownloadPipelineArtifact@2
16 | inputs:
17 | artifact: symbols-Linux
18 | path: $(Pipeline.Workspace)/symbols/Linux
19 | displayName: 🔻 Download Linux symbols
20 | continueOnError: true
21 | - ${{ if parameters.EnableMacOSBuild }}:
22 | - task: DownloadPipelineArtifact@2
23 | inputs:
24 | artifact: symbols-macOS
25 | path: $(Pipeline.Workspace)/symbols/macOS
26 | displayName: 🔻 Download macOS symbols
27 | continueOnError: true
28 |
29 | - task: DownloadPipelineArtifact@2
30 | inputs:
31 | artifact: test_symbols-Windows
32 | path: $(Pipeline.Workspace)/test_symbols/Windows
33 | displayName: 🔻 Download Windows test symbols
34 | continueOnError: true
35 | - ${{ if parameters.EnableLinuxBuild }}:
36 | - task: DownloadPipelineArtifact@2
37 | inputs:
38 | artifact: test_symbols-Linux
39 | path: $(Pipeline.Workspace)/test_symbols/Linux
40 | displayName: 🔻 Download Linux test symbols
41 | continueOnError: true
42 | - ${{ if parameters.EnableMacOSBuild }}:
43 | - task: DownloadPipelineArtifact@2
44 | inputs:
45 | artifact: test_symbols-macOS
46 | path: $(Pipeline.Workspace)/test_symbols/macOS
47 | displayName: 🔻 Download macOS test symbols
48 | continueOnError: true
49 |
50 | - task: PublishSymbols@2
51 | inputs:
52 | SymbolsFolder: $(Pipeline.Workspace)/symbols
53 | SearchPattern: '**/*.pdb'
54 | IndexSources: false
55 | SymbolServerType: TeamServices
56 | displayName: 📢 Publish symbols
57 |
58 | - task: PublishSymbols@2
59 | inputs:
60 | SymbolsFolder: $(Pipeline.Workspace)/test_symbols
61 | SearchPattern: '**/*.pdb'
62 | IndexSources: false
63 | SymbolServerType: TeamServices
64 | displayName: 📢 Publish test symbols
65 |
66 | - powershell: tools/Prepare-Legacy-Symbols.ps1 -Path $(Pipeline.Workspace)/symbols/Windows
67 | displayName: ⚙ Prepare symbols for symbol archival
68 |
--------------------------------------------------------------------------------
/azure-pipelines/publish_artifacts.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .SYNOPSIS
3 | This script translates all the artifacts described by _all.ps1
4 | into commands that instruct Azure Pipelines to actually collect those artifacts.
5 | #>
6 |
7 | [CmdletBinding()]
8 | param (
9 | [string]$ArtifactNameSuffix,
10 | [switch]$StageOnly,
11 | [switch]$AvoidSymbolicLinks
12 | )
13 |
14 | Function Set-PipelineVariable($name, $value) {
15 | if ((Test-Path "Env:\$name") -and (Get-Item "Env:\$name").Value -eq $value) {
16 | return # already set
17 | }
18 |
19 | #New-Item -LiteralPath "Env:\$name".ToUpper() -Value $value -Force | Out-Null
20 | Write-Host "##vso[task.setvariable variable=$name]$value"
21 | }
22 |
23 | Function Test-ArtifactUploaded($artifactName) {
24 | $varName = "ARTIFACTUPLOADED_$($artifactName.ToUpper())"
25 | Test-Path "env:$varName"
26 | }
27 |
28 | & "$PSScriptRoot/../tools/artifacts/_stage_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix -AvoidSymbolicLinks:$AvoidSymbolicLinks |% {
29 | # Set a variable which will out-live this script so that a subsequent attempt to collect and upload artifacts
30 | # will skip this one from a check in the _all.ps1 script.
31 | Set-PipelineVariable "ARTIFACTSTAGED_$($_.Name.ToUpper())" 'true'
32 | Write-Host "Staged artifact $($_.Name) to $($_.Path)"
33 |
34 | if (!$StageOnly) {
35 | if (Test-ArtifactUploaded $_.Name) {
36 | Write-Host "Skipping $($_.Name) because it has already been uploaded." -ForegroundColor DarkGray
37 | } else {
38 | Write-Host "##vso[artifact.upload containerfolder=$($_.Name);artifactname=$($_.Name);]$($_.Path)"
39 |
40 | # Set a variable which will out-live this script so that a subsequent attempt to collect and upload artifacts
41 | # will skip this one from a check in the _all.ps1 script.
42 | Set-PipelineVariable "ARTIFACTUPLOADED_$($_.Name.ToUpper())" 'true'
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/azure-pipelines/release-deployment-prep.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - download: CI
3 | artifact: Variables-Windows
4 | displayName: 🔻 Download Variables-Windows artifact
5 | - powershell: $(Pipeline.Workspace)/CI/Variables-Windows/_define.ps1
6 | displayName: ⚙️ Set pipeline variables based on artifacts
7 |
--------------------------------------------------------------------------------
/azure-pipelines/schedule-only-steps.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - powershell: echo "##vso[build.addbuildtag]auto-insertion"
3 | displayName: Tag for auto-insertion
4 |
--------------------------------------------------------------------------------
/azurepipelines-coverage.yml:
--------------------------------------------------------------------------------
1 | # https://learn.microsoft.com/azure/devops/pipelines/test/codecoverage-for-pullrequests?view=azure-devops
2 | coverage:
3 | status:
4 | comments: on # add comment to PRs reporting diff in coverage of modified files
5 | diff: # diff coverage is code coverage only for the lines changed in a pull request.
6 | target: 70% # set this to a desired %. Default is 70%
7 |
--------------------------------------------------------------------------------
/docfx/.gitignore:
--------------------------------------------------------------------------------
1 | _site/
2 | api/
3 |
--------------------------------------------------------------------------------
/docfx/docfx.json:
--------------------------------------------------------------------------------
1 | {
2 | "metadata": [
3 | {
4 | "src": [
5 | {
6 | "src": "../src/StreamJsonRpc",
7 | "files": [
8 | "**/*.csproj"
9 | ]
10 | }
11 | ],
12 | "dest": "api"
13 | }
14 | ],
15 | "build": {
16 | "content": [
17 | {
18 | "files": [
19 | "**/*.{md,yml}"
20 | ],
21 | "exclude": [
22 | "_site/**"
23 | ]
24 | }
25 | ],
26 | "resource": [
27 | {
28 | "files": [
29 | "images/**"
30 | ]
31 | }
32 | ],
33 | "xref": [
34 | "https://dotnet.github.io/Nerdbank.Streams/xrefmap.yml",
35 | "https://microsoft.github.io/vs-threading/xrefmap.yml",
36 | "https://microsoft.github.io/vs-validation/xrefmap.yml",
37 | "https://learn.microsoft.com/en-us/dotnet/.xrefmap.json"
38 | ],
39 | "output": "_site",
40 | "template": [
41 | "default",
42 | "modern"
43 | ],
44 | "globalMetadata": {
45 | "_appName": "StreamJsonRpc",
46 | "_appTitle": "StreamJsonRpc",
47 | "_enableSearch": true,
48 | "pdf": false
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/docfx/docs/getting-started.md:
--------------------------------------------------------------------------------
1 | # Getting Started
2 |
3 | ## Installation
4 |
5 | Consume this library via its NuGet Package.
6 | Click on the badge to find its latest version and the instructions for consuming it that best apply to your project.
7 |
8 | [](https://nuget.org/packages/StreamJsonRpc)
9 |
10 | ## Use cases
11 |
12 | If you're new to JSON-RPC and/or StreamJsonRpc, check out our brief [overview](../index.md).
13 | The rest of our documentation are organized around use case.
14 |
15 | 1. [Establish a connection](connecting.md)
16 | 1. [Send an RPC request](sendrequest.md)
17 | 1. [Receive an RPC request](recvrequest.md)
18 | 1. [Disconnect](disconnecting.md)
19 | 1. [Test your code](testing.md)
20 | 1. [Write resilient code](resiliency.md)
21 | 1. [Remote Targets](remotetargets.md)
22 | 1. [Pass certain special types in arguments or return values](../exotic_types/index.md)
23 | 1. [Trace context](tracecontext.md)
24 | 1. [JoinableTaskFactory integration](joinableTaskFactory.md)
25 | 1. [Troubleshoot](troubleshooting.md)
26 |
27 | See [full samples](https://github.com/AArnott/StreamJsonRpc.Sample) demonstrating two processes
28 | on the same machine utilizing this library for RPC, using either named pipes or web sockets.
29 |
30 | [Learn more about how you can customize the JSON-RPC protocol's wire format](extensibility.md) that StreamJsonRpc uses for better interoperability or better performance.
31 |
32 | See also [Visual Studio specific concerns](vs.md).
33 |
--------------------------------------------------------------------------------
/docfx/docs/remotetargets.md:
--------------------------------------------------------------------------------
1 | # Adding Remote RPC Targets
2 |
3 | There are scenarios where users may need to add remote RPC targets to facilitate communication between two endpoints that have no direct RPC connection channel. Consider the following 3 endpoints:
4 |
5 | * client
6 | * server
7 | * remote
8 |
9 | There is a direct RPC connection between client and server, and server and remote. However, client and remote may need to send messages to each other as well. To do so, users can utilize the remote target feature:
10 |
11 | ``` csharp
12 | var serverToClientRpc = new JsonRpc(clientStream, new ClientTarget());
13 | var serverToRemoteRpc = new JsonRpc(remoteStream, new RemoteTarget());
14 |
15 | // This allows the client endpoint to send messages to the remote endpoint.
16 | serverToClientRpc.AddRemoteTarget(serverToRemoteRpc);
17 |
18 | // This allows the remote endpoint to send messages to the client endpoint.
19 | serverToRemoteRpc.AddRemoteTarget(serverToClientRpc);
20 | ```
21 |
22 | ### Intercepting Remote Target Calls
23 |
24 | The client can only make a call to the remote endpoint if the server (what's in the middle) hasn't defined a method with the same signature. For example, consider the following:
25 |
26 | ``` csharp
27 | public class ServerTarget
28 | {
29 | public int GetInt()
30 | {
31 | return 5;
32 | }
33 | }
34 |
35 | public class RemoteTarget
36 | {
37 | public int GetInt()
38 | {
39 | return 10;
40 | }
41 | }
42 |
43 | public static class Sample
44 | {
45 | public static async Task InterceptionTest()
46 | {
47 | var clientRpc = new JsonRpc(clientServerStream);
48 | var serverClientRpc = new JsonRpc(serverClientStream, new ServerTarget());
49 | var serverRemoteRpc = new JsonRpc(serverRemoteStream);
50 | var remoteServerRpc = new JsonRpc(remoteServerStream, new RemoteTarget());
51 |
52 | serverClientRpc.AddRemoteTarget(serverRemoteRpc);
53 |
54 | clientRpc.StartListening();
55 | serverClientRpc.StartListening();
56 | remoteServerRpc.StartListening();
57 |
58 | var result = clientRpc.InvokeAsync("GetInt");
59 | }
60 | }
61 | ```
62 |
63 | The `result` captured in `InterceptionTest()` would be 5 instead of 10. When invoking methods on the remote target, StreamJsonRpc will first check to see if there are local methods matching the invocation signature. Only when it does not find a method will it forward the call to the remote target.
64 |
--------------------------------------------------------------------------------
/docfx/docs/security.md:
--------------------------------------------------------------------------------
1 | # StreamJsonRpc security guidance
2 |
3 | The following links contain information about the security practices followed in this repo:
4 |
5 | * [Registering all public methods/events on an object](https://github.com/microsoft/vs-streamjsonrpc/blob/main/doc/recvrequest.md#registering-all-public-methodsevents-on-an-object)
6 | * [Message formatters](https://github.com/microsoft/vs-streamjsonrpc/blob/main/doc/extensibility.md#message-formatters)
7 | * [MessagePack security](https://github.com/MessagePack-CSharp/MessagePack-CSharp#security)
8 |
--------------------------------------------------------------------------------
/docfx/docs/testing.md:
--------------------------------------------------------------------------------
1 | # Testability/mockability
2 |
3 | Testing this library or users of this library can be done without any transport
4 | by using @Nerdbank.Streams.FullDuplexStream.CreatePair*?displayProperty=nameWithType from the the [Nerdbank.Streams](https://www.nuget.org/packages/nerdbank.streams) library in your tests
5 | to produce a pair of full-duplex Stream objects.
6 |
--------------------------------------------------------------------------------
/docfx/docs/toc.yml:
--------------------------------------------------------------------------------
1 | items:
2 | - href: getting-started.md
3 | - href: connecting.md
4 | - href: sendrequest.md
5 | - href: recvrequest.md
6 | - href: disconnecting.md
7 | - href: testing.md
8 | - href: resiliency.md
9 | - href: remotetargets.md
10 | - href: tracecontext.md
11 | - href: joinableTaskFactory.md
12 | - href: troubleshooting.md
13 | - href: extensibility.md
14 | - href: vs.md
15 |
16 | - href: dynamicproxy.md
17 | - href: exceptions.md
18 | - href: security.md
19 |
--------------------------------------------------------------------------------
/docfx/docs/troubleshooting.md:
--------------------------------------------------------------------------------
1 | # Troubleshooting
2 |
3 | ## Tracing
4 |
5 | When investigating failures, you may find StreamJsonRpc's tracing functionality useful.
6 |
7 | With the property, you can listen for:
8 |
9 | 1. Which server methods are registered
10 | 1. Incoming and outgoing JSON-RPC messages and how they're being handled along the entire pipeline
11 | 1. When listening is started
12 | 1. RPC method invocation failures with full exception callstacks.
13 |
14 | The above is just a sample. The full list of events is available on the enum.
15 |
16 | ## Other issues
17 |
18 | ### Requests failing with ConnectionLostException
19 |
20 | Please see our [disconnecting](disconnecting.md) documentation.
21 |
22 | ### Hangs after connecting over IPC pipes
23 |
24 | When connecting two processes using Windows (named) pipes, be sure to use
25 | when creating those pipes to be used with our @StreamJsonRpc.JsonRpc class. All our I/O is asynchronous, and
26 | without that flag, .NET Framework and .NET Core will hang.
27 | See [dotnet/runtime#31390](https://github.com/dotnet/runtime/issues/31390).
28 |
--------------------------------------------------------------------------------
/docfx/docs/vs.md:
--------------------------------------------------------------------------------
1 | # Visual Studio specific concerns
2 |
3 | ## Versions to reference for Visual Studio extensions
4 |
5 | When building a Visual Studio extension, you should not include StreamJsonRpc in your VSIX. Instead, you should compile your extension against the version of StreamJsonRpc that is included in the Visual Studio version that you are targeting as your minimum supported version and rely on Visual Studio's copy of the library to be present at runtime.
6 |
7 | | VS version | StreamJsonRpc version |
8 | | -- | -- |
9 | | VS 2017.0 | 1.0.x
10 | | VS 2017.3 | 1.1.x
11 | | VS 2017.5 | 1.2.x
12 | | VS 2017.6 | 1.3.x
13 | | VS 2019.0 | 1.5.x
14 | | VS 2019.1 | 1.5.x, 2.0.x
15 | | VS 2019.3 | 1.5.x, 2.1.x
16 | | VS 2019.4 | 1.5.x, 2.2.x
17 | | VS 2019.5 | 1.5.x, 2.3.x
18 | | VS 2019.6 | 1.5.x, 2.4.x
19 | | VS 2019.7 | 1.5.x, 2.5.x
20 | | VS 2019.8 | 1.5.x, 2.6.x
21 | | VS 2019.9 | 1.5.x, 2.7.x
22 | | VS 2019.10 | 1.5.x, 2.8.x
23 | | VS 2022.0 | 1.5.x, 2.9.x
24 | | VS 2022.1 | 1.5.x, 2.10.x
25 | | VS 2022.2 | 1.5.x, 2.11.x
26 | | VS 2022.3 | 1.5.x, 2.12.x
27 | | VS 2022.4 | 1.5.x, 2.13.x
28 | | VS 2022.5 | 1.5.x, 2.14.x
29 | | VS 2022.6 | 1.5.x, 2.15.x
30 | | VS 2022.7 | 1.5.x, 2.16.x
31 | | VS 2022.8 | 1.5.x, 2.17.x
32 | | VS 2022.10 | 1.5.x, 2.18.x
33 | | VS 2022.11 | 1.5.x, 2.19.x
34 | | VS 2022.12 | 1.5.x, 2.20.x
35 | | VS 2022.13 | 1.5.x, 2.21.x
36 | | VS 2022.14 | 1.5.x, 2.22.x
37 | | VS 2022.15 | 1.5.x, 2.23.x
38 |
39 | StreamJsonRpc versions are forwards and backwards compatible "over the wire". For example it is perfectly legitimate to use StreamJsonRpc 2.4 on the server-side even if the client only uses 1.0, or vice versa. If an RPC method utilizes a newer StreamJsonRpc feature (e.g. `IAsyncEnumerable` return value) and an older client that doesn't support these specially marshaled objects is used to call that method, a memory leak on the server may result.
40 |
41 | StreamJsonRpc is binary compatible within a major version. If you compile against 1.3 for targeting VS 2017.6, you'll successfully run against the StreamJsonRpc 1.5 version when installed in a later version of Visual Studio.
42 | StreamJsonRpc 2.0 introduced breaking changes, so folks who compile against 1.x will continue to run on 1.x, while folks who want the additional functionality of 2.0 may recompile against that and work in VS 2019.1 and later.
43 |
--------------------------------------------------------------------------------
/docfx/exotic_types/index.md:
--------------------------------------------------------------------------------
1 | # Exotic Types
2 |
3 | Some types are not serializable but are specially recognized and marshaled by StreamJsonRpc when used in arguments or return values.
4 |
5 | * [`CancellationToken`](../docs/sendrequest.md#cancellation)
6 | * [`IProgress`](progresssupport.md)
7 | * [`Stream`, `IDuplexPipe`, `PipeReader`, `PipeWriter`](oob_streams.md)
8 | * [`IAsyncEnumerable`](asyncenumerable.md)
9 | * [`IObserver`](observer.md)
10 | * [`IDisposable`](disposable.md)
11 | * [Interfaces marked with `RpcMarshalableAttribute`](rpc_marshalable_objects.md)
12 | * [General marshalable object support](general_marshaled_objects.md)
13 |
14 | The @System.Threading.CancellationToken support is built into the @StreamJsonRpc.JsonRpc class itself so that it works in any configuration, provided the remote side also supports it.
15 |
16 | The rest of the types listed above require support by the in use. All formatters that ship within the StreamJsonRpc library come with built-in support for all of these.
17 |
--------------------------------------------------------------------------------
/docfx/exotic_types/toc.yml:
--------------------------------------------------------------------------------
1 | items:
2 | - href: index.md
3 | - href: asyncenumerable.md
4 | - href: disposable.md
5 | - href: observer.md
6 | - href: oob_streams.md
7 | - href: progresssupport.md
8 | - href: rpc_marshalable_objects.md
9 | - href: general_marshaled_objects.md
10 | - href: general_marshaled_objects_2.md
11 |
--------------------------------------------------------------------------------
/docfx/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | _layout: landing
3 | ---
4 |
5 | # Overview
6 |
7 | ## Protocol overview
8 |
9 | [JSON-RPC][spec] is a two-party, peer-to-peer based protocol by which one party can request a method's invocation
10 | of the other party, and optionally receive a response from the server with the result of that invocation.
11 |
12 | While we may often use the words 'client' and 'server' in discussions and documentation around JSON-RPC,
13 | these are just convenient terms for referring to the party that is requesting a method invocation vs. the
14 | party that is serving that request. At any given moment, *either party* may send an RPC request to the other party.
15 |
16 | A common pattern is that one party tends to issue most of the RPC requests, while the other party may occasionally
17 | transmit requests as a "call back" to the client for raising notifications. This is merely an artifact of architectural
18 | expediency for many applications and not due to any design of the JSON-RPC protocol, or this library's particular
19 | implementation of it.
20 |
21 | For this reason, our documentation is organized around individual scenarios rather than on the client and server roles.
22 |
23 | ## StreamJsonRpc's role
24 |
25 | StreamJsonRpc is a .NET library that implements the JSON-RPC protocol and exposes it via a .NET API to easily
26 | send and receive RPC requests.
27 |
28 | StreamJsonRpc works on any transport (e.g. Stream, WebSocket, Pipe).
29 |
30 | ## Security
31 |
32 | The fundamental feature of the JSON-RPC protocol is the ability to request code execution of another party, including
33 | passing data either direction that may influence code execution.
34 | Neither the JSON-RPC protocol nor this library attempts to address the applicable security risks entailed.
35 |
36 | Before establishing a JSON-RPC connection with a party that exists outside your own trust boundary, consider
37 | the threats and how to mitigate them at your application level.
38 |
39 | [spec]: https://www.jsonrpc.org/specification
40 |
--------------------------------------------------------------------------------
/docfx/toc.yml:
--------------------------------------------------------------------------------
1 | items:
2 | - name: Docs
3 | href: docs/
4 | - name: Exotic Types
5 | href: exotic_types/
6 | - name: API
7 | href: api/
8 | - name: GitHub
9 | href: https://github.com/microsoft/vs-streamjsonrpc
10 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "9.0.203",
4 | "rollForward": "patch",
5 | "allowPrerelease": false
6 | },
7 | "msbuild-sdks": {
8 | "Microsoft.Build.NoTargets": "3.7.56"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/init.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | SETLOCAL
3 | set PS1UnderCmd=1
4 |
5 | :: Get the datetime in a format that can go in a filename.
6 | set _my_datetime=%date%_%time%
7 | set _my_datetime=%_my_datetime: =_%
8 | set _my_datetime=%_my_datetime::=%
9 | set _my_datetime=%_my_datetime:/=_%
10 | set _my_datetime=%_my_datetime:.=_%
11 | set CmdEnvScriptPath=%temp%\envvarscript_%_my_datetime%.cmd
12 |
13 | powershell.exe -NoProfile -NoLogo -ExecutionPolicy bypass -Command "try { & '%~dpn0.ps1' %*; exit $LASTEXITCODE } catch { write-host $_; exit 1 }"
14 |
15 | :: Set environment variables in the parent cmd.exe process.
16 | IF EXIST "%CmdEnvScriptPath%" (
17 | ENDLOCAL
18 | CALL "%CmdEnvScriptPath%"
19 | DEL "%CmdEnvScriptPath%"
20 | )
21 |
--------------------------------------------------------------------------------
/nuget.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/settings.VisualStudio.json:
--------------------------------------------------------------------------------
1 | {
2 | "textEditor.codeCleanup.profile": "profile1"
3 | }
4 |
--------------------------------------------------------------------------------
/src/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.cs]
2 |
3 | dotnet_diagnostic.VSTHRD111.severity = error
4 | dotnet_diagnostic.VSTHRD100.severity = error
5 | dotnet_diagnostic.VSTHRD200.severity = error
6 |
--------------------------------------------------------------------------------
/src/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Runtime.InteropServices;
5 |
6 | [assembly: DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
7 |
--------------------------------------------------------------------------------
/src/AssemblyInfo.vb:
--------------------------------------------------------------------------------
1 | ' Copyright (c) Microsoft Corporation. All rights reserved.
2 | ' Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | Imports System.Runtime.InteropServices
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | README.md
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | PackageIcon.png
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/OptProf.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | IBC
5 | Common7\IDE\PrivateAssemblies\$(TargetFileName)
6 | /ExeConfig:"%VisualStudio.InstallationUnderTest.Path%\Common7\IDE\vsn.exe"
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/PackageIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/vs-streamjsonrpc/23f1c7d9ff245fef4b7beb7703b97fa1bc7476b2/src/PackageIcon.png
--------------------------------------------------------------------------------
/src/StreamJsonRpc/CommonMethodNameTransforms.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Text.Json;
5 |
6 | namespace StreamJsonRpc;
7 |
8 | ///
9 | /// Common RPC method transform functions that may be supplied to
10 | /// by way of .
11 | ///
12 | public static class CommonMethodNameTransforms
13 | {
14 | ///
15 | /// Gets a function that converts a given string from PascalCase to camelCase.
16 | ///
17 | public static Func CamelCase
18 | {
19 | get
20 | {
21 | return name =>
22 | {
23 | if (name is null)
24 | {
25 | throw new ArgumentNullException();
26 | }
27 |
28 | return Utilities.ToCamelCase(name);
29 | };
30 | }
31 | }
32 |
33 | ///
34 | /// Gets a function that prepends a particular string in front of any RPC method name.
35 | ///
36 | ///
37 | /// The prefix to prepend to any method name.
38 | /// This value must not be null.
39 | /// When this value is the empty string, no transformation is performed by the returned function.
40 | ///
41 | /// The transform function.
42 | public static Func Prepend(string prefix)
43 | {
44 | Requires.NotNull(prefix, nameof(prefix));
45 |
46 | if (prefix.Length == 0)
47 | {
48 | return name => name;
49 | }
50 | else
51 | {
52 | // Using a local variable for the closure avoids C# from allocating the closure
53 | // earlier in the method, which would impact even the fast path.
54 | string localPrefix = prefix;
55 | return name => localPrefix + name;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/DisposableAction.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc;
5 |
6 | internal class DisposableAction : IDisposableObservable
7 | {
8 | private static readonly Action EmptyAction = () => { };
9 | private Action? disposeAction;
10 |
11 | internal DisposableAction(Action? disposeAction)
12 | {
13 | this.disposeAction = disposeAction ?? EmptyAction;
14 | }
15 |
16 | public bool IsDisposed => this.disposeAction is null;
17 |
18 | public void Dispose()
19 | {
20 | Interlocked.Exchange(ref this.disposeAction, null)?.Invoke();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/EventArgs/DisconnectedReason.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc;
5 |
6 | ///
7 | /// Identifies a reason for a stream disconnection.
8 | ///
9 | public enum DisconnectedReason
10 | {
11 | ///
12 | /// An error occurred while accessing the stream.
13 | ///
14 | StreamError,
15 |
16 | ///
17 | /// A syntax or schema error while reading a JSON-RPC packet occurred.
18 | ///
19 | ParseError,
20 |
21 | ///
22 | /// The instance was disposed.
23 | ///
24 | LocallyDisposed,
25 |
26 | ///
27 | /// The underlying transport was closed by the remote party.
28 | ///
29 | RemotePartyTerminated,
30 |
31 | ///
32 | /// A fatal exception was thrown in a local method that was requested by the remote party.
33 | ///
34 | ///
35 | /// Exceptions thrown by locally dispatched method calls are not considered fatal by default.
36 | /// The method may be overridden
37 | /// by an application in order to enable a JSON-RPC server to throw an exception that can terminate
38 | /// the entire connection.
39 | ///
40 | FatalException,
41 |
42 | ///
43 | /// An extensibility point was leveraged locally and broke the contract.
44 | ///
45 | LocalContractViolation,
46 |
47 | ///
48 | /// The remote party violated the JSON-RPC protocol.
49 | ///
50 | RemoteProtocolViolation,
51 | }
52 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/ExceptionProcessing.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using StreamJsonRpc.Protocol;
5 |
6 | namespace StreamJsonRpc;
7 |
8 | ///
9 | /// Enumerates the exception handling behaviors that are built into the class.
10 | ///
11 | ///
12 | public enum ExceptionProcessing
13 | {
14 | ///
15 | /// Exceptions thrown by the server are serialized as the simple class
16 | /// and the default error code is .
17 | /// The client experiences a whose property
18 | /// is the deserialized .
19 | ///
20 | CommonErrorData,
21 |
22 | ///
23 | /// Exceptions thrown by the server are serialized via the mechanism and captures more detail,
24 | /// using the error code .
25 | /// These are deserialized with the original exception types as inner exceptions of the thrown at the client.
26 | /// The is also set to an instance of that resembles the inner exception tree.
27 | ///
28 | ISerializable,
29 | }
30 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Exceptions/BadRpcHeaderException.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc;
5 |
6 | ///
7 | /// An exception thrown when a deserialized message has a bad header.
8 | ///
9 | ///
10 | [Serializable]
11 | public class BadRpcHeaderException : RemoteRpcException
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | /// The message.
17 | public BadRpcHeaderException(string? message)
18 | : base(message)
19 | {
20 | }
21 |
22 | ///
23 | /// Initializes a new instance of the class.
24 | ///
25 | /// The message.
26 | /// The inner exception.
27 | public BadRpcHeaderException(string? message, Exception? innerException)
28 | : base(message, innerException)
29 | {
30 | }
31 |
32 | ///
33 | /// Initializes a new instance of the class.
34 | ///
35 | /// Serialization info.
36 | /// Streaming context.
37 | #if NET8_0_OR_GREATER
38 | [Obsolete]
39 | #endif
40 | protected BadRpcHeaderException(
41 | System.Runtime.Serialization.SerializationInfo info,
42 | System.Runtime.Serialization.StreamingContext context)
43 | : base(info, context)
44 | {
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Exceptions/ConnectionLostException.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc;
5 |
6 | ///
7 | /// An exception used to fault a returned from a request
8 | /// when the request could not be completed or the response cannot be received because the connection dropped.
9 | ///
10 | [System.Serializable]
11 | public class ConnectionLostException : RemoteRpcException
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | public ConnectionLostException()
17 | : this(Resources.ConnectionDropped)
18 | {
19 | }
20 |
21 | ///
22 | /// Initializes a new instance of the class.
23 | ///
24 | /// The message that describes the error.
25 | public ConnectionLostException(string? message)
26 | : base(message)
27 | {
28 | }
29 |
30 | ///
31 | /// Initializes a new instance of the class.
32 | ///
33 | /// The error message that explains the reason for the exception.
34 | /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.
35 | public ConnectionLostException(string? message, Exception? innerException)
36 | : base(message, innerException)
37 | {
38 | }
39 |
40 | ///
41 | /// Initializes a new instance of the class.
42 | ///
43 | /// Serialization info.
44 | /// Streaming context.
45 | #if NET8_0_OR_GREATER
46 | [Obsolete]
47 | #endif
48 | protected ConnectionLostException(
49 | System.Runtime.Serialization.SerializationInfo info,
50 | System.Runtime.Serialization.StreamingContext context)
51 | : base(info, context)
52 | {
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Exceptions/LocalRpcException.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using StreamJsonRpc.Protocol;
5 |
6 | namespace StreamJsonRpc;
7 |
8 | ///
9 | /// An exception that may be thrown within a locally invoked server method, and carries with it data that influences the JSON-RPC error message's error object.
10 | ///
11 | public class LocalRpcException : Exception
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | public LocalRpcException()
17 | {
18 | }
19 |
20 | ///
21 | /// Initializes a new instance of the class.
22 | ///
23 | /// The error message that explains the reason for the exception.
24 | public LocalRpcException(string? message)
25 | : base(message)
26 | {
27 | }
28 |
29 | ///
30 | /// Initializes a new instance of the class.
31 | ///
32 | /// The error message that explains the reason for the exception.
33 | /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.
34 | public LocalRpcException(string? message, Exception? inner)
35 | : base(message, inner)
36 | {
37 | }
38 |
39 | ///
40 | /// Gets or sets the value for the error.data property.
41 | ///
42 | public object? ErrorData { get; set; }
43 |
44 | ///
45 | /// Gets or sets the value for the error.code property.
46 | ///
47 | ///
48 | /// The default value is set to a special general error code: .
49 | /// This may be set to a more meaningful error code for the application that allows the client to programatically respond to the error condition.
50 | /// Application-defined values should avoid the [-32768, -32000] range, which is reserved for the JSON-RPC protocol itself.
51 | ///
52 | public int ErrorCode { get; set; } = (int)JsonRpcErrorCode.InvocationError;
53 | }
54 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Exceptions/RemoteSerializationException.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using StreamJsonRpc.Protocol;
5 |
6 | namespace StreamJsonRpc;
7 |
8 | ///
9 | /// An exception thrown from back to the client from various request methods when the server failed to serialize the response.
10 | ///
11 | ///
12 | /// This exception comes from the error code.
13 | ///
14 | [Serializable]
15 | public class RemoteSerializationException : RemoteRpcException
16 | {
17 | ///
18 | /// Initializes a new instance of the class.
19 | ///
20 | ///
21 | public RemoteSerializationException(string? message, object? errorData, object? deserializedErrorData)
22 | : base(message)
23 | {
24 | this.ErrorCode = JsonRpcErrorCode.ResponseSerializationFailure;
25 | this.ErrorData = errorData;
26 | this.DeserializedErrorData = deserializedErrorData;
27 | }
28 |
29 | ///
30 | /// Initializes a new instance of the class.
31 | ///
32 | /// Serialization info.
33 | /// Streaming context.
34 | #if NET8_0_OR_GREATER
35 | [Obsolete]
36 | #endif
37 | protected RemoteSerializationException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext)
38 | : base(serializationInfo, streamingContext)
39 | {
40 | throw new NotImplementedException();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Exceptions/UnexpectedEmptyEnumerableResponseException.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc;
5 |
6 | internal class UnexpectedEmptyEnumerableResponseException : RemoteRpcException
7 | {
8 | ///
9 | /// Initializes a new instance of the class.
10 | ///
11 | ///
12 | public UnexpectedEmptyEnumerableResponseException(string? message)
13 | : base(message)
14 | {
15 | }
16 |
17 | ///
18 | /// Initializes a new instance of the class.
19 | ///
20 | ///
21 | public UnexpectedEmptyEnumerableResponseException(string? message, Exception? innerException)
22 | : base(message, innerException)
23 | {
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Exceptions/UnrecognizedJsonRpcMessageException.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Runtime.Serialization;
5 |
6 | namespace StreamJsonRpc;
7 |
8 | ///
9 | /// An exception thrown when an incoming JSON-RPC message could not be recognized as conforming to any known JSON-RPC message.
10 | ///
11 | [Serializable]
12 | public class UnrecognizedJsonRpcMessageException : RemoteRpcException
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | public UnrecognizedJsonRpcMessageException()
18 | : base(Resources.UnrecognizableMessage)
19 | {
20 | }
21 |
22 | ///
23 | /// Initializes a new instance of the class.
24 | ///
25 | /// The error message that explains the reason for the exception.
26 | public UnrecognizedJsonRpcMessageException(string? message)
27 | : base(message)
28 | {
29 | }
30 |
31 | ///
32 | /// Initializes a new instance of the class.
33 | ///
34 | /// The error message that explains the reason for the exception.
35 | /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.
36 | public UnrecognizedJsonRpcMessageException(string? message, Exception? innerException)
37 | : base(message, innerException)
38 | {
39 | }
40 |
41 | ///
42 | /// Initializes a new instance of the class.
43 | ///
44 | /// Serialization info.
45 | /// Streaming context.
46 | #if NET8_0_OR_GREATER
47 | [Obsolete]
48 | #endif
49 | protected UnrecognizedJsonRpcMessageException(SerializationInfo info, StreamingContext context)
50 | : base(info, context)
51 | {
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Hex.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Runtime.InteropServices;
5 |
6 | namespace StreamJsonRpc;
7 |
8 | internal static class Hex
9 | {
10 | private static readonly byte[] HexBytes = "0123456789abcdef"u8.ToArray();
11 | private static readonly byte[] ReverseHexDigits = BuildReverseHexDigits();
12 |
13 | internal static void Encode(ReadOnlySpan src, ref Span dest)
14 | {
15 | Span bytes = MemoryMarshal.Cast(dest);
16 |
17 | // Inspired by http://stackoverflow.com/questions/623104/c-byte-to-hex-string/3974535#3974535
18 | int lengthInNibbles = src.Length * 2;
19 |
20 | for (int i = 0; i < (lengthInNibbles & -2); i++)
21 | {
22 | int index0 = +i >> 1;
23 | var b = (byte)(src[index0] >> 4);
24 | bytes[(2 * i) + 1] = 0;
25 | bytes[2 * i++] = HexBytes[b];
26 |
27 | b = (byte)(src[index0] & 0x0F);
28 | bytes[(2 * i) + 1] = 0;
29 | bytes[2 * i] = HexBytes[b];
30 | }
31 |
32 | dest = dest.Slice(lengthInNibbles);
33 | }
34 |
35 | internal static void Decode(ReadOnlySpan value, Span bytes)
36 | {
37 | for (int i = 0; i < value.Length; i++)
38 | {
39 | int c1 = ReverseHexDigits[value[i++] - '0'] << 4;
40 | int c2 = ReverseHexDigits[value[i] - '0'];
41 |
42 | bytes[i >> 1] = (byte)(c1 + c2);
43 | }
44 | }
45 |
46 | private static byte[] BuildReverseHexDigits()
47 | {
48 | var bytes = new byte['f' - '0' + 1];
49 |
50 | for (int i = 0; i < 10; i++)
51 | {
52 | bytes[i] = (byte)i;
53 | }
54 |
55 | for (int i = 10; i < 16; i++)
56 | {
57 | bytes[i + 'a' - '0' - 0x0a] = (byte)i;
58 | bytes[i + 'A' - '0' - 0x0a] = (byte)i;
59 | }
60 |
61 | return bytes;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/IActivityTracingStrategy.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using StreamJsonRpc.Protocol;
5 |
6 | namespace StreamJsonRpc;
7 |
8 | ///
9 | /// Synchronizes contextual activities between an RPC client and server
10 | /// consistent with the W3C Trace Context specification.
11 | ///
12 | ///
13 | /// Implementations are required to be thread-safe.
14 | ///
15 | public interface IActivityTracingStrategy
16 | {
17 | ///
18 | /// Applies a contextual activity to an outbound RPC request.
19 | ///
20 | /// The outbound RPC request.
21 | ///
22 | /// This method may be invoked regardless of whether a contextual activity exists.
23 | ///
24 | void ApplyOutboundActivity(JsonRpcRequest request);
25 |
26 | ///
27 | /// Applies an activity described in an incoming RPC request to the current context so the dispatched method can inherit it.
28 | ///
29 | /// The inbound RPC request.
30 | /// An optional disposable object that can revert the effects taken by this method at the conclusion of the dispatched RPC server method.
31 | ///
32 | /// This method may be invoked regardless of whether an activity is identified in the incoming request.
33 | /// The may be referenced by the returned value if necessary.
34 | ///
35 | IDisposable? ApplyInboundActivity(JsonRpcRequest request);
36 | }
37 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/IJsonRpcAsyncMessageFormatter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Buffers;
5 | using System.IO.Pipelines;
6 | using StreamJsonRpc.Protocol;
7 |
8 | namespace StreamJsonRpc;
9 |
10 | ///
11 | /// An interface that offers serialization to an and asynchronous deserialization.
12 | ///
13 | public interface IJsonRpcAsyncMessageFormatter : IJsonRpcMessageFormatter
14 | {
15 | ///
16 | /// Deserializes a .
17 | ///
18 | /// The reader to deserialize from.
19 | /// A cancellation token.
20 | /// The deserialized .
21 | ValueTask DeserializeAsync(PipeReader reader, CancellationToken cancellationToken);
22 | }
23 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/IJsonRpcAsyncMessageTextFormatter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Buffers;
5 | using System.IO.Pipelines;
6 | using System.Text;
7 | using StreamJsonRpc.Protocol;
8 |
9 | namespace StreamJsonRpc;
10 |
11 | ///
12 | /// An interface that offers serialization to an and asynchronous deserialization
13 | /// and formats messages as JSON (text).
14 | ///
15 | public interface IJsonRpcAsyncMessageTextFormatter : IJsonRpcAsyncMessageFormatter, IJsonRpcMessageTextFormatter
16 | {
17 | ///
18 | /// Deserializes a sequence of bytes to a .
19 | ///
20 | /// The reader to deserialize from.
21 | /// The encoding to read the bytes from with. Must not be null.
22 | /// A cancellation token.
23 | /// The deserialized message.
24 | ValueTask DeserializeAsync(PipeReader reader, Encoding encoding, CancellationToken cancellationToken);
25 | }
26 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/IJsonRpcClientProxy.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc;
5 |
6 | ///
7 | /// Implemented by dynamically generated proxies returned from and its overloads
8 | /// to provide access to additional JSON-RPC functionality.
9 | ///
10 | public interface IJsonRpcClientProxy : IDisposable
11 | {
12 | ///
13 | /// Gets the instance behind this proxy.
14 | ///
15 | JsonRpc JsonRpc { get; }
16 | }
17 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/IJsonRpcClientProxyInternal.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc;
5 |
6 | ///
7 | /// An interface implemented by dynamic proxies generated by .
8 | ///
9 | internal interface IJsonRpcClientProxyInternal : IJsonRpcClientProxy, IDisposableObservable
10 | {
11 | ///
12 | /// Occurs when a method is invoked on the proxy but before it is sent over RPC.
13 | ///
14 | ///
15 | /// The event arg is the CLR name of the method being invoked.
16 | /// Exceptions thrown from the handler propagate directly to the caller of the proxy and prevent the RPC request from being transmitted.
17 | ///
18 | event EventHandler CallingMethod;
19 |
20 | ///
21 | /// Occurs after a method is invoke and transmission over RPC has been queued.
22 | ///
23 | ///
24 | /// The event arg is the CLR name of the method that was invoked.
25 | /// Exceptions thrown from the handler propagate directly to the caller of the proxy, although the RPC request was already transmitted.
26 | ///
27 | event EventHandler CalledMethod;
28 |
29 | ///
30 | /// Gets the handle of the object that is being marshaled over RPC for which this is a proxy, if applicable.
31 | ///
32 | long? MarshaledObjectHandle { get; }
33 | }
34 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/IJsonRpcInstanceContainer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc;
5 |
6 | ///
7 | /// Interface optionally implemented by implementations that need a reference to their owner class.
8 | ///
9 | public interface IJsonRpcInstanceContainer
10 | {
11 | ///
12 | /// Sets the instance.
13 | ///
14 | /// May be thrown when set more than once.
15 | JsonRpc Rpc { set; }
16 | }
17 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/IJsonRpcMessageFactory.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using StreamJsonRpc.Protocol;
5 |
6 | namespace StreamJsonRpc;
7 |
8 | ///
9 | /// An interface that allows instances to act as a factory for -derived types.
10 | ///
11 | public interface IJsonRpcMessageFactory
12 | {
13 | ///
14 | /// Creates an instance of suitable for transmission over the .
15 | ///
16 | /// An instance of .
17 | JsonRpcRequest CreateRequestMessage();
18 |
19 | ///
20 | /// Creates an instance of suitable for transmission over the .
21 | ///
22 | /// An instance of .
23 | JsonRpcError CreateErrorMessage();
24 |
25 | ///
26 | /// Creates an instance of suitable for transmission over the .
27 | ///
28 | /// An instance of .
29 | JsonRpcResult CreateResultMessage();
30 | }
31 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/IJsonRpcMessageFormatter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Buffers;
5 | using StreamJsonRpc.Protocol;
6 | using StreamJsonRpc.Reflection;
7 |
8 | namespace StreamJsonRpc;
9 |
10 | ///
11 | /// An interface that offers serialization to and from a sequence of bytes.
12 | ///
13 | public interface IJsonRpcMessageFormatter
14 | {
15 | ///
16 | /// Deserializes a .
17 | ///
18 | /// A sequence of bytes to deserialize.
19 | /// The deserialized .
20 | JsonRpcMessage Deserialize(ReadOnlySequence contentBuffer);
21 |
22 | ///
23 | /// Serializes a .
24 | ///
25 | /// The receiver of the serialized bytes.
26 | /// The message to serialize.
27 | void Serialize(IBufferWriter bufferWriter, JsonRpcMessage message);
28 |
29 | ///
30 | /// Gets a JSON representation for a given message for tracing purposes.
31 | ///
32 | /// The message to be traced.
33 | /// Any object whose method will produce a human-readable JSON string, suitable for tracing.
34 | [Obsolete("Tracing is now done via the " + nameof(IJsonRpcTracingCallbacks) + " and " + nameof(IJsonRpcFormatterTracingCallbacks) + " interfaces. Formatters may throw NotSupportedException from this method.")]
35 | object GetJsonText(JsonRpcMessage message);
36 | }
37 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/IJsonRpcMessageTextFormatter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Buffers;
5 | using System.Text;
6 | using StreamJsonRpc.Protocol;
7 |
8 | namespace StreamJsonRpc;
9 |
10 | ///
11 | /// An that formats messages as JSON (text).
12 | ///
13 | public interface IJsonRpcMessageTextFormatter : IJsonRpcMessageFormatter
14 | {
15 | ///
16 | /// Gets or sets the encoding used for serialization for methods that do not take an explicit .
17 | ///
18 | /// Never null.
19 | /// Thrown at an attempt to set the value to null.
20 | Encoding Encoding { get; set; }
21 |
22 | ///
23 | /// Deserializes a sequence of bytes to a .
24 | ///
25 | /// The bytes to deserialize.
26 | /// The encoding to read the bytes in with. Must not be null.
27 | /// The deserialized message.
28 | JsonRpcMessage Deserialize(ReadOnlySequence contentBuffer, Encoding encoding);
29 | }
30 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/IRpcMarshaledContext.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc;
5 |
6 | ///
7 | /// Represents an object to be marshaled and provides check or influence its lifetime.
8 | ///
9 | /// The interface type whose methods are exposed for RPC invocation on the target object.
10 | ///
11 | /// When an object implementing this interface is disposed
12 | /// the marshaling relationship is immediately terminated.
13 | /// This releases resources allocated to facilitating the marshaling of the object
14 | /// and prevents any further invocations of the object by the remote party.
15 | /// If the underlying object implements then its
16 | /// method is also invoked.
17 | ///
18 | ///
19 | /// This type is an interface rather than a class so that users can enjoy covariance on the generic type parameter.
20 | ///
21 | internal interface IRpcMarshaledContext : IDisposableObservable
22 | where T : class
23 | {
24 | ///
25 | /// Occurs when the marshalling relationship is released,
26 | /// whether by a local call to
27 | /// or at the remote party's request.
28 | ///
29 | event EventHandler? Disposed;
30 |
31 | ///
32 | /// Gets the marshalable proxy that should be used in the RPC message.
33 | ///
34 | T Proxy { get; }
35 |
36 | ///
37 | /// Gets the to associate with this object when it becomes a RPC target.
38 | ///
39 | JsonRpcTargetOptions JsonRpcTargetOptions { get; }
40 | }
41 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/OptProf.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | IBC
5 | Common7\IDE\PublicAssemblies\StreamJsonRpc.2.x\$(TargetFileName)
6 | /ExeConfig:"%VisualStudio.InstallationUnderTest.Path%\Common7\IDE\vsn.exe"
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Resources;
5 |
6 | [assembly: NeutralResourcesLanguage("en-US")]
7 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Protocol/Constants.cs:
--------------------------------------------------------------------------------
1 | #pragma warning disable SA1303 // Const field names should begin with upper-case letter
2 |
3 | namespace StreamJsonRpc.Protocol;
4 |
5 | internal static class Constants
6 | {
7 | internal const string jsonrpc = "jsonrpc";
8 | internal const string id = "id";
9 |
10 | internal static class Request
11 | {
12 | internal const string method = "method";
13 | internal const string @params = "params";
14 | internal const string traceparent = "traceparent";
15 | internal const string tracestate = "tracestate";
16 |
17 | internal static bool IsPropertyReserved(string propertyName)
18 | {
19 | Requires.NotNull(propertyName, nameof(propertyName));
20 |
21 | return
22 | propertyName.Equals(jsonrpc, StringComparison.Ordinal) ||
23 | propertyName.Equals(method, StringComparison.Ordinal) ||
24 | propertyName.Equals(@params, StringComparison.Ordinal) ||
25 | propertyName.Equals(traceparent, StringComparison.Ordinal) ||
26 | propertyName.Equals(tracestate, StringComparison.Ordinal) ||
27 | propertyName.Equals(id, StringComparison.Ordinal);
28 | }
29 | }
30 |
31 | internal static class Result
32 | {
33 | internal const string result = "result";
34 |
35 | internal static bool IsPropertyReserved(string propertyName)
36 | {
37 | Requires.NotNull(propertyName, nameof(propertyName));
38 |
39 | return
40 | propertyName.Equals(jsonrpc, StringComparison.Ordinal) ||
41 | propertyName.Equals(result, StringComparison.Ordinal) ||
42 | propertyName.Equals(id, StringComparison.Ordinal);
43 | }
44 | }
45 |
46 | internal static class Error
47 | {
48 | internal const string error = "error";
49 |
50 | internal static bool IsPropertyReserved(string propertyName)
51 | {
52 | Requires.NotNull(propertyName, nameof(propertyName));
53 |
54 | return
55 | propertyName.Equals(jsonrpc, StringComparison.Ordinal) ||
56 | propertyName.Equals(error, StringComparison.Ordinal) ||
57 | propertyName.Equals(id, StringComparison.Ordinal);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Protocol/IJsonRpcMessageWithId.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc.Protocol;
5 |
6 | ///
7 | /// An interface found on JSON-RPC protocol messages that contain an id field.
8 | ///
9 | public interface IJsonRpcMessageWithId
10 | {
11 | ///
12 | /// Gets or sets the ID on a message.
13 | ///
14 | RequestId RequestId { get; set; }
15 | }
16 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/README.md:
--------------------------------------------------------------------------------
1 | # StreamJsonRpc
2 |
3 | StreamJsonRpc is a cross-platform, .NET portable library that implements the
4 | [JSON-RPC][JSONRPC] wire protocol.
5 |
6 | It works over [Stream](https://docs.microsoft.com/dotnet/api/system.io.stream), [WebSocket](https://docs.microsoft.com/dotnet/api/system.net.websockets.websocket), or System.IO.Pipelines pipes, independent of the underlying transport.
7 |
8 | Bonus features beyond the JSON-RPC spec include:
9 |
10 | 1. Request cancellation
11 | 1. .NET Events as notifications
12 | 1. Dynamic client proxy generation
13 | 1. Support for [compact binary serialization](https://microsoft.github.io/vs-streamjsonrpc/docs/extensibility.html) via MessagePack
14 | 1. Pluggable architecture for custom message handling and formatting.
15 |
16 | Learn about the use cases for JSON-RPC and how to use this library from our [documentation](https://microsoft.github.io/vs-streamjsonrpc/docs/getting-started.html).
17 |
18 | ## Compatibility
19 |
20 | This library has been tested with and is compatible with the following other
21 | JSON-RPC libraries:
22 |
23 | * [json-rpc-peer][json-rpc-peer] (npm)
24 | * [vscode-jsonrpc][vscode-jsonrpc] (npm)
25 |
26 | [JSONRPC]: https://www.jsonrpc.org/
27 | [json-rpc-peer]: https://www.npmjs.com/package/json-rpc-peer
28 | [vscode-jsonrpc]: https://www.npmjs.com/package/vscode-jsonrpc
29 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Reflection/CodeGenHelpers.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.ComponentModel;
5 |
6 | namespace StreamJsonRpc.Reflection;
7 |
8 | ///
9 | /// Helper methods for dynamically generated proxies to invoke.
10 | /// This type is only public because mono does not support IgnoresAccessChecksToAttribute. Do not call directly.
11 | ///
12 | [EditorBrowsable(EditorBrowsableState.Never)]
13 | [Obsolete("This class is only for invoking from dynamically generated code.")]
14 | public static class CodeGenHelpers
15 | {
16 | #pragma warning disable VSTHRD200 // Use "Async" suffix in names of methods that return an awaitable type.
17 | ///
18 | public static IAsyncEnumerable CreateAsyncEnumerableProxy(Task> enumerableTask, CancellationToken defaultCancellationToken) => new ProxyGeneration.AsyncEnumerableProxy(enumerableTask, defaultCancellationToken);
19 | #pragma warning restore VSTHRD200 // Use "Async" suffix in names of methods that return an awaitable type.
20 | }
21 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Reflection/IJsonRpcFormatterCallbacks.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc.Reflection;
5 |
6 | ///
7 | /// Implemented by to expose callbacks allowing an to perform resource cleanup.
8 | ///
9 | public interface IJsonRpcFormatterCallbacks
10 | {
11 | ///
12 | /// Occurs when aborts the transmission of an outbound request (that was not a notification).
13 | ///
14 | ///
15 | /// This usually occurs because of an exception during serialization or transmission, possibly due to cancellation.
16 | ///
17 | event EventHandler RequestTransmissionAborted;
18 |
19 | ///
20 | /// Occurs when receives a response to a previously sent request.
21 | ///
22 | event EventHandler ResponseReceived;
23 |
24 | ///
25 | /// Occurs when transmits a response message.
26 | ///
27 | event EventHandler ResponseSent;
28 | }
29 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Reflection/IJsonRpcFormatterState.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc.Reflection;
5 |
6 | ///
7 | /// An interface implemented by instances
8 | /// to support some formatter extensions such as .
9 | ///
10 | public interface IJsonRpcFormatterState
11 | {
12 | ///
13 | /// Gets the id of the request or response currently being serialized.
14 | ///
15 | public RequestId SerializingMessageWithId { get; }
16 |
17 | ///
18 | /// Gets the ID of the response currently being deserialized.
19 | ///
20 | public RequestId DeserializingMessageWithId { get; }
21 |
22 | ///
23 | /// Gets a value indicating whether a is being serialized.
24 | ///
25 | ///
26 | /// A response is being serialized if this property's value is while is non-empty.
27 | ///
28 | public bool SerializingRequest { get; }
29 | }
30 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Reflection/IJsonRpcFormatterTracingCallbacks.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Buffers;
5 | using StreamJsonRpc.Protocol;
6 |
7 | namespace StreamJsonRpc.Reflection;
8 |
9 | ///
10 | /// Optionally implemented by a when it needs the fully serialized sequence in order to trace the JSON representation of the message.
11 | ///
12 | public interface IJsonRpcFormatterTracingCallbacks
13 | {
14 | ///
15 | /// Invites the formatter to call with the JSON representation of the message just serialized..
16 | ///
17 | /// The message that was just serialized.
18 | /// The encoded copy of the message, as it recently came from the method.
19 | void OnSerializationComplete(JsonRpcMessage message, ReadOnlySequence encodedMessage);
20 | }
21 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Reflection/IJsonRpcMessageBufferManager.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using StreamJsonRpc.Protocol;
5 |
6 | namespace StreamJsonRpc.Reflection;
7 |
8 | ///
9 | /// An interface that may be found on an object to request notification of when
10 | /// message deserialization is completed so buffers can be released or safely recycled.
11 | ///
12 | public interface IJsonRpcMessageBufferManager
13 | {
14 | ///
15 | /// Notifies that it is safe to free buffers held to deserialize the payload for a message because all deserialization attempts are completed.
16 | ///
17 | /// The message whose deserialization is done.
18 | ///
19 | /// Implementations are guaranteed to be called at least once for each message when deserialization is completed.
20 | /// This method will be invoked before the next request to .
21 | ///
22 | void DeserializationComplete(JsonRpcMessage message);
23 | }
24 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Reflection/IJsonRpcTracingCallbacks.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using StreamJsonRpc.Protocol;
5 |
6 | namespace StreamJsonRpc.Reflection;
7 |
8 | ///
9 | /// An interface implemented by for implementations to use to facilitate message tracing.
10 | ///
11 | public interface IJsonRpcTracingCallbacks
12 | {
13 | ///
14 | /// Occurs when the has serialized a message for transmission.
15 | ///
16 | /// The JSON-RPC message.
17 | /// The encoded form of the message. Calling on this should produce the JSON-RPC text of the message.
18 | void OnMessageSerialized(JsonRpcMessage message, object encodedMessage);
19 |
20 | ///
21 | /// Occurs when the has deserialized an incoming message.
22 | ///
23 | /// The JSON-RPC message.
24 | /// The encoded form of the message. Calling on this should produce the JSON-RPC text of the message.
25 | void OnMessageDeserialized(JsonRpcMessage message, object encodedMessage);
26 | }
27 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Reflection/JsonRpcIgnoreAttribute.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc;
5 |
6 | ///
7 | /// Attribute which identifies methods that should not be invokable over RPC.
8 | ///
9 | ///
10 | /// When adding an RPC target object via or other APIs,
11 | /// all public methods on the object default to being exposed to invocation by the client.
12 | /// When is set, even more methods are exposed.
13 | /// Applying this attribute to any method will ensure it can never be invoked directly by the RPC client.
14 | /// If and are applied to the same method,
15 | /// an exception will be thrown at the time of adding the object as an RPC target.
16 | ///
17 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
18 | public class JsonRpcIgnoreAttribute : Attribute
19 | {
20 | }
21 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Reflection/JsonRpcMessageEventArgs.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using StreamJsonRpc.Protocol;
5 |
6 | namespace StreamJsonRpc.Reflection;
7 |
8 | ///
9 | /// Carries the from request or response messages.
10 | ///
11 | public class JsonRpcMessageEventArgs : EventArgs
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | /// The ID from the request or response that the event is regarding.
17 | public JsonRpcMessageEventArgs(RequestId requestId)
18 | {
19 | Requires.Argument(!requestId.IsEmpty, nameof(requestId), "Non-default ID required.");
20 | this.RequestId = requestId;
21 | }
22 |
23 | ///
24 | /// Initializes a new instance of the class.
25 | ///
26 | /// The message the event is regarding.
27 | internal JsonRpcMessageEventArgs(IJsonRpcMessageWithId message)
28 | {
29 | Requires.NotNull(message, nameof(message));
30 | Requires.Argument(!message.RequestId.IsEmpty, nameof(message), "Non-default ID required.");
31 | this.RequestId = message.RequestId;
32 | }
33 |
34 | ///
35 | /// Gets the id on the request, result or error.
36 | ///
37 | public RequestId RequestId { get; private set; }
38 | }
39 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Reflection/JsonRpcResponseEventArgs.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using StreamJsonRpc.Protocol;
5 |
6 | namespace StreamJsonRpc.Reflection;
7 |
8 | ///
9 | /// Carries the and success status of response messages.
10 | ///
11 | public class JsonRpcResponseEventArgs : JsonRpcMessageEventArgs
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | /// The ID from the request or response that the event is regarding.
17 | /// A flag indicating whether the response is a result (as opposed to an error).
18 | public JsonRpcResponseEventArgs(RequestId requestId, bool isSuccessfulResponse)
19 | : base(requestId)
20 | {
21 | this.IsSuccessfulResponse = isSuccessfulResponse;
22 | }
23 |
24 | ///
25 | /// Initializes a new instance of the class.
26 | ///
27 | /// The message the event is regarding.
28 | internal JsonRpcResponseEventArgs(IJsonRpcMessageWithId message)
29 | : this(message.RequestId, message is JsonRpcResult)
30 | {
31 | }
32 |
33 | ///
34 | /// Gets a value indicating whether the response is a result (as opposed to an error).
35 | ///
36 | public bool IsSuccessfulResponse { get; }
37 | }
38 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Reflection/MethodSignatureAndTarget.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.Diagnostics;
5 | using System.Diagnostics.CodeAnalysis;
6 | using System.Reflection;
7 | using System.Runtime.CompilerServices;
8 |
9 | namespace StreamJsonRpc;
10 |
11 | [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")]
12 | internal struct MethodSignatureAndTarget : IEquatable
13 | {
14 | internal MethodSignatureAndTarget(MethodInfo method, object? target, JsonRpcMethodAttribute? attribute, SynchronizationContext? perMethodSynchronizationContext)
15 | {
16 | Requires.NotNull(method, nameof(method));
17 |
18 | this.Signature = new MethodSignature(method, attribute);
19 | this.Target = target;
20 | this.SynchronizationContext = perMethodSynchronizationContext;
21 | }
22 |
23 | internal MethodSignatureAndTarget(MethodSignature signature, object? target, SynchronizationContext? perMethodSynchronizationContext)
24 | {
25 | this.Signature = signature;
26 | this.Target = target;
27 | this.SynchronizationContext = perMethodSynchronizationContext;
28 | }
29 |
30 | internal MethodSignature Signature { get; }
31 |
32 | internal object? Target { get; }
33 |
34 | internal SynchronizationContext? SynchronizationContext { get; }
35 |
36 | [ExcludeFromCodeCoverage]
37 | private string DebuggerDisplay => this.ToString();
38 |
39 | ///
40 | public override bool Equals(object? obj)
41 | {
42 | return obj is MethodSignatureAndTarget other
43 | && this.Equals(other);
44 | }
45 |
46 | ///
47 | public bool Equals(MethodSignatureAndTarget other)
48 | {
49 | return this.Signature.Equals(other.Signature)
50 | && object.ReferenceEquals(this.Target, other.Target);
51 | }
52 |
53 | ///
54 | public override int GetHashCode()
55 | {
56 | return this.Signature.GetHashCode() + (this.Target is not null ? RuntimeHelpers.GetHashCode(this.Target) : 0);
57 | }
58 |
59 | ///
60 | public override string ToString() => $"{this.Signature} ({this.Target})";
61 | }
62 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/Reflection/RpcMarshalableAttribute.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc;
5 |
6 | ///
7 | /// Designates an interface that is used in an RPC contract to marshal the object so the receiver can invoke remote methods on it instead of serializing the object to send its data to the remote end.
8 | ///
9 | ///
10 | /// Learn more about marshable interfaces.
11 | ///
12 | [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = false)]
13 | public class RpcMarshalableAttribute : Attribute
14 | {
15 | ///
16 | /// Gets a value indicating whether the marshaled object is only allowed in requests
17 | /// and may only be invoked by the receiver until the response is sent.
18 | ///
19 | ///
20 | /// Objects marshaled via an interface attributed with this property set to true may only be used as RPC method parameters.
21 | /// They will not be allowed as return values from RPC methods.
22 | /// While the receiver may dispose of the proxy they receive, this disposal will not propagate to the sender,
23 | /// and their originating object will not be disposed of.
24 | /// The original object owner retains ownership of the lifetime of the object after the RPC call.
25 | ///
26 | public bool CallScopedLifetime { get; init; }
27 | }
28 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/RequestIdJsonConverter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using Newtonsoft.Json;
5 |
6 | namespace StreamJsonRpc;
7 |
8 | #pragma warning disable CA1812
9 | internal class RequestIdJsonConverter : JsonConverter
10 | #pragma warning restore CA1812
11 | {
12 | public override RequestId ReadJson(JsonReader reader, Type objectType, RequestId existingValue, bool hasExistingValue, JsonSerializer serializer)
13 | {
14 | switch (reader.TokenType)
15 | {
16 | case JsonToken.Integer: return new RequestId(reader.Value is int i ? i : (long)reader.Value!);
17 | case JsonToken.String: return new RequestId((string?)reader.Value);
18 | case JsonToken.Null: return RequestId.Null;
19 | default: throw new JsonSerializationException("Unexpected token type for request ID: " + reader.TokenType);
20 | }
21 | }
22 |
23 | public override void WriteJson(JsonWriter writer, RequestId value, JsonSerializer serializer)
24 | {
25 | if (value.Number.HasValue)
26 | {
27 | writer.WriteValue(value.Number.Value);
28 | }
29 | else
30 | {
31 | writer.WriteValue(value.String);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/RpcMarshaledContext.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc;
5 |
6 | ///
7 | internal class RpcMarshaledContext : IRpcMarshaledContext
8 | where T : class
9 | {
10 | ///
11 | /// Initializes a new instance of the class.
12 | ///
13 | /// The value that should be used in the object graph to be sent over RPC, to trigger marshaling.
14 | /// The to use when adding this object as an RPC target.
15 | internal RpcMarshaledContext(T value, JsonRpcTargetOptions options)
16 | {
17 | // We shouldn't reach this point with a proxy.
18 | Requires.Argument(value is not IJsonRpcClientProxyInternal, nameof(value), "Cannot marshal a proxy.");
19 |
20 | this.Proxy = value;
21 | this.JsonRpcTargetOptions = options;
22 | }
23 |
24 | ///
25 | public event EventHandler? Disposed;
26 |
27 | ///
28 | public T Proxy { get; private set; }
29 |
30 | ///
31 | public bool IsDisposed { get; private set; }
32 |
33 | ///
34 | public JsonRpcTargetOptions JsonRpcTargetOptions { get; }
35 |
36 | ///
37 | /// Immediately terminates the marshaling relationship.
38 | /// This releases resources allocated to facilitating the marshaling of the object
39 | /// and prevents any further invocations of the object by the remote party.
40 | /// If the underlying object implements then its
41 | /// method is also invoked.
42 | ///
43 | public void Dispose()
44 | {
45 | throw new NotImplementedException();
46 | #pragma warning disable CS0162 // Unreachable code detected
47 | this.IsDisposed = true;
48 | this.Disposed?.Invoke(this, EventArgs.Empty);
49 | #pragma warning restore CS0162 // Unreachable code detected
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/SharedUtilities.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace StreamJsonRpc;
5 |
6 | ///
7 | /// Utilities that are source-shared between the library and its tests.
8 | ///
9 | internal static class SharedUtilities
10 | {
11 | ///
12 | /// The various modes that can be used to test the class.
13 | ///
14 | internal enum EventSourceTestMode
15 | {
16 | ///
17 | /// ETW events are not forced on.
18 | ///
19 | None,
20 |
21 | ///
22 | /// ETW events are forced on and exceptions are swallowed as they would be in production.
23 | ///
24 | EmulateProduction,
25 |
26 | ///
27 | /// ETW events are forced on and exceptions are not swallowed, allowing tests to detect errors in ETW logging.
28 | ///
29 | DoNotSwallowExceptions,
30 | }
31 |
32 | internal static EventSourceTestMode GetEventSourceTestMode() => Environment.GetEnvironmentVariable("StreamJsonRpc_TestWithEventSource") switch
33 | {
34 | "1" => EventSourceTestMode.EmulateProduction,
35 | "2" => EventSourceTestMode.DoNotSwallowExceptions,
36 | _ => EventSourceTestMode.None,
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/StreamJsonRpc.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.0;netstandard2.1;net8.0
4 | prompt
5 | 4
6 | true
7 | A cross-platform .NETStandard library that implements the JSON-RPC wire protocol and can use System.IO.Stream, System.IO.Pipelines or WebSocket so you can use it with any transport.
8 | visualstudio stream json rpc jsonrpc
9 |
10 | $(NoWarn);SYSLIB0050
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/StreamJsonRpc/net8.0/PublicAPI.Unshipped.txt:
--------------------------------------------------------------------------------
1 | StreamJsonRpc.JsonRpc.Attach(System.ReadOnlySpan interfaceTypes, StreamJsonRpc.JsonRpcProxyOptions? options) -> object!
--------------------------------------------------------------------------------
/src/StreamJsonRpc/netstandard2.0/PublicAPI.Unshipped.txt:
--------------------------------------------------------------------------------
1 | StreamJsonRpc.JsonRpc.Attach(System.ReadOnlySpan interfaceTypes, StreamJsonRpc.JsonRpcProxyOptions? options) -> object!
--------------------------------------------------------------------------------
/src/StreamJsonRpc/netstandard2.1/PublicAPI.Unshipped.txt:
--------------------------------------------------------------------------------
1 | StreamJsonRpc.JsonRpc.Attach(System.ReadOnlySpan interfaceTypes, StreamJsonRpc.JsonRpcProxyOptions? options) -> object!
--------------------------------------------------------------------------------
/src/VSInsertionMetadata/ProfilingInputs.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/VSInsertionMetadata/StreamJsonRpc.VSInsertionMetadata.proj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.0
4 | true
5 | $(RepoRootPath)bin\Packages\$(Configuration)\VSRepo\
6 | false
7 | false
8 | Contains metadata for insertion into VS.
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/stylecop.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
3 | "settings": {
4 | "documentationRules": {
5 | "companyName": "Microsoft Corporation",
6 | "copyrightText": "Copyright (c) {companyName}. All rights reserved.\nLicensed under the {licenseName} license. See {licenseFile} file in the project root for full license information.",
7 | "variables": {
8 | "licenseName": "MIT",
9 | "licenseFile": "LICENSE"
10 | },
11 | "fileNamingConvention": "stylecop",
12 | "xmlHeader": false
13 | },
14 | "namingRules": {
15 | "tupleElementNameCasing": "PascalCase"
16 | },
17 | "orderingRules": {
18 | "usingDirectivesPlacement": "outsideNamespace"
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/test/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.cs]
2 |
3 | # SA1600: Elements should be documented
4 | dotnet_diagnostic.SA1600.severity = silent
5 |
6 | # SA1601: Partial elements should be documented
7 | dotnet_diagnostic.SA1601.severity = silent
8 |
9 | # SA1602: Enumeration items should be documented
10 | dotnet_diagnostic.SA1602.severity = silent
11 |
12 | # SA1615: Element return value should be documented
13 | dotnet_diagnostic.SA1615.severity = silent
14 |
15 | dotnet_diagnostic.VSTHRD001.severity = none
16 | dotnet_diagnostic.VSTHRD002.severity = silent
17 | dotnet_diagnostic.VSTHRD003.severity = none
18 | dotnet_diagnostic.VSTHRD012.severity = none
19 |
20 | # VSTHRD103: Call async methods when in an async method
21 | dotnet_diagnostic.VSTHRD103.severity = silent
22 |
23 | # VSTHRD111: Use .ConfigureAwait(bool)
24 | dotnet_diagnostic.VSTHRD111.severity = none
25 |
26 | # VSTHRD200: Use Async suffix for async methods
27 | dotnet_diagnostic.VSTHRD200.severity = silent
28 |
29 | # CA1014: Mark assemblies with CLSCompliant
30 | dotnet_diagnostic.CA1014.severity = none
31 |
32 | # CA1050: Declare types in namespaces
33 | dotnet_diagnostic.CA1050.severity = none
34 |
35 | # CA1303: Do not pass literals as localized parameters
36 | dotnet_diagnostic.CA1303.severity = none
37 |
38 | # CS1591: Missing XML comment for publicly visible type or member
39 | dotnet_diagnostic.CS1591.severity = silent
40 |
41 | # CA1707: Identifiers should not contain underscores
42 | dotnet_diagnostic.CA1707.severity = silent
43 |
44 | # CA1062: Validate arguments of public methods
45 | dotnet_diagnostic.CA1062.severity = suggestion
46 |
47 | # CA1063: Implement IDisposable Correctly
48 | dotnet_diagnostic.CA1063.severity = silent
49 |
50 | # CA1816: Dispose methods should call SuppressFinalize
51 | dotnet_diagnostic.CA1816.severity = silent
52 |
53 | # CA2007: Consider calling ConfigureAwait on the awaited task
54 | dotnet_diagnostic.CA2007.severity = none
55 |
56 | # SA1401: Fields should be private
57 | dotnet_diagnostic.SA1401.severity = silent
58 |
59 | # SA1133: Do not combine attributes
60 | dotnet_diagnostic.SA1133.severity = silent
61 |
--------------------------------------------------------------------------------
/test/Benchmarks/.gitignore:
--------------------------------------------------------------------------------
1 | BenchmarkDotNet.Artifacts/
2 |
--------------------------------------------------------------------------------
/test/Benchmarks/Benchmarks.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0;net472
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/test/Benchmarks/InvokeBenchmarks.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System.IO.Pipelines;
5 | using BenchmarkDotNet.Attributes;
6 | using Microsoft;
7 | using Nerdbank.Streams;
8 | using StreamJsonRpc;
9 |
10 | namespace Benchmarks;
11 |
12 | [MemoryDiagnoser]
13 | public class InvokeBenchmarks
14 | {
15 | private JsonRpc clientRpc = null!;
16 | private JsonRpc serverRpc = null!;
17 |
18 | [Params("JSON", "MessagePack")]
19 | public string Formatter { get; set; } = null!;
20 |
21 | [GlobalSetup]
22 | public void Setup()
23 | {
24 | (IDuplexPipe, IDuplexPipe) duplex = FullDuplexStream.CreatePipePair();
25 | this.clientRpc = new JsonRpc(CreateHandler(duplex.Item1));
26 | this.clientRpc.StartListening();
27 |
28 | this.serverRpc = new JsonRpc(CreateHandler(duplex.Item2));
29 | this.serverRpc.AddLocalRpcTarget(new Server());
30 | this.serverRpc.StartListening();
31 |
32 | IJsonRpcMessageHandler CreateHandler(IDuplexPipe pipe)
33 | {
34 | return this.Formatter switch
35 | {
36 | "JSON" => new HeaderDelimitedMessageHandler(pipe, new JsonMessageFormatter()),
37 | "MessagePack" => new LengthHeaderMessageHandler(pipe, new MessagePackFormatter()),
38 | _ => throw Assumes.NotReachable(),
39 | };
40 | }
41 | }
42 |
43 | [Benchmark]
44 | public Task InvokeAsync_NoArgs() => this.clientRpc.InvokeAsync(nameof(Server.NoOp), Array.Empty