常规路由不反序列化 json 正文请求(ASP.NET 核心 API)

Conventional Routing doesn't deserialize json body requests (ASP.NET Core API)

问题

在控制器和操作上使用 ApiControllerAttribute 和 RouteAttribute,一切正常。

当我更改代码以使用传统路由时,请求中的标识 属性 始终设置为空。

带有 ApiControllerAttribute 的代码(请求中加载的标识)

[ApiController]
[Route("api/[controller]")]
Public Class Main : ControllerBase
{
    [HttpPost(nameof(GetExternalRemoteExternal))]
    public async Task<GetByIdentityResponse<RemoteExternal>> GetExternalRemoteExternal(GetByIdentityRequest<RemoteExternalIdentity> request)
    {
        return await GetExternal<RemoteExternal, RemoteExternalIdentity>(request);
    }
}

startup.cs

app.UseEndpoints(endpoints => endpoints.MapControllers());

具有常规路由的代码(请求具有空标识)

Public Class Main : ControllerBase
{
    [HttpPost]
    public async Task<GetByIdentityResponse<RemoteExternal>> GetExternalRemoteExternal(GetByIdentityRequest<RemoteExternalIdentity> request)
    {
        return await GetExternal<RemoteExternal, RemoteExternalIdentity>(request);
    }
}

startup.cs

app.UseEndpoints(endpoints => endpoints.MapControllerRoute(
                                               name: "default",
                                               pattern: "api/{controller}/{action}")) //Not work even with "api/{controller}/{action}/{?id}"

常用码

public class GetByIdentityRequest<TIDentity> : ServiceRequest
    where TIDentity : BaseIdentity
{
    public TIDentity Identity { get; set; }
}

public class RemoteExternalIdentity : BaseIdentity
{
    public int IdX { get; set; }
}

JSON

{"$id":"1","Identity":{"$id":"2","IdX":10000}}

API LINK

.../api/Main/GetExternalRemoteExternal

[ApiController] attribute adds a few conventions to controllers that enables some opinionated behaviors, including binding source parameter inference 使复杂的参数默认从 body 绑定。

由于您不能将 [ApiController] 属性与基于约定的路由一起使用(因为约定之一就是为了防止这种情况发生),您可以使用带有参数的显式 [FromBody] 来强制它们从 JSON 正文解析:

public class Main : ControllerBase
{
    [HttpPost]
    public async Task<GetByIdentityResponse<RemoteExternal>> GetExternalRemoteExternal(
        [FromBody] GetByIdentityRequest<RemoteExternalIdentity> request)
    {
        return await GetExternal<RemoteExternal, RemoteExternalIdentity>(request);
    }
}