【C#】.net core 8.0 MVC在一次偶然间发现控制器方法整个Model实体类对象值为null,猛然发现原来是
尽管博主工作了十来年,但是有些知识点还是容易忽略。比如这次遇到的后端接收参数问题,居然因为一个传递数据类型导致整个实体参数值为null.
🌹欢迎来到《小5讲堂》🌹
🌹这是《C#》系列文章,每篇文章将以博主理解的角度展开讲解。🌹
🌹温馨提示:博主能力有限,理解水平有限,若有不对之处望指正!🌹
目录
前言
尽管博主工作了十来年,但是有些知识点还是容易忽略。
比如这次遇到的后端接收参数问题,居然因为一个传递数据类型导致整个实体参数值为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返回null
return 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,配置文件详细说明
更多推荐
所有评论(0)