Search code examples
c#visual-studio-2022visual-studio-extensionsvsixlanguage-server-protocol

Microsoft.VisualStudio.Extensibility.LanguageServer.LanguageServerProvider: Exception "No method by the name 'initialize' is found."


I call a language server from an extension for VS2022. This was created using Omnisharp.Extensions.LanguageServer 0.19.9. For the call I use the (currently) experimental class LanguageServerProvider from Microsoft.VisualStudio.Extensibility 17.10.2084.

When starting my languageserver from my extension I get an exception from "VS/IDE/TaskStatusCenter/RunningRegisteredTaskFailed":

            StreamJsonRpc.RemoteMethodNotFoundException: No method by the name 'initialize' is found.
            at StreamJsonRpc.JsonRpc.<InvokeCoreAsync>d__154`1.MoveNext()
            --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at Microsoft.VisualStudio.LanguageServer.Client.JsonRpcExtensionMethods.<SendMethodRequestWithTelemetryAsync>d__0`2.MoveNext()
            --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at Microsoft.VisualStudio.LanguageServer.Client.RemoteLanguageClientInstance.<SendInitializeRequestAsync>d__115.MoveNext()
            --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at Microsoft.VisualStudio.LanguageServer.Client.RemoteLanguageClientInstance.<InitializeAsync>d__110.MoveNext()
            --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at Microsoft.VisualStudio.Threading.TplExtensions.<WithTimeout>d__5.MoveNext()
            --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at Microsoft.VisualStudio.LanguageServer.Client.RemoteLanguageClientInstance.<TrackTaskAsync>d__113.MoveNext()
            --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at Microsoft.VisualStudio.LanguageServer.Client.RemoteLanguageClientInstance.<ActivateLanguageClientAsync>d__122.MoveNext()

What does this message mean? For which class is the "initialize" method missing?

I use

  • omnisharp.extensions.languageserver 0.19.9
  • Visual Studio Extensibility Sdk and Visual Studio Extensibility Framework 17.10.2084
  • Microsoft Visual Studio Community 2022 (64-bit) 17.10.5

Here is my language-server-provider:

using System.Diagnostics;
using System.IO.Pipelines;
using JetBrains.Annotations;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.LanguageServer;
using Microsoft.VisualStudio.RpcContracts.LanguageServerProvider;
using Nerdbank.Streams;
using ReniLSP;

namespace Reni.LSPVSIX;

#pragma warning disable VSEXTPREVIEW_LSP
[VisualStudioContribution]
[UsedImplicitly]
public sealed class ReniLanguageServerProvider : LanguageServerProvider
{
    [UsedImplicitly]
    Task? ServerPipeTask;

    public ReniLanguageServerProvider
        (ExtensionCore container, VisualStudioExtensibility extensibilityObject, TraceSource traceSource)
        : base(container, extensibilityObject) { }

    public override LanguageServerProviderConfiguration LanguageServerProviderConfiguration =>
        new("Reni Language Server",
            new[]
            {
                DocumentFilter.FromDocumentType(Constants.LanguageName),
            });

    // Activate the language server and return a duplex pipe that communicates with the server. 
    public override Task<IDuplexPipe?> CreateServerConnectionAsync(CancellationToken token)
    {
        var (pipeToServer, pipeToVS) = FullDuplexStream.CreatePair();

        ServerPipeTask = Task.Run(
            () => MainContainer.RunServer(pipeToVS.UsePipeReader(), pipeToServer.UsePipeWriter())
            , token
        );

        return Task.FromResult<IDuplexPipe?>(new DuplexPipe(pipeToServer.UsePipeReader(), pipeToVS.UsePipeWriter()));
    }

    protected override void Dispose(bool isDisposing)
    {
        if(isDisposing)
            ServerPipeTask?.Dispose();
        base.Dispose(isDisposing);
    }

    public override Task OnServerInitializationResultAsync
    (
        ServerInitializationResult startState, LanguageServerInitializationFailureInfo? initializationFailureInfo
        , CancellationToken cancellationToken
    ) =>
        // Method called when server activation was completed successfully or failed, denoted by "startState".
        Task.CompletedTask;
}

Solution

  • The method CreateServerConnectionAsync was wrong. This is working:

    public override Task<IDuplexPipe?> CreateServerConnectionAsync(CancellationToken token)
    {
        var (pipeToLSP, pipeToVS) = FullDuplexStream.CreatePair();
        ServerPipeTask = Task.Run(() => MainContainer.RunServer(pipeToLSP.UsePipeReader(), pipeToLSP.UsePipeWriter()), token);
        var duplexPipe = new DuplexPipe(pipeToVS.UsePipeReader(), pipeToVS.UsePipeWriter());
    
        return Task.FromResult<IDuplexPipe?>(duplexPipe);
    }