You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Web API2调用时JObject转mproject实体抛出无效类型转换异常

问题描述

调用Web API 2接口时遇到如下错误:

Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'NG_API_DNET_FRX.Models.mproject'.

站点前端使用Angular框架,网页端发送的原始JSON内容如下:

{
    "id": "3137",
    "clientId": "2",
    "Name": "MFAQ project1",
    "EstimatedStartDate": "07/01/2022",
    "EstimatedEndDate": "07/08/2022",
    "ActualStartDate": "07/15/2022",
    "ActualEndDate": "07/22/2022",
    "EstimatedBudget": "44444.0000",
    "ActualBudget": "55555.0000"
}

调试时通过监视窗口复制的接口实际接收到的参数JSON表示如下:
注意:该对象外层包裹了双层大括号{{...}},JSONLint会对该格式报错,但此前所有接口调用都存在该现象且Web API可正常处理,不确定是否为本次问题的诱因。

{{
  "id": 3137,
  "clientId": 2,
  "Name": "MFAQ project1",
  "EstimatedStartDate": "07/13/2022",
  "EstimatedEndDate": "6/8/2022",
  "ActualStartDate": "6/15/2022",
  "ActualEndDate": "6/22/2022",
  "EstimatedBudget": 44444,
  "ActualBudget": 55555
}}

目标接收结构体的C#定义及接口代码如下:

public class mproject
{
    public int id;
    public int clientId;
    public string Name;
    public string EstimatedStartDate;
    public string EstimatedEndDate;
    public string ActualStartDate;
    public string ActualEndDate;
    public decimal EstimatedBudget;
    public decimal ActualBudget;
    public string sbProperties;
    public string projectType;

    public mprojectRev[] Revisions;
}

[System.Web.Http.HttpPatch]
[Route("{itemId_}")]
public IHttpActionResult PatchItemById([FromUri] int itemId_, [FromBody] mproject webForm_  )
{
    // 直接指定参数类型为mproject时,webForm_为null
    // 如果把参数类型改成dynamic/object,手动强转时就会抛出上述转换错误
    //mproject webForm_;
    //try
    //{
    //    webForm_ = (mproject)webForm_1;
    //}
    //catch (Exception ex)
    //{
    //    return JSONStringResultExtension.JSONString(this, errorAsJSON(ex), HttpStatusCode.InternalServerError);
    //}
}

该异常无内部异常。传入的参数未包含mproject类定义的3个属性,已排除该因素(此前缺失属性的场景均可正常处理)。近期在调试日期字段相关逻辑,怀疑日期格式是问题诱因。

核心问题:为什么该类型转换会抛出异常?
需要了解获取更多异常详情定位根因的方法,以及对应的故障排查技巧。


问题根因

按影响优先级排序:

  1. 核心诱因:mproject类用的是公共字段,不是公共属性
    这是Web API 2里极其常见的坑。Web API 2默认用Newtonsoft.Json做序列化,默认配置下只会反序列化带get/set访问器的公共属性,完全忽略公共字段。你现在类里写的全是public int id;这种字段定义,序列化器找不到可写入的属性入口,没法把请求JSON里的值映射到mproject实例,直接导致模型绑定失败,所以你用mproject类型接参数的时候拿到的是null。
    如果你把参数类型改成object/dynamic,拿到的是原始解析后的JObject对象,这时候直接写(mproject)jObj做强转,走的是CLR原生类型校验:JObject和mproject没有任何继承、类型转换实现关系,必然抛出你看到的类型转换异常。
    你提到之前缺失字段也能正常处理,大概率是之前的模型类写的都是带get/set的属性,或者全局Json配置改过支持字段,之后被重置了。
  2. 双层大括号不是请求格式问题,是VS调试监视窗口的显示bug
    调试器渲染JObject类型对象时会额外套一层大括号显示,实际内存里存的就是正常的单大括号JSON结构,所有接口调用都存在该现象也能佐证这一点,完全不用在这上面花时间排查。
  3. 日期格式、缺失字段都不是问题诱因
    你把日期字段定义成了string类型,只要传的是字符串值就不会绑定失败;缺失字段的话序列化器会直接给对应类型赋默认值(int为0、引用类型为null),不会导致整个模型绑定直接失败。

排查&修复方案
  • 优先改模型定义,把所有公共字段改成自动属性,这是最符合.NET开发规范、也不用改动全局配置的方案:
    public class mproject
    {
        public int id {get;set;}
        public int clientId {get;set;}
        public string Name {get;set;}
        public string EstimatedStartDate {get;set;}
        public string EstimatedEndDate {get;set;}
        public string ActualStartDate {get;set;}
        public string ActualEndDate {get;set;}
        public decimal EstimatedBudget {get;set;}
        public decimal ActualBudget {get;set;}
        public string sbProperties {get;set;}
        public string projectType {get;set;}
        public mprojectRev[] Revisions {get;set;}
    }
    
    改完之后直接用[FromBody] mproject webForm_接收参数即可,绝大多数场景下直接恢复正常。
  • 如果因为历史代码原因不能改字段定义,就去WebApiConfig.cs里修改Json序列化配置,开启公共字段的序列化支持(注意要引用Newtonsoft.Json.Serialization和System.Reflection命名空间):
    config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new DefaultContractResolver()
    {
        DefaultMembersSearchFlags = BindingFlags.Public | BindingFlags.Instance
    };
    
  • 如果确实需要手动接收JObject再做转换,不要直接用C#强转语法,要用Newtonsoft自带的ToObject<T>()方法,这个方法会走序列化映射逻辑,不是做CLR原生类型校验:
    // 错误写法:直接强转
    // webForm_ = (mproject)webForm_1;
    // 正确写法
    webForm_ = ((JObject)webForm_1).ToObject<mproject>();
    
  • 后续排查模型绑定问题不用盲目猜测,直接在Action里访问ModelState属性,里面会把每个字段绑定失败的具体原因列得清清楚楚,比如类型不匹配、格式错误等,比盯着请求JSON排查效率高得多。如果要全局捕获绑定错误,也可以写个模型绑定日志过滤器,统一记录所有绑定错误信息。

内容的提问来源于stack exchange,提问作者greg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 02:54:40