OmniSharp / OmniSharp/csharp-language-server-protocol

Problem with dependency injecting records

Open
#647 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C#
Stars
638
Forks
109
Avg merge
1m
Merged PRs (30d)
2

Description

I can't use records to do dependency injection into handlers. A recurssive dependency exception is thrown.
I have reduced it down this basic code:

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Server;

namespace MyLSP
{
    public static class Program
    {
        public static void Main()
        {
            MainAsync().Wait();
        }

        private static async Task MainAsync()
        {
            var server = await LanguageServer
                .From(options =>
                    options
                        .WithInput(Console.OpenStandardInput())
                        .WithOutput(Console.OpenStandardOutput())
                        .WithServices(s => s.AddSingleton<SomethingUseful>())
                        .WithHandler<TextDocumentLinkHandler>())
                    .ConfigureAwait(false);

            await server.WaitForExit
                .ConfigureAwait(false);
        }
    }

    public record SomethingUseful
    {

    }

    public record TextDocumentLinkHandler : IDocumentLinkHandler
    {
        public TextDocumentLinkHandler(SomethingUseful stuff)
        {
        }

        public DocumentLinkRegistrationOptions GetRegistrationOptions(DocumentLinkCapability capability, ClientCapabilities clientCapabilities)
        {
            throw new NotImplementedException();
        }

        public Task<DocumentLinkContainer> Handle(DocumentLinkParams request, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }
    }
}

Following exception is thrown in main function:

ContainerException: code: Error.RecursiveDependencyDetected;
message: Recursive dependency is detected when resolving 
MyLSP.SomethingUseful {DryIoc.IfUnresolved.ReturnDefault} as parameter "original" (IsSingletonOrDependencyOfSingleton) <--recursive
  in Singleton MyLSP.SomethingUseful {DryIoc.IfUnresolved.ReturnDefault} as parameter "stuff" FactoryId=39 (IsSingletonOrDependencyOfSingleton) <--recursive
  in resolution root MyLSP.TextDocumentLinkHandler {DryIoc.IfUnresolved.ReturnDefault} FactoryId=153
  from container without scope
 with Rules with {TrackingDisposableTransients, ResolveIEnumerableAsLazyEnumerable, UseDynamicRegistrationsAsFallbackOnly, SelectLastRegisteredFactory} and without {ThrowOnRegisteringDisposableTransient, VariantGenericTypesInResolvedCollection}
 with DefaultReuse=Scoped {Lifespan=100}
 with FactorySelector=SelectLastRegisteredFactory
 with Made={FactoryMethod=ConstructorWithResolvableArgumentsIncludingNonPublic}.

Change SomethingUseful from record to class and problem is gone.
I tried something similar with generic host model but couldn't get this fault. So.... maybe someting in LSP ?
Same issue from LSP version 0.19.0 to 0.19.5. Didn't try older ones, they have compatibility breaks.
Same issue on .NET 5.0 and .NET 6.0 preview 7.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal Program.MainAsync reproduction, especially the LanguageServer.From configuration using WithServices and WithHandler. Compare resolving TextDocumentLinkHandler with SomethingUseful declared as a record versus a class across the reported LSP versions and .NET versions; done means the record-based dependency no longer produces the recursive dependency exception.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.