ASP.NET Core嵌套模型[FromForm]无法绑定问题咨询
问题描述
有以下两个模型类:
public class TokenRequestModel { [FromHeader(Name = HeaderName.RequestId)] public Guid? RequestId { get; set; } [FromHeader(Name = HeaderName.Authorization), Required, SwaggerParameter(DocConstants.Authorization, Required = true)] public required string Authorization { get; set; } [FromRoute(Name = RouteConstants.AuthorizationServerId)] public required string AuthorizationServerId { get; set; } } public class TokenRequest { [FromForm(Name = "code")] public string? Code { get; set; } [FromForm(Name = "refresh_token")] public string? RefreshToken { get; set; } [FromForm(Name = "grant_type")] public required string GrantType { get; set; } [FromForm(Name = "redirect_uri")] public string? RedirectUri { get; set; } }
当将两个模型分别作为Action参数传入时,绑定可正常完成:
public async Task<ActionResult<TokenResponse>> Exchange( TokenRequestModel tokenRequestModel, [FromForm] TokenRequest tokenRequest) { }
但将TokenRequest作为属性嵌套到TokenRequestModel中后,绑定失败:
public class TokenRequestModel { [FromHeader(Name = HeaderName.RequestId)] public Guid? RequestId { get; set; } [FromHeader(Name = HeaderName.Authorization)] public required string Authorization { get; set; } [FromRoute(Name = RouteConstants.AuthorizationServerId)] public required string AuthorizationServerId { get; set; } [FromForm] public TokenRequest? TokenRequest { get; set; } }
对应的Action方法:
public async Task<ActionResult<TokenResponse>> Exchange( TokenRequestModel tokenRequestModel) { }
预期通过URL编码表单数据,使用[FromForm]将数据绑定到TokenRequest属性,但该属性始终为null。此前使用[FromBody]处理JSON数据时绑定正常,询问该场景是否不被支持还是操作有误。
问题原因与解决方案
这是ASP.NET Core表单绑定的命名规则导致的问题,并非场景不被支持。
原因分析
当使用嵌套对象进行表单绑定时,ASP.NET Core默认会期望表单字段名采用父属性名+子属性名的格式(比如TokenRequest.Code),但当前提交的表单字段是code、grant_type这类平级名称,和绑定规则不匹配,所以TokenRequest属性无法被正确赋值,始终为null。
而使用[FromBody]处理JSON时,JSON的层级结构天然匹配嵌套对象,所以绑定正常;分开作为参数时,[FromForm]直接作用在TokenRequest上,会直接匹配平级的表单字段,因此也能正常绑定。
解决方案
有两种可行的处理方式:
修改表单提交的字段名
提交表单时,将字段名改为嵌套格式,比如:TokenRequest.CodeTokenRequest.GrantTypeTokenRequest.RefreshTokenTokenRequest.RedirectUri
手动映射属性
如果无法修改提交的字段格式,可以在TokenRequestModel中添加与表单字段对应的直接属性,然后手动映射到TokenRequest对象中,示例:public class TokenRequestModel { [FromHeader(Name = HeaderName.RequestId)] public Guid? RequestId { get; set; } [FromHeader(Name = HeaderName.Authorization)] public required string Authorization { get; set; } [FromRoute(Name = RouteConstants.AuthorizationServerId)] public required string AuthorizationServerId { get; set; } [FromForm(Name = "code")] public string? Code { get; set; } [FromForm(Name = "refresh_token")] public string? RefreshToken { get; set; } [FromForm(Name = "grant_type")] public required string GrantType { get; set; } [FromForm(Name = "redirect_uri")] public string? RedirectUri { get; set; } public TokenRequest? TokenRequest => new TokenRequest { Code = Code, RefreshToken = RefreshToken, GrantType = GrantType, RedirectUri = RedirectUri }; }
内容的提问来源于stack exchange,提问作者Mark Good
相关产品推荐
相关产品推荐

