ASP.NET Core中PUT控制器无法从请求体绑定Guid?
这个问题我之前也碰到过,其实是ASP.NET Core模型绑定和JSON序列化的小细节在搞鬼。咱们来拆解一下原因和解决办法:
问题根源
当你把Guid这种简单类型用[FromBody]标记时,ASP.NET Core的JSON序列化器(默认是System.Text.Json)期望请求体是一个符合JSON规范的原始字符串值,但大多数情况下,我们可能会下意识地发送一个JSON对象(比如{"testId": "xxx"}),或者发送不带双引号的纯Guid字符串,这都会导致模型绑定失败,参数变成null。
而路径参数guidThatWorks能正常工作,是因为URL中的字符串会被模型绑定直接解析为Guid类型,不需要遵循JSON格式规则。
解决方案
方案1:发送正确的纯JSON字符串请求体
如果你坚持直接用Guid作为[FromBody]参数,那么请求体必须是带双引号的Guid字符串:
"3fa85f64-5717-4562-b3fc-2c963f66afa6"
注意:一定要带双引号,这才是合法的JSON字符串值。在Postman或Swagger中,选择raw格式并指定为JSON,然后输入上述内容即可。
方案2:使用DTO包装类(推荐)
这种方式更符合前后端交互的常规习惯,前端通常更倾向于发送JSON对象。我们可以创建一个简单的数据传输对象(DTO):
public class UpdateGuidRequest { public Guid TestId { get; set; } }
然后修改控制器方法,用这个DTO来接收请求体:
[HttpPut("Test/{guidThatWorks:guid}")] [Consumes("application/json")] [Produces("application/json")] public async Task<IActionResult> Test(Guid guidThatWorks, [FromBody] UpdateGuidRequest request) { // 这里就可以正常使用request.TestId了 return Ok(); }
此时发送的请求体就是标准的JSON对象:
{"TestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"}
这种方式不仅更直观,也方便后续扩展参数(比如以后要加其他字段,直接在DTO里加就行)。
方案3:配置JSON序列化器允许顶级值(不推荐)
如果你不想用DTO,也可以配置System.Text.Json允许解析顶级的简单类型。在Program.cs中添加如下配置:
builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; // 允许解析顶级的简单类型(比如字符串、数字、Guid等) options.JsonSerializerOptions.AllowTrailingCommas = true; });
不过这种方式还是不如方案2灵活,而且前端容易因为格式问题出错,所以更推荐用DTO的方式。
内容的提问来源于stack exchange,提问作者Yuk

