Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spectre.Console doesn't respect Microsoft.Extensions.DependencyInjection singletons #1710

Open
macdonaldr93 opened this issue Dec 6, 2024 · 3 comments
Labels
bug Something isn't working needs triage

Comments

@macdonaldr93
Copy link

Information

  • OS: MacOS
  • Version: 0.49.1
  • Terminal: iTerms

Describe the bug

When dependency injecting a service registered as a singleton into my command, the instance of the service isn't the same as the singleton. Spectre seems to instantiate a new instance of injected parameters outside of the ServiceCollection.

To Reproduce

I've created this example repo: https://github.com/macdonaldr93/spectre-di-debug

It's a minimalist implementation, so you should be able to read all of the code. The main two spots are:

  1. HashCode output from the HostedService: https://github.com/macdonaldr93/spectre-di-debug/blob/main/SpectreDI/Program.cs#L23
  2. HashCode output from the Command: https://github.com/macdonaldr93/spectre-di-debug/blob/main/SpectreDI/Commands/ExampleCommand.cs#L22

You can run the console app with:

dotnet run --project SpectreDI example

and this will output:

HostedService->IExampleService hash code: 1816341
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/ryan.macdonald/src/github.com/spectre-di
ExampleCommand->IExampleService hash code: 58130472

Expected behavior

I expected the hash code to be the same because the instance of ExampleService should be the same.

Additional context

The real use case is that we have a background authentication hosted service. We want this available as a singleton when the command runs because it knows about the auth token.


Please upvote 👍 this issue if you are interested in it.

@macdonaldr93 macdonaldr93 added bug Something isn't working needs triage labels Dec 6, 2024
@github-project-automation github-project-automation bot moved this to Todo 🕑 in Spectre Console Dec 6, 2024
@patriksvensson
Copy link
Contributor

I'm sorry, but this is not a minimal reproducable example, this is a whole framework. You will need to reduce the scope a bit, perhaps create an example using just the TypeRegistrar and TypeResolver and show us what is wrong.

@phil-scott-78
Copy link
Contributor

phil-scott-78 commented Dec 6, 2024

I actually had a few seconds to look at this and I've been trying to wrap my head around DI so I thought I'd dig in some more. Oo me this seems like just a misunderstanding of how MEDI is gonna work along with the TypeRegistrar you've written. That Registrar builds its own service provider, as does hosted service. So the code relating to DI is no different than this which has a similiar output.

var services = new ServiceCollection();
services.AddSingleton<IExampleService, ExampleService>();

var provider1 = services.BuildServiceProvider();
var exampleService1 = provider1.GetRequiredService<IExampleService>();
Console.WriteLine(exampleService1.GetHashCode());

var provider2 = services.BuildServiceProvider();
var exampleService2 = provider2.GetRequiredService<IExampleService>();
Console.WriteLine(exampleService2.GetHashCode());

That being said, this probably falls under #1657 as first class Microsoft.Extensions.DependencyInjection would probably allow Spectre.Console to play nicely with whatever HostedService is doing to grab that singular service provider

@macdonaldr93
Copy link
Author

@phil-scott-78 that's super helpful context! You're right, I assumed that Build would only be called once here https://github.com/macdonaldr93/spectre-di-debug/blob/main/SpectreDI/Program.cs#L35.

It looks like #1657 already captures our use case. I'm happy to close this and keep an eye on that issue. Our example just gives you another use case of how folks are attempting to make this work.

In the meantime, do you know of any workarounds? We'll internally work on it, but if there's someone who's already solved this, it would help a lot. From what I've seen online, most folks take a similar approach to us. @patriksvensson just realizing now that your repo (https://github.com/patriksvensson/spectre.console-di-sample/blob/main/Infrastructure/TypeRegistrar.cs) was the one I had originally referenced. At the time I didn't realize you were an author on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs triage
Projects
Status: Todo 🕑
Development

No branches or pull requests

3 participants