jQuery JSON将对象保存到ASP.NET MVC2
我正在使用ASP.NET MVC2和jQuery加载和保存对象。我使用knockout.js的对象序列化/反序列化来在加载/保存数据时安全地维护对象的数据结构 在ASP.NET的服务器端,当我使用下面的JavaScript方法将对象以其精确结构发送回服务器时,我的GraduationClass对象被实例化,但它没有任何数据 我在firebug中检查了post数据,所有数据都以正确的结构正确地发送回请求中的服务器,但是ASP.NET MVC内部管道无法将数据反序列化回GraduationClass对象。我尝试了使用和不使用contentType设置 我想知道我做错了什么jQuery JSON将对象保存到ASP.NET MVC2,jquery,ajax,json,asp.net-mvc-2,deserialization,Jquery,Ajax,Json,Asp.net Mvc 2,Deserialization,我正在使用ASP.NET MVC2和jQuery加载和保存对象。我使用knockout.js的对象序列化/反序列化来在加载/保存数据时安全地维护对象的数据结构 在ASP.NET的服务器端,当我使用下面的JavaScript方法将对象以其精确结构发送回服务器时,我的GraduationClass对象被实例化,但它没有任何数据 我在firebug中检查了post数据,所有数据都以正确的结构正确地发送回请求中的服务器,但是ASP.NET MVC内部管道无法将数据反序列化回GraduationClass
// javascript save method
function save(graduationClass) {
$.ajax({
url: "/SiteManagement/saveGraduationClass",
type: "POST",
// data: ko.mapping.toJSON(graduationClass), // (solution 1)
data: graduationClass, // (solution 2)
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
});
}
// both solutions result in a blank object construction on the server side
// ASP.NET MVC2 AJAX method
[HttpPost]
public ActionResult saveGraduationClass(GraduationClass graduationClass) {
// graduationClass here has all default data rather than the data sent in the post
return Json(new { resultText = "success" }, JsonRequestBehavior.AllowGet);
}
我相信有两个可能的问题 首先,我非常确定,当您指定在Ajax请求中发送JSON时,jQuery将序列化在数据参数中传递的Javascript对象。您肯定是在创建一个jQuery对象,其属性
json
的值为字符串(我相信,我不熟悉knockout)。然后,传递给MVC的值将如下所示:
{
json : 'string of graduationClass data '
}
这有点像双重序列化
第二个问题是,前面的JSON与您的saveGraduationClass
方法参数graduationClass
不匹配
我认为这两种解决方案中的任何一种都应该有效:
data: ko.toJSON(graduationClass), // knockout.js utility method
或
更新
如果我有这门课:
public class Person
{
public string Name { get; set; }
}
我有一个JSON:
{
Name : 'Jon Doe'
}
然后它将填充此方法:
public ActionResult SomeMethod(Person person)
但是,以下JSON将不起作用:
{
json : '{ Name : "Jon Doe" }'
}
它也将不匹配:
{
json :
{
Name : 'Jon Doe'
}
}
JSON的布局需要与试图填充的类的布局完全匹配。您好,我认为问题可能出在默认的JsonValueProvider中,但您可以编写一个自定义的JsonValueProvider:
public sealed class JsonDotNetValueProviderFactory : ValueProviderFactory
{
private static void AddToBackingStore(Dictionary<string, object> backingStore, string prefix, object value)
{
IDictionary<string, object> d = value as IDictionary<string, object>;
if (d != null)
{
foreach (KeyValuePair<string, object> entry in d)
{
AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value);
}
return;
}
IList l = value as IList;
if (l != null)
{
for (int i = 0; i < l.Count; i++)
{
AddToBackingStore(backingStore, MakeArrayKey(prefix, i), l[i]);
}
return;
}
// primitive
backingStore[prefix] = value;
}
private static object GetDeserializedObject(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
// not JSON request
return null;
}
StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
string bodyText = reader.ReadToEnd();
if (String.IsNullOrEmpty(bodyText))
{
// no JSON data
return null;
}
object jsonData = new JavaScriptSerializer().DeserializeObject(bodyText);
return jsonData;
}
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
object jsonData = GetDeserializedObject(controllerContext);
if (jsonData == null)
{
return null;
}
Dictionary<string, object> backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
AddToBackingStore(backingStore, String.Empty, jsonData);
return new DictionaryValueProvider<object>(backingStore, CultureInfo.CurrentCulture);
}
private static string MakeArrayKey(string prefix, int index)
{
return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]";
}
private static string MakePropertyKey(string prefix, string propertyName)
{
return (String.IsNullOrEmpty(prefix)) ? propertyName : prefix + "." + propertyName;
}
}
我认为这绝对是正确的方向。没有将毕业班作为命名参数似乎是一个错误。js的toJSON方法保留了额外的映射数据,所以我需要弄清楚是否可以删除它。如果对象不完全匹配,ASP.NET MVC中的序列化是否无效?或者它会忽略无法识别的字段?逻辑非常简单,需要匹配。使用ko.mapping.toJSON(graduationClass),我现在有了一个精确的结构匹配。。。但是,尽管GraduationClass对象正在实例化,但它仍然只有默认数据值。我刚刚确认json在加载和保存时是完全匹配的。正如我前面所说的,您正在另一个jquery对象中封装您的
toJSON
,实际上是双重序列化。请尝试我发布的第一个解决方案。Erik-再次感谢您的帮助。我用我对你们两种解决方案的解释修改了原来的帖子。然而,我仍然得到一个空白的graduationClass被传递到服务器端的saveGraduationClass方法中。我实际上将post更改为更简单的$.post(“/SiteManagement/saveGraduationClass”,{graduationClass:graduationClass},函数(数据){//code goes here});--并且仍然得到相同的结果。ko.mapping.toJSON(graduationClass)-这很有帮助。但是,由于某种原因,虽然对象不是以null形式输入(一件好事),但它只是缺少数据。@Adamlevit是否尝试替换值提供程序?现在尝试。。。虽然这看起来是一个非常大的障碍,所以这是朝着正确方向迈出的一大步,但这给我留下了一些问题。1.它没有正确序列化标准JSON日期格式(例如/date(1335412800000)/)。2.这可能会产生什么其他影响?3.为什么这是必需的,而不是现成的?这对我来说是最好的解决方案:
public sealed class JsonDotNetValueProviderFactory : ValueProviderFactory
{
private static void AddToBackingStore(Dictionary<string, object> backingStore, string prefix, object value)
{
IDictionary<string, object> d = value as IDictionary<string, object>;
if (d != null)
{
foreach (KeyValuePair<string, object> entry in d)
{
AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value);
}
return;
}
IList l = value as IList;
if (l != null)
{
for (int i = 0; i < l.Count; i++)
{
AddToBackingStore(backingStore, MakeArrayKey(prefix, i), l[i]);
}
return;
}
// primitive
backingStore[prefix] = value;
}
private static object GetDeserializedObject(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
// not JSON request
return null;
}
StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
string bodyText = reader.ReadToEnd();
if (String.IsNullOrEmpty(bodyText))
{
// no JSON data
return null;
}
object jsonData = new JavaScriptSerializer().DeserializeObject(bodyText);
return jsonData;
}
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
object jsonData = GetDeserializedObject(controllerContext);
if (jsonData == null)
{
return null;
}
Dictionary<string, object> backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
AddToBackingStore(backingStore, String.Empty, jsonData);
return new DictionaryValueProvider<object>(backingStore, CultureInfo.CurrentCulture);
}
private static string MakeArrayKey(string prefix, int index)
{
return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]";
}
private static string MakePropertyKey(string prefix, string propertyName)
{
return (String.IsNullOrEmpty(prefix)) ? propertyName : prefix + "." + propertyName;
}
}
ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
ValueProviderFactories.Factories.Add(new JsonDotNetValueProviderFactory());
var jsonModel = ko.mapping.toJSON(graduationClass);
$.ajax({
url: '/SiteManagement/saveGraduationClass',
type: 'POST',
dataType: 'json',
data: jsonModel,
contentType: 'application/json; charset=utf-8',
success: function (data) {
// get the result and do some magic with it
}
});