当前位置: 首页 > news >正文

【C#】.net core 8.0 MVC在一次偶然间发现控制器方法整个Model实体类对象值为null,猛然发现原来是

🌹欢迎来到《小5讲堂》🌹
🌹这是《C#》系列文章,每篇文章将以博主理解的角度展开讲解。🌹
🌹温馨提示:博主能力有限,理解水平有限,若有不对之处望指正!🌹

在这里插入图片描述

目录

  • 前言
  • 问题分析
    • 方案一:前端处理(推荐且最清晰)
    • 方案二:后端模型使用可空整型 (`int?`)
    • 方案三:自定义模型绑定器 (Model Binder)
    • 方案四:使用字符串类型接收再转换
    • 方案五:使用 JSON 反序列化设置
    • 推荐方案
  • 推荐文章

前言

尽管博主工作了十来年,但是有些知识点还是容易忽略。
比如这次遇到的后端接收参数问题,居然因为一个传递数据类型导致整个实体参数值为null.

在这里插入图片描述

后端为空整型参数,前端传递过来的是空字符串,导致无法解析,所以整个实体类接收对象为null
解决方案是,要么不传参数ID,要不ID这个参数赋值为0.

问题分析

好的,这个问题在 C# MVC 中非常典型。当 JSON 反序列化器遇到一个期望是 int 的字段却收到了空字符串 "" 时,它无法完成转换,从而导致整个模型绑定失败,模型对象为 null

你提出的两种思路(不传或传0)是正确的。以下是针对 C# MVC 的详细解决方案:


方案一:前端处理(推荐且最清晰)

在前端(JavaScript)发送数据之前,确保整型字段不是空字符串。

使用 JavaScript 处理:

// 假设这是你要发送的数据对象
let formData = {id: "", // 前端可能由于输入框清空而变成空字符串name: "Test Name",age: ""
};// 在发送前清理数据
function cleanData(data) {const cleaned = { ...data };for (const key in cleaned) {// 将空字符串转换为 null 或直接删除if (cleaned[key] === "") {// 方式1: 转换为 null (需要后端配合使用 int?)cleaned[key] = null;// 方式2: 转换为 0// cleaned[key] = 0;// 方式3: 直接删除该属性(推荐,让后端用默认值)// delete cleaned[key];}}return cleaned;
}// 使用清理后的数据发送请求
fetch('/YourController/YourAction', {method: 'POST',headers: {'Content-Type': 'application/json',},body: JSON.stringify(cleanData(formData))
});

使用 jQuery Ajax:

var dataToSend = {id: $("#idField").val(),name: $("#nameField").val()
};// 清理空字符串
if (dataToSend.id === "") {delete dataToSend.id; // 直接删除属性
}$.ajax({url: '/YourController/YourAction',type: 'POST',contentType: 'application/json',data: JSON.stringify(dataToSend),success: function(response) {// 处理响应}
});

方案二:后端模型使用可空整型 (int?)

将模型中的整型字段改为可空类型,这样就能接收 null 值。

public class YourModel
{public int? Id { get; set; } // 改为可空整型public string Name { get; set; }public int Age { get; set; }
}

然后在控制器中处理:

[HttpPost]
public ActionResult YourAction(YourModel model)
{if (model == null){return BadRequest("Invalid model data");}// 处理 Id 可能为 null 的情况int effectiveId = model.Id ?? 0; // 如果为null则用0代替// 或者根据业务逻辑判断if (model.Id.HasValue){// 更新操作}else{// 新增操作}// ... 其他逻辑
}

方案三:自定义模型绑定器 (Model Binder)

创建自定义模型绑定器来处理空字符串到整型的转换。

1. 创建自定义模型绑定器:

using System;
using System.Web.Mvc;public class EmptyStringToZeroModelBinder : DefaultModelBinder
{public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext){var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);if (valueProviderResult != null){// 如果是整型字段且值为空字符串if (bindingContext.ModelType == typeof(int) || bindingContext.ModelType == typeof(int?)){if (string.IsNullOrWhiteSpace(valueProviderResult.AttemptedValue)){// 对于不可空int返回0,对于可空int返回nullreturn bindingContext.ModelType == typeof(int) ? (object)0 : null;}}}return base.BindModel(controllerContext, bindingContext);}
}

2. 注册全局模型绑定器(在 Global.asax.cs 中):

protected void Application_Start()
{AreaRegistration.RegisterAllAreas();FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);RouteConfig.RegisterRoutes(RouteTable.Routes);BundleConfig.RegisterBundles(BundleTable.Bundles);// 注册自定义模型绑定器ModelBinders.Binders.DefaultBinder = new EmptyStringToZeroModelBinder();
}

或者针对特定属性注册:

// 在模型类中
[ModelBinder(typeof(EmptyStringToZeroModelBinder))]
public int Id { get; set; }

方案四:使用字符串类型接收再转换

public class YourModel
{public string IdString { get; set; } // 用字符串接收public string Name { get; set; }// 添加一个只读属性来获取转换后的整型值public int Id {get{if (int.TryParse(IdString, out int result))return result;return 0; // 或者根据业务需求返回默认值}}
}

方案五:使用 JSON 反序列化设置

如果你使用的是 Newtonsoft.Json,可以配置反序列化设置:

var settings = new JsonSerializerSettings
{Converters = new List<JsonConverter> { new EmptyStringToZeroConverter() },NullValueHandling = NullValueHandling.Ignore
};// 在Action中手动反序列化
[HttpPost]
public ActionResult YourAction()
{string json = new StreamReader(Request.InputStream).ReadToEnd();var model = JsonConvert.DeserializeObject<YourModel>(json, settings);// 处理model
}

需要创建相应的转换器:

public class EmptyStringToZeroConverter : JsonConverter
{public override bool CanConvert(Type objectType){return objectType == typeof(int) || objectType == typeof(int?);}public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer){if (reader.TokenType == JsonToken.String && string.IsNullOrEmpty((string)reader.Value)){return objectType == typeof(int) ? 0 : (int?)null;}return serializer.Deserialize(reader, objectType);}public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer){serializer.Serialize(writer, value);}
}

推荐方案

  1. 首选方案一(前端处理):最清晰,责任分离明确
  2. 次选方案二(使用 int?:简单有效,适合大多数场景
  3. 复杂场景用方案三(自定义模型绑定器):适合需要全局处理的情况

推荐文章

【C#】.net core 8.0 MVC在一次偶然间发现控制器方法整个Model实体类对象值为null,猛然发现原来是

【C#】.net framework 4.8非常久远的框架如何把日期格式/Date(1754548600000)/以及带T的2025-08-07T14:36:40时间格式转为统一的格式输出

【C#】实体类定义的是long和值识别到的是Int64,实体类反射容易出现Object does not match target type

【C#】如果有一个数值如 168.0000100,如何去除末尾的无效零,只显示有效的小数位数,让DeepSeek给我们解答

【C#】Quartz.NET怎么动态调用方法,并且根据指定时间周期执行,动态配置类何方法以及Cron表达式,有请DeepSeek

【C#】.net core6.0无法访问到控制器方法,直接404。由于自己的不仔细,出现个低级错误,这让DeepSeek看出来了,是什么错误呢,来瞧瞧

【C#】Html转Pdf,Spire和iTextSharp结合,.net framework 4.8

【C#】事务(进程 ID 64)与另一个进程被死锁在锁资源上,并且已被选作死锁牺牲品。请重新运行该事务。不能在具有唯一索引“XXX_Index”的对象“dbo.Test”中插入重复键的行。

【C#】使用DeepSeek帮助评估数据库性能问题,C# 使用定时任务,每隔一分钟移除一次表,再重新创建表,和往新创建的表追加5万多条记录

【C#】合理使用DeepSeek相关AI应用为我们提供强有力的开发工具,在.net core 6.0框架下使用JsonNode动态解析json字符串,如何正确使用单问号和双问号做好空值处理

【C#】已经实体类和动态实体类的反射使用方法,两分钟回顾,码上就懂

【C#】使用vue3的axios发起get和post请求.net framework部署的API显示跨域

【C#】.net core 6.0 webapi 使用core版本的NPOI的Excel读取数据以及保存数据

【C#】pdf按页分割文件,以及分页合并,效果还不错,你值得拥有

【C#】未能加载文件或程序集“CefSharp.Core.Runtime.dll”或它的某一个依赖项。找不到指定的模块。

【C#】.net core 6.0 在program时间格式统一json格式化,并列举program默认写法和简化写法

【C#】.net core 6.0 ApiController,API控制器方法,API接口以实体类作为接收参数应该注意的点

【C#】 SortedDictionary,查找字典中是否存在给定的关键字

【C#】.net core 6.0 MVC返回JsonResult显示API接口返回值不可被JSON反序列化

【C#】.net core 6.0 使用第三方日志插件Log4net,配置文件详细说明

【C#】使用代码实现龙年春晚扑克牌魔术(守岁共此时),代码实现篇

【C#】使用代码实现龙年春晚扑克牌魔术(守岁共此时),流程描述篇


文章转载自:

http://LFw4oMYB.pffyc.cn
http://yUhTXpr3.pffyc.cn
http://R8mJINqj.pffyc.cn
http://7cccMHSf.pffyc.cn
http://8Nwe59Ik.pffyc.cn
http://IJHCIW6K.pffyc.cn
http://c2kH6Ge7.pffyc.cn
http://UtvdLdTm.pffyc.cn
http://A95bibQC.pffyc.cn
http://6g5gBeT9.pffyc.cn
http://g7Om7tq2.pffyc.cn
http://FB2s7yzg.pffyc.cn
http://aRujd4zM.pffyc.cn
http://3QORxBes.pffyc.cn
http://9yldReGK.pffyc.cn
http://qUqUrcLZ.pffyc.cn
http://wgT1pwQZ.pffyc.cn
http://0gUga6yg.pffyc.cn
http://WJHOM8t4.pffyc.cn
http://F05cexS0.pffyc.cn
http://2tv8dtY1.pffyc.cn
http://4dJMZt2i.pffyc.cn
http://4UvmSStV.pffyc.cn
http://mpkl1JaI.pffyc.cn
http://lYOaahQl.pffyc.cn
http://M9xFoMLu.pffyc.cn
http://5Hd74oGF.pffyc.cn
http://9Y9NLC3Y.pffyc.cn
http://oSa7UQyh.pffyc.cn
http://jsGxh5R3.pffyc.cn
http://www.dtcms.com/a/384564.html

相关文章:

  • 【小白笔记】 Linux 命令及其含义
  • vue ElementUI textarea在光标位置插入指定变量及校验
  • 边缘人工智能计算机
  • 亚远景侯亚文老师受邀出席PTC中国数字化转型精英汇,分享汽车研发破局“三擎”之道
  • K8S结合Istio深度实操
  • 【SQLMap】POST请求注入
  • 【C++实战⑪】解锁C++结构体:从基础到实战的进阶之旅
  • SAP-ABAP:SAP业务伙伴角色查询:BAPI_BUPA_ROLES_GET_2 详解与实践
  • 【openGLES】帧缓冲区对象frameBufferObject(FBO)
  • 端口转发神器Rinetd:轻量级安装与配置指南
  • Cursor+Claude编程+工作体会
  • [数据结构——lesson12.希尔排序]
  • Field II 超声成像仿真 1--得到Bmode图像
  • SpringBoot整合RustFS:全方位优化文件上传性能
  • 硬件(十一):EPIT、GPT、UART 外设配置
  • 趣味学RUST基础篇(OOP)
  • 微服务网关的bug
  • Rust 与 C/C++ 的特性对比
  • mac 安装hive
  • Nginx 从入门到进阶:反向代理、负载均衡与高性能实战指南
  • 微服务-nacos服务中心
  • uniApp开发XR-Frame微信小程序 | 动态加载与删除模型
  • AR 巡检在工业的应用|阿法龙XR云平台
  • eureka微服务注册问题
  • 【LangChain指南】大语言模型(LLMs)
  • 一台设备管理多个 GitHub 账号:从配置到切换的完整指南
  • K - 近邻(KNN)算法:基于约会数据集的分类任务全流程
  • 机器学习实战第四章 线性回归
  • 概率统计面试题2:随机抛掷两点到圆心距离较小值的期望
  • 什么是 OFDM?它如何解决频率选择性衰落?