来自JSON的ASP.NET MVC 4递归模型绑定
本文关键字:递归 模型 绑定 MVC NET JSON ASP 来自 | 更新日期: 2023-09-27 18:27:16
我正在使用Fabric.js,将图形对象保存到数据库中。我们经常使用组,从而产生多个级别的嵌套图形对象。我已经创建了与从画布对象发回的值相匹配的类,它正确地绑定了绘图中的顶级项。然而,它没有绑定任何子项,我也不知道出了什么问题。
我的模型(为了简短起见,删除了一些属性:
public class DrawingObj
{
public int ParentID { get; set; } //will be populated manually
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("originX")]
public string OriginX { get; set; }
[JsonProperty("originY")]
public string OriginY { get; set; }
....
[JsonProperty("objects")]
public ICollection<DrawingObj> ChildObj { get; set; }
[JsonProperty("points")]
public ICollection<Point> Points { get; set; }
}
public class Point
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("x")]
public decimal X { get; set; }
[JsonProperty("y")]
public decimal Y { get; set; }
}
这是Json。对不起,有很多。
{"objects":[{"type":"group","originX":"center","originY":"center","left":461,"top":278,"width":126,"height":247.5,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","objects":[{"type":"rounded-polygon","originX":"center","originY":"center","left":0,"top":0,"width":126,"height":247.5,"fill":"white","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","points":[{"type":"line","x":-63,"y":-123.75},{"type":"line","x":-63,"y":123.75},{"type":"line","x":63,"y":123.75},{"type":"line","x":63,"y":-123.75},{"type":"line","x":-63,"y":-123.75}]},{"type":"rounded-polygon","originX":"center","originY":"center","left":0,"top":0,"width":125,"height":246.25,"fill":"white","stroke":1,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","points":[{"type":"line","x":-62.5,"y":-123.125},{"type":"line","x":-62.5,"y":123.125},{"type":"line","x":62.5,"y":123.125},{"type":"line","x":62.5,"y":-123.125},{"type":"line","x":-62.5,"y":-123.125}]},{"type":"rounded-polygon","originX":"center","originY":"center","left":0,"top":0,"width":111.38,"height":231,"fill":"white","stroke":1,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","points":[{"type":"line","x":-55.6875,"y":-115.5},{"type":"line","x":-55.6875,"y":115.5},{"type":"line","x":55.6875,"y":115.5},{"type":"line","x":55.6875,"y":-115.5},{"type":"line","x":-55.6875,"y":-115.5}]},{"type":"rounded-polygon","originX":"center","originY":"center","left":0,"top":0,"width":96,"height":215.25,"fill":"#C9C9C9","stroke":1,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","points":[{"type":"line","x":-48,"y":-107.625},{"type":"line","x":-48,"y":107.625},{"type":"line","x":48,"y":107.625},{"type":"line","x":48,"y":-107.625},{"type":"line","x":-48,"y":-107.625}]},{"type":"rounded-polygon","originX":"center","originY":"center","left":0,"top":0,"width":91.5,"height":210.75,"fill":"black","stroke":1,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","points":[{"type":"line","x":-45.75,"y":-105.375},{"type":"line","x":-45.75,"y":105.375},{"type":"line","x":45.75,"y":105.375},{"type":"line","x":45.75,"y":-105.375},{"type":"line","x":-45.75,"y":-105.375}]},{"type":"rounded-polygon","originX":"center","originY":"center","left":0,"top":0,"width":90,"height":209.62,"fill":"#A5EDF2","stroke":1,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","points":[{"type":"line","x":-45,"y":-104.811},{"type":"line","x":-45,"y":104.811},{"type":"line","x":45,"y":104.811},{"type":"line","x":45,"y":-104.811},{"type":"line","x":-45,"y":-104.811}]},{"type":"custom-circle","originX":"center","originY":"center","left":0,"top":0,"width":20,"height":20,"fill":"white","stroke":2,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","radius":10},{"type":"named-text","originX":"center","originY":"center","left":0,"top":0,"width":6,"height":15.6,"fill":"black","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","text":"1","fontSize":12,"fontWeight":"normal","fontFamily":"Times New Roman","fontStyle":"","lineHeight":1.3,"textDecoration":"","textAlign":"left","path":null,"textBackgroundColor":"","useNative":true,"name":"label"}]},{"type":"group","originX":"center","originY":"center","left":598,"top":277,"width":126,"height":247.5,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","objects":[{"type":"rounded-polygon","originX":"center","originY":"center","left":0,"top":0,"width":126,"height":247.5,"fill":"white","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","points":[{"type":"line","x":-63,"y":-123.75},{"type":"line","x":-63,"y":123.75},{"type":"line","x":63,"y":123.75},{"type":"line","x":63,"y":-123.75},{"type":"line","x":-63,"y":-123.75}]},{"type":"rounded-polygon","originX":"center","originY":"center","left":0,"top":0,"width":125,"height":246.25,"fill":"white","stroke":1,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","points":[{"type":"line","x":-62.5,"y":-123.125},{"type":"line","x":-62.5,"y":123.125},{"type":"line","x":62.5,"y":123.125},{"type":"line","x":62.5,"y":-123.125},{"type":"line","x":-62.5,"y":-123.125}]},{"type":"rounded-polygon","originX":"center","originY":"center","left":0,"top":0,"width":111.38,"height":231,"fill":"white","stroke":1,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","points":[{"type":"line","x":-55.6875,"y":-115.5},{"type":"line","x":-55.6875,"y":115.5},{"type":"line","x":55.6875,"y":115.5},{"type":"line","x":55.6875,"y":-115.5},{"type":"line","x":-55.6875,"y":-115.5}]},{"type":"rounded-polygon","originX":"center","originY":"center","left":0,"top":0,"width":96,"height":215.25,"fill":"#C9C9C9","stroke":1,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","points":[{"type":"line","x":-48,"y":-107.625},{"type":"line","x":-48,"y":107.625},{"type":"line","x":48,"y":107.625},{"type":"line","x":48,"y":-107.625},{"type":"line","x":-48,"y":-107.625}]},{"type":"rounded-polygon","originX":"center","originY":"center","left":0,"top":0,"width":91.5,"height":210.75,"fill":"black","stroke":1,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","points":[{"type":"line","x":-45.75,"y":-105.375},{"type":"line","x":-45.75,"y":105.375},{"type":"line","x":45.75,"y":105.375},{"type":"line","x":45.75,"y":-105.375},{"type":"line","x":-45.75,"y":-105.375}]},{"type":"rounded-polygon","originX":"center","originY":"center","left":0,"top":0,"width":90,"height":209.62,"fill":"#A5EDF2","stroke":1,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","points":[{"type":"line","x":-45,"y":-104.811},{"type":"line","x":-45,"y":104.811},{"type":"line","x":45,"y":104.811},{"type":"line","x":45,"y":-104.811},{"type":"line","x":-45,"y":-104.811}]},{"type":"custom-circle","originX":"center","originY":"center","left":0,"top":0,"width":20,"height":20,"fill":"white","stroke":2,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","radius":10},{"type":"named-text","originX":"center","originY":"center","left":0,"top":0,"width":6,"height":15.6,"fill":"black","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","text":"2","fontSize":12,"fontWeight":"normal","fontFamily":"Times New Roman","fontStyle":"","lineHeight":1.3,"textDecoration":"","textAlign":"left","path":null,"textBackgroundColor":"","useNative":true,"name":"label"}]}],"background":""}
Ajax调用:
var jsontext = JSON.stringify(canvas);
$.ajax({
url: '/Project/SaveDrawing/',
data: jsontext,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
type: 'post',
success: onSaved,
error: function (data, textStatus) { alert(textStatus); }
});
控制器:
[HttpPost]
public JsonResult SaveDrawing(ICollection<DrawingObj> objects)
{
try
{
if (objects != null)
{
bool saved = Drawing.SaveDrawing(objects);
return Json(new { success = saved });
}
}
catch (Exception ex)
{
error = ex.Message;
}
return Json(new { success = false, error = error });
}
因此,我的两个顶级项完全按照预期绑定,但ChildObj和Points都为null。我不明白为什么这些集合没有绑定,因为我相信我的命名是正确的。
提前感谢您的帮助。
很明显,ASP.NET MVC DefaultModelBinder
在那里工作不正常。
一种方法是为对象创建自定义模型绑定器。首先,您必须添加一个额外的类来正确地将您发布的JSON映射到控制器。
[JsonObject]
public class ContainerObj
{
[JsonProperty("objects")]
public ICollection<DrawingObj> Objects { get; set; }
[JsonProperty("background")]
public string Background { get; set; }
}
然后,您将创建一个自定义模型绑定器,使用JSON.NET:将此对象反序列化为您需要的对象
public class ContainerObjModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType == typeof(ContainerObj))
{
var data = GetDocumentContents(controllerContext.HttpContext.Request);
return JsonConvert.DeserializeObject<ContainerObj>(data);
}
return base.BindModel(controllerContext, bindingContext);
}
private string GetDocumentContents(System.Web.HttpRequestBase Request)
{
string documentContents;
using (var receiveStream = Request.InputStream)
{
using (var readStream = new StreamReader(receiveStream, Encoding.UTF8))
{
readStream.BaseStream.Seek(0, SeekOrigin.Begin);
documentContents = readStream.ReadToEnd();
}
}
return documentContents;
}
}
然后你可以在Global.asax
:中注册这个自定义模型绑定器
ModelBinders.Binders.Add(typeof(ContainerObj), new ContainerObjModelBinder());
最后,您的控制器会自动识别出需要使用自定义模型绑定器:
[HttpPost]
public JsonResult SaveDrawing(ContainerObj data)
{
// Request processing
}
默认的模型绑定器不符合JSON.Net属性,因此子JSON元素"objects"
被完全忽略。
只需在JSON中将子"objects"
更改为"childObj"
(以匹配模型属性名称),就可以使用默认的模型绑定器。
{ "objects":
[{ "type": "group", "originX": "center", "originY": "center", ...
"childObj": [{ "type": "rounded-polygon", "originX": "center", "originY": "center",
...
}
否则,按照ZenCoder的建议,创建一个使用JSON.Net属性的自定义模型绑定器。