aspnetcore/breaking-changes/7/api-controller-action-parameters-di.md
The mechanism to infer binding sources of API controller action parameters now marks parameters to be bound from the Dependency Injection (DI) container when the type is registered in the container. In rare cases, this can break apps that have a type in DI that is also accepted in API controller action methods.
ASP.NET Core 7.0
If you wanted to bind a type registered in the DI container, it must be explicitly decorated using an attribute that implements xref:Microsoft.AspNetCore.Http.Metadata.IFromServiceMetadata, such as xref:Microsoft.AspNetCore.Mvc.FromServicesAttribute:
Services.AddScoped<SomeCustomType>();
[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
public ActionResult Get([FromServices]SomeCustomType service) => Ok();
}
If the attribute wasn't specified, the parameter was resolved from the request body sent by the client:
Services.AddScoped<SomeCustomType>();
[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
// Bind from the request body
[HttpPost]
public ActionResult Post(SomeCustomType service) => Ok();
}
Types in DI are checked at app startup using xref:Microsoft.Extensions.DependencyInjection.IServiceProviderIsService to determine if an argument in an API controller action comes from DI or from other sources.
In the following example, which assumes you're using the default DI container, SomeCustomType comes from the DI container:
Services.AddScoped<SomeCustomType>();
[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
// Bind from DI
[HttpPost]
public ActionResult Post(SomeCustomType service) => Ok();
}
The mechanism to infer binding sources of API controller action parameters follows the following rules:
This change affects source compatibility.
This same behavior is already implemented in minimal APIs.
The likelihood of breaking apps is low as it isn't common to have a type in DI and as an argument in your API controller action at the same time.
If you're broken by this change, you can disable the feature by setting DisableImplicitFromServicesParameters to true:
Services.Configure<ApiBehaviorOptions>(options =>
{
options.DisableImplicitFromServicesParameters = true;
});
If you're broken by the change, but you want to bind from DI for specific API controller action parameters, you can disable the feature as shown above and use an attribute that implements xref:Microsoft.AspNetCore.Http.Metadata.IFromServiceMetadata, such as xref:Microsoft.AspNetCore.Mvc.FromServicesAttribute:
Services.AddScoped<SomeCustomType>();
[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
// Bind from DI
[HttpPost]
public ActionResult Post([FromServices]SomeCustomType service) => Ok();
}
API controller actions