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 控制器操作参数绑定源的机制遵循以下规则:
- 以前指定的 BindingInfo.BindingSource 永远不会被覆盖。
- 分配 BindingSource.Services 给在 DI 容器中注册的复杂类型参数。
- 分配 BindingSource.Body 给在 DI 容器中注册的复杂类型参数。
- 具有以下名称的参数将被分配 BindingSource.Path,即在“任何”路由模板中都显示为路由值。
- 所有其他参数都被分配 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 控制器操作