API 控制器操作尝试从 DI 推断参数

当在容器中注册类型时,用于推断 API 控制器操作参数绑定源的机制现在会将参数标记为从依赖关系注入 (DI) 容器绑定。 在极少数情况下,这可能会中断 DI 中具有 API 控制器操作方法中也接受的类型的应用。

引入的版本

ASP.NET Core 7.0

旧行为

如果要在 DI 容器中绑定注册的类型,则必须使用实现 IFromServiceMetadata 的属性对其进行显式修饰,如 FromServicesAttribute

Services.AddScoped<SomeCustomType>();

[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
    public ActionResult Get([FromServices]SomeCustomType service) => Ok();
}

如果未指定该属性,则会从客户端发送的请求正文解析该参数:

Services.AddScoped<SomeCustomType>();

[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
    // Bind from the request body
    [HttpPost]
    public ActionResult Post(SomeCustomType service) => Ok();
}

新行为

DI 中的类型将在应用启动时使用 IServiceProviderIsService 来检查,以确定 API 控制器操作中的参数是来自 DI 还是来自源。

在以下示例中,假定你使用的是默认的 DI 容器,SomeCustomType 来自 DI 容器:

Services.AddScoped<SomeCustomType>();

[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
    // Bind from DI
    [HttpPost]
    public ActionResult Post(SomeCustomType service) => Ok();
}

用于推断 API 控制器操作参数绑定源的机制遵循以下规则:

  1. 以前指定的 BindingInfo.BindingSource 永远不会被覆盖。
  2. 分配 BindingSource.Services 给在 DI 容器中注册的复杂类型参数。
  3. 分配 BindingSource.Body 给在 DI 容器中注册的复杂类型参数。
  4. 具有以下名称的参数将被分配 BindingSource.Path,即在“任何”路由模板中都显示为路由值。
  5. 所有其他参数都被分配 BindingSource.Query

中断性变更的类型

此更改会影响源兼容性。

更改原因

已在最小 API 中实现此相同行为。

中断应用的可能性较低,因为同时既是 DI 中的类型,又是 API 控制器操作中参数的情况并不常见。

如果你被此更改中断,可以通过将 DisableImplicitFromServicesParameters 设置为 true 来禁用此功能:

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

如果被更改中断,但你想要从 DI 绑定特定的 API 控制器操作参数,则可以禁用该功能(如上所示),并使用实现 IFromServiceMetadata 的属性,例如 FromServicesAttribute

Services.AddScoped<SomeCustomType>();

[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
    // Bind from DI
    [HttpPost]
    public ActionResult Post([FromServices]SomeCustomType service) => Ok();
}

受影响的 API

API 控制器操作