C# WebAPI接收嵌套JSON数据时出现400验证错误排查
问题排查与解决
核心原因
- 请求JSON结构与WebAPI参数接收逻辑不匹配:你的请求是外层包含
RawJson嵌套对象的JSON,但接口方法SubmitNewActivity接收的是string类型参数,ASP.NET自动模型绑定会尝试将整个JSON对象转换为字符串,直接触发类型转换错误,导致400响应。 - 职责混乱:
ActivitySubmissionService既是依赖注入的业务服务类(注入了GPSAPIContext),又被当作JSON反序列化的DTO使用,同时你还试图将单个对象的JSON反序列化为List<ActivitySubmissionService>,完全不符合请求数据结构。 - 反序列化逻辑错误:请求中的
RawJson是单个对象,而非数组,但你强行反序列化为列表,后续取FirstOrDefault的逻辑从根源上不成立。
解决步骤
1. 拆分职责,创建独立DTO类
创建专门用于接收请求数据的DTO,避免用业务服务类承担DTO的职责:
// 对应RawJson内部的结构 public class ActivityDataDto { [JsonProperty("ParkSys_ID")] public int ParkSys_ID { get; set; } [JsonProperty("Route_ID")] public int Route_ID { get; set; } [JsonProperty("TrailName")] public string TrailName { get; set; } [JsonProperty("GPXData")] public List<GpxPointDto> GPXData { get; set; } } // 对应GPXData数组中的单个点 public class GpxPointDto { public DateTime Timestamp { get; set; } public double Latitude { get; set; } public double Longitude { get; set; } public double Altitude { get; set; } public double Accuracy { get; set; } public double VerticalAccuracy { get; set; } public double? Speed { get; set; } public double? Course { get; set; } public bool IsFromMockProvider { get; set; } public int AltitudeReferenceSystem { get; set; } } // 对应整个请求的外层结构 public class ActivitySubmissionRequestDto { [JsonProperty("RawJson")] public ActivityDataDto RawJson { get; set; } }
2. 修改WebAPI控制器接口
调整接口参数,直接接收匹配请求结构的DTO(假设你有一个控制器调用该服务):
[ApiController] [Route("api/activities")] public class ActivityController : ControllerBase { private readonly IActivitySubmission _activitySubmissionService; public ActivityController(IActivitySubmission activitySubmissionService) { _activitySubmissionService = activitySubmissionService; } [HttpPost] public async Task<IActionResult> SubmitActivity([FromBody] ActivitySubmissionRequestDto request) { if (!ModelState.IsValid) { return BadRequest(ModelState); } var result = await _activitySubmissionService.SubmitNewActivity(request.RawJson); return Ok(result); } }
3. 修正业务服务类的逻辑
重构ActivitySubmissionService,去掉错误的反序列化逻辑,直接接收DTO:
public class ActivitySubmissionService : IActivitySubmission { private readonly GPSAPIContext _gpsapiContext; public ActivitySubmissionService(GPSAPIContext gpsapiContext) { _gpsapiContext = gpsapiContext; } public async Task<object> SubmitNewActivity(ActivityDataDto activityData) { // 这里可以添加你的业务逻辑,比如保存到数据库 // 示例:返回GPXData,你可以根据需求修改 return activityData.GPXData; } }
4. 验证请求
确保你的请求JSON结构不变(和你之前提交的一致),此时ASP.NET会自动完成模型绑定,不会再出现400错误。
额外说明
- 避免将业务服务类与DTO混用,这会导致代码耦合、职责不清,后续维护困难。
- 尽量使用强类型DTO而非
object类型,这样可以获得编译时类型检查,减少运行时错误。 - 如果需要接收原始JSON字符串,可以在控制器中用
[FromBody] string rawJson,但此时前端需要将整个JSON序列化为字符串(即请求体是带引号的字符串),这通常不是最优方案。
内容的提问来源于stack exchange,提问作者tlf
相关产品推荐
相关产品推荐

