Problem with dependency injecting records
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.
Found the cuplrit with JustDecompile. Compiler create constructor of class itself with "original" argument:
protected SomethingUseful(SomethingUseful original)
{
}
Maybe Microsoft DI extensions or DryLoc need a fix?