OmniSharp / OmniSharp/csharp-language-server-protocol
Problem with dependency injecting records
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
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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