【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);}
}
推荐方案
- 首选方案一(前端处理):最清晰,责任分离明确
- 次选方案二(使用
int?
):简单有效,适合大多数场景 - 复杂场景用方案三(自定义模型绑定器):适合需要全局处理的情况
推荐文章
【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#】使用代码实现龙年春晚扑克牌魔术(守岁共此时),流程描述篇