JasperFx / lamar

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

Adding Lamar to .NET 7 Asp.net web application breaks input model binding #373

Closed kblooie closed 1 year ago

kblooie commented 1 year ago

I ran into an issue upgrading a WebApi project from .NET 6 to .NET 7 where all of the input parameters for HttpPost operations are null. I was able to track it down to the use of Lamar for DI. I was able to reproduce this issue in a brand new .NET 7 WebApi project (attached).

Lamar.Microsoft.DependencyInjection Version="10.0.0"

Steps To Repro

  1. Run the application
  2. Put a breakpoint in WeatherForecastController.Post
  3. POST to http://localhost:5070/WeatherForecast with json: { "Name":"TTT" }

Expected: input.Name should be "TTT"

Actual: input.Name is null.

NOTE: You can get it to work as expected by removing UseLamar from Program.cs:

Comment out:

//builder.Host.UseLamar(registry =>
//{
//    registry.AddControllers();
//});

uncomment

builder.Services.AddControllers();

Re-running will now populate input.Name to "TTT"

I'm not sure if this issue is specific to Lamar or all 3rd party DI libraries. Any suggestions?

Net7.zip

kblooie commented 1 year ago

I believe this issue is being caused by this breaking change in .NET 7:

https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/7.0/api-controller-action-parameters-di

My guess is that Lamar "supports" building the input model, so asp.net is defaulting to the empty input object that's built by Lamar.

I was able to work around this issue with the following configuration code:

builder.Services.Configure<ApiBehaviorOptions>(options =>
{
    options.DisableImplicitFromServicesParameters = true;
});

Is this issue specific to Lamar?

jeremydmiller commented 1 year ago

Lamar/StructureMap has always had the ability to "auto resolve" concrete types that could be resolved by Lamar/StructureMap. This is a case of Lamar apparently not being exactly in line with our AspNetCore overlord's vision of how this should all work.

It's going to be clumsy, but I can make the adjustment to Lamar's implementation of IServiceProviderIsService to get around this.

It's Lamar specific I imagine, but I'm still gonna bitch about the AspNetCore team here:-)