Model Binding无法绑定System.Drawing对象问题求助
解决System.Drawing.Size在ASP.NET MVC模型绑定中失败的问题
你遇到的问题很典型:ASP.NET的DefaultModelBinder并没有原生支持System.Drawing.Size这个值类型的模型绑定,虽然它有Width和Height属性,但默认绑定器在处理嵌套JSON对象时,没法正确实例化这个struct并为其属性赋值,导致始终得到{Height=0, Width=0}的默认值。
下面给你几个可行的解决方案,按推荐程度排序:
方案一:自定义Size类型的模型绑定器
这是最优雅的解决方案,直接扩展DefaultModelBinder的能力,让它能正确解析Size类型。
1. 创建自定义ModelBinder类
public class SizeModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { // 获取JSON中嵌套的Width和Height值 var widthValue = bindingContext.ValueProvider.GetValue($"{bindingContext.ModelName}.Width"); var heightValue = bindingContext.ValueProvider.GetValue($"{bindingContext.ModelName}.Height"); // 如果值不存在,返回空Size if (widthValue == null || heightValue == null) { return Size.Empty; } // 尝试解析为整数并创建Size实例 if (int.TryParse(widthValue.AttemptedValue, out int width) && int.TryParse(heightValue.AttemptedValue, out int height)) { return new Size(width, height); } // 解析失败时添加模型错误 bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Size格式无效,请传入有效的Width和Height整数"); return Size.Empty; } }
2. 注册绑定器
有两种注册方式:
- 局部注册:直接在
ConvertSettings的Size属性上添加特性:public class ConvertSettings : IListItem { // 其他属性... [ModelBinder(typeof(SizeModelBinder))] public System.Drawing.Size Size { get; set; } // 其他属性... } - 全局注册:在
Global.asax的Application_Start方法中注册,让整个应用都能识别Size类型的绑定:protected void Application_Start() { // 其他初始化代码... ModelBinders.Binders.Add(typeof(Size), new SizeModelBinder()); }
方案二:改用自定义DTO类替代System.Drawing.Size
如果不想写自定义绑定器,可以创建一个简单的DTO类来接收前端的Size数据,然后在控制器中转换为System.Drawing.Size。
1. 创建SizeDTO类
public class SizeDTO { public int Width { get; set; } public int Height { get; set; } // 添加隐式转换,方便后续使用 public static implicit operator Size(SizeDTO dto) { return new Size(dto.Width, dto.Height); } }
2. 修改ConvertSettings模型
public class ConvertSettings : IListItem { public int? ID { get; set; } public string Title { get; set; } // 替换原Size属性为SizeDTO public SizeDTO Size { get; set; } public SizeType SizeType { get; set; } public MimeType MimeType { get; set; } }
3. 在控制器中使用
public ActionResult ConvertPictures(ConvertSettings settings) { // 自动转换为System.Drawing.Size System.Drawing.Size actualSize = settings.Size; // 后续业务逻辑... }
方案三:手动解析JSON(应急方案)
如果以上两种方式都不想用,可以直接在控制器中读取请求的JSON内容,手动反序列化并处理Size属性:
public ActionResult ConvertPictures() { // 读取请求流中的JSON内容 string jsonContent = new StreamReader(Request.InputStream).ReadToEnd(); var jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(jsonContent); // 反序列化基本属性 var settings = jsonObj["settings"].ToObject<ConvertSettings>(); // 手动解析Size属性 var sizeJson = jsonObj["settings"]["Size"]; settings.Size = new Size( sizeJson["Width"].Value<int>(), sizeJson["Height"].Value<int>() ); // 后续业务逻辑... }
验证前端请求
你的AJAX代码是正确的:已经设置了contentType: 'application/json; charset=utf-8',并且用JSON.stringify序列化了数据,这确保了前端发送的是标准的JSON格式,所以问题完全出在后端的模型绑定逻辑上。
内容的提问来源于stack exchange,提问作者krawat10
相关产品推荐
相关产品推荐

