0

オブジェクトの読み込みと保存に ASP.NET MVC2 と jQuery を使用しています。データのロード/保存時にオブジェクトのデータ構造を安全に維持するために、knockout.js のオブジェクトのシリアル化/逆シリアル化を使用しています。

ASP.NET のサーバー側で、次の JavaScript メソッドを使用してオブジェクトを正確な構造でサーバーに送り返すと、GraduationClass オブジェクトがインスタンス化されますが、データはありません。

firebug で投稿データを確認したところ、すべてのデータが正しい構造でリクエスト内のサーバーに適切に送り返されていますが、ASP.NET MVC 内部パイプラインはデータを GraduationClass オブジェクトに逆シリアル化できません。contentType 設定の有無にかかわらず、これを試しました。

私は間違って何をしているのか疑問に思っています。

// 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);
}
4

2 に答える 2

1

こんにちは、問題はデフォルトの 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;
        }


    }

次に、これを Global.asax の Application_Start に追加します。

    ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
ValueProviderFactories.Factories.Add(new JsonDotNetValueProviderFactory());

この例ではJson.NETを使用しています

また、卒業クラスは監視可能なオブジェクトになる可能性があるため、ko.mapping プラグインko.mappingを使用することをお勧めします。

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                            
                        }
                    });
于 2012-06-11T16:35:39.767 に答える
1

2つの問題が考えられると思います。

まず、JSON を Ajax リクエストで送信するように指定すると、jQuery は data パラメーターで渡された Javascript オブジェクトをシリアライズします。あなたは間違いなく、文字列の値を持つプロパティを持つ jQuery オブジェクトを作成してjsonいます (私はノックアウトに慣れていないと思います)。MVC に渡される値は次のようになります。

{
  json : 'string of graduationClass data '
}

これは一種の二重シリアライゼーションです。

saveGraduationClass2 つ目の問題は、前の JSON がメソッドのパラメーターと一致しないことgraduationClassです。

これらのソリューションのいずれかが機能するはずだと思います:

data: ko.toJSON(graduationClass),  // knockout.js utility method

また

data: graduationClass,  // let jQuery serialize the object.

アップデート

このクラスがある場合:

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のレイアウトは、入力しようとしているクラスのレイアウトと正確に一致する必要があります。

于 2012-06-11T16:30:21.560 に答える