csharp-language-server-protocol
csharp-language-server-protocol copied to clipboard
JSON RPC documentation or example app request
Would it be possible to add to the documentation or as an example app something like:
using MediatR;
using Microsoft.Extensions.Hosting;
using OmniSharp.Extensions.JsonRpc;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static Task Main(string[] args) =>
new HostBuilder()
.ConfigureServices((context, services) =>
services.AddJsonRpcServer(options =>
options
.WithInput(Console.OpenStandardInput())
.WithOutput(Console.OpenStandardOutput())
.WithHandler<PingHandler>()))
.Build()
.RunAsync();
class PingHandler : IJsonRpcRequestHandler<PingHandler.PingRequest, PingHandler.PongResponse>
{
[Method("ping", Direction.ClientToServer)]
public Task<PongResponse> Handle(PingRequest request, CancellationToken cancellationToken)
{
return Task.FromResult(new PongResponse
{
pong = request.ping + 1
});
}
public class PongResponse
{
public int pong;
}
public class PingRequest : IRequest<PongResponse>
{
public int ping;
}
}
}
}
It requres the nuget packages:
Microsoft.Extensions.Hosting
OmniSharp.Extensions.JsonRpc
When run, it should be able to read from the terminal something like:
{ "jsonrpc":"2.0", "id":2, "method": "ping", "params": { "ping": 41 }}
and throw out a { pong: 42} response.
It currently doesn't work, it never creates the json rpc service really, I will be checking now the source code of the tests, but if there was a minimal working example app, it'd get me going much faster, it'd probably help with the adoption of this tool as well.
Ok, this seems to work, I just have a gut-feeling it is not very correct. I am not that confident in the way it await at the end, and if there is a better way to initialize the JsonRpcServer:
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OmniSharp.Extensions.JsonRpc;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static async Task Main(string[] args)
{
var cts = new CancellationTokenSource();
var host = new HostBuilder()
.ConfigureServices((context, services) =>
services.AddJsonRpcServer(options =>
options
.WithInput(Console.OpenStandardInput())
.WithOutput(Console.OpenStandardOutput())
.WithHandler<PingHandler>()))
.Build();
var jsonRPCServer = host.Services.GetRequiredService<JsonRpcServer>();
await jsonRPCServer.Initialize(cts.Token);
await host.RunAsync(cts.Token);
}
[Method("ping", Direction.ClientToServer)]
class PingHandler : IJsonRpcRequestHandler<PingHandler.PingRequest, PingHandler.PongResponse>
{
public Task<PongResponse> Handle(PingRequest request, CancellationToken cancellationToken)
{
return Task.FromResult(new PongResponse
{
pong = request.ping + 1
});
}
public class PongResponse
{
public int pong;
}
public class PingRequest : IRequest<PongResponse>
{
public int ping;
}
}
}
}
And the actual input you have to paste through the terminal to get a response and hit a breakpoint inside:
Content-Length: 61
{"jsonrpc":"2.0","id":1,"method":"ping","params":{"ping":15}}
Works well with the following vscode-jsonrpc TypeScript:
import * as cp from "child_process";
import * as rpc from "vscode-jsonrpc/node";
// ... some code ommited here
// dotnetPath is path like: C:\Program Files\dotnet\dotnet.exe
// args is an array with a single string element - a path to a framework-dependent .dll
// with a console app from the above snippets
console.log(`Start .NET host...`);
const childProcess = cp.spawn(dotnetPath, args);
const connection = rpc.createMessageConnection(
new rpc.StreamMessageReader(childProcess.stdout),
new rpc.StreamMessageWriter(childProcess.stdin)
);
console.log(`Initialize .NET host comms...`);
let ping = new rpc.RequestType<{ ping: number }, { pong: number}, Error>("ping");
console.log(`.NET host listen...`);
connection.listen();
console.log(`Ping? 2`);
var response = await connection.sendRequest(ping, { ping: 2 });
this.log(`Pong! ${response.pong}`);
Thanks for your code. It is very useful for me. I initialized JsonRpcServer by using IHostedService and it worked.
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OmniSharp.Extensions.JsonRpc;
var builder = Host.CreateApplicationBuilder();
builder.Services.AddHostedService<Initializer>();
builder.Services.AddJsonRpcServer(options =>
options
.WithInput(Console.OpenStandardInput())
.WithOutput(Console.OpenStandardError())
.WithHandler<PingHandler>());
var host = builder.Build();
await host.RunAsync();
class Initializer(JsonRpcServer server) : IHostedService
{
public Task StartAsync(CancellationToken cancellationToken) => server.Initialize(cancellationToken);
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
[Method("ping", Direction.ClientToServer)]
class PingHandler : IJsonRpcRequestHandler<PingHandler.PingRequest, PingHandler.PongResponse>
{
public Task<PongResponse> Handle(PingRequest request, CancellationToken cancellationToken)
{
return Task.FromResult(new PongResponse
{
pong = request.ping + 1
});
}
public class PongResponse
{
public int pong;
}
public class PingRequest : IRequest<PongResponse>
{
public int ping;
}
}