JasperFx / lamar

Fast Inversion of Control Tool and Successor to StructureMap
https://jasperfx.github.io/lamar
MIT License
563 stars 118 forks source link

`IServiceProviderIsService` not returning `true` for various registrations #368

Closed andrewlock closed 1 year ago

andrewlock commented 1 year ago

I was just playing using Lamar with minimal APIs and I've found there are various cases where injected services aren't being inferred because Lamar's IServiceProviderIsService implementation isn't return true for various cases:

Sample app demonstrating the issue below. Note that in all cases, add [FromServices] fixes the issue - it's not the registration at issue, it's the call to IServiceProviderIsService that's wrong. This repros on .NET 6 and .NET 7, giving the following error (indicating none of the args were resolved from DI)

InvalidOperationException: Body was inferred but the method does not allow inferred body parameters.
Below is the list of parameters that we found:

Parameter | Source
---------------------------------------------------------------------------------
services  | Body (Inferred)
concrete  | UNKNOWN
generic   | UNKNOWN

I haven't done an extensive search for all the cases that are/aren't found, but these seem to be the main culprits

Thanks!

using Lamar;
using Lamar.Microsoft.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);
builder.Host.UseLamar(services =>
{
    services.Scan(s =>
    {
        s.AssemblyContainingType(typeof(Program));
        s.WithDefaultConventions();
        s.AddAllTypesOf<IService>();
    });
});

var app = builder.Build();

app.MapGet("/", (IEnumerable<IService> services,
    ConcreteClass concrete,
    IGenericService<ConcreteClass> generic) => "Hello World!");

app.Run();

public interface IService { }
public class ServiceA : IService { }
public class ServiceB : IService { }

public class ConcreteClass {}

public interface IGenericService<T> {}
public class GenericService<T> {}
jeremydmiller commented 1 year ago

Ugh, @andrewlock I didn't realize that was part of their "spec" for how that was supposed to work. Okay. This is one of those times when I curse the conforming container behavior that's rammed down our throats

andrewlock commented 1 year ago

Ugh, @andrewlock I didn't realize that was part of their "spec" for how that was supposed to work. Okay.

To be totally fair, I'm not entirely sure that it definitely is, but best I understand the expectations of IServiceProviderIsService it's "if you can resolve the type from the container, it should return true".

This is one of those times when I curse the conforming container behavior that's rammed down our throats

😬 yeah, I totally get that. The fact there's no real spec for it doesn't help either 🙄

dadhi commented 1 year ago

I was thinking that MS.DI Spec tests should catch all cases :/ Now upping to .Net 7 means more work :(

andrewlock commented 1 year ago

I was thinking that MS.DI Spec tests should catch all cases :/ Now upping to .Net 7 means more work :(

Just to be clear, this is "broken" in .NET 6 too, so not technically tied to the .NET 7 upgrade..

jeremydmiller commented 1 year ago

Think this will be in a new Lamar 10.0 soon.