2011-01-25 21 views
65

JSONを使用してMVC3にオブジェクトの配列をポストするソリューションを探しています。私はのオフに働いてJSONを介してASP.Netにオブジェクトの配列を投稿するMVC3

例コード: http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx

JS:

var data = { ItemList: [ {Str: 'hi', Enabled: true} ], X: 1, Y: 2 }; 

$.ajax({ 
    url: '/list/save', 
    data: JSON.stringify(data), 
    success: success, 
    error: error, 
    type: 'POST', 
    contentType: 'application/json, charset=utf-8', 
    dataType: 'json' 
}); 

ListViewModel.cs:

public class ListViewModel 
{ 
    public List<ItemViewModel> ItemList { get; set; } 
    public float X { get; set; } 
    public float Y { get; set; } 
} 

ItemViewModel.cs:

public class ItemViewModel 
{ 
    public string Str; // originally posted with: { get; set; } 
    public bool Enabled; // originally posted with: { get; set; } 
} 

ListController.cs:

public ActionResult Save(ListViewModel list) 
{ 
    // Do something 
} 

このPOSTの結果:

リストが設定され、下地ITEMLISTプロパティが設定されている
そのXおよびYプロパティが
に設定されているListViewModelに
ITEMLIST 1つのアイテムが含まれています。
そのItemListのアイテムは初期化されていません。 Strはnull、Enabledはfalseです。

別の言い方をすれば、これは私が結合MVC3のモデルから得るものです:

list.X == 1 
list.Y == 2 
list.ItemList != null 
list.ItemList.Count == 1 
list.ItemList[0] != null 
list.ItemList[0].Str == null 

をMVC3 JsonValueProviderは、複雑なオブジェクトのために働いていないと思われます。これをどのように機能させるには?既存のMVC3 JsonValueProviderを修正して修正する必要がありますか?もしそうなら、どうやってMVC3プロジェクトに取り替えるのですか?私はすでに無駄に追求してきました

関連StackOverflowの質問:

Asp.net Mvc Ajax Json (post Array) はMVC2と古いフォームベースのエンコードを使用する - そのアプローチは、オブジェクトの配列を含むオブジェクトで失敗(jQueryのそれを適切にエンコードするために失敗しました)。

Post an array of complex objects with JSON, JQuery to ASP.NET MVC Controller ハックを使用する代わりにコントローラがフレームワークを利用するのではなく、手動でデシリアライズするプレーンストリングを受け取ることを避けたいと思います。

MVC3 RC2 JSON Post Binding not working correctly コンテンツタイプが設定されていません。コードに設定されています。

How to post an array of complex objects with JSON, jQuery to ASP.NET MVC Controller? この貧しい人は、配列を解析するためにJsonFilterを書く必要がありました。私が避けたいもう一つのハック。

これをどうすればいいですか?

+0

更新:私はJsonValueProviderFactoryを掘り下げました。正しく "str"プロパティを消費し、正しく見えるKey = "ItemList [0] .Str"、Value = "hi"としてバッキングディクショナリに追加します。 ModelBinder? –

+1

あなたはスタックオーバーフロー問題の優れた実行のためにupvoteとスターを受け取ったばかりです! :) – Moulde

+0

これは、これが最終的に私のために働くようになったものです。ありがとう! – Otake

答えて

30

リストにあったモデルのプロパティがパブリックプロパティで取得/設定されていないという問題がありました。別の言い方をすれば、MVC3の自動JSONバインディングは、取得して設定したオブジェクトプロパティに対してのみ機能します。

これは結合しない。

public string Str; 

をこれが結合します:

public string Str { get; set; } 
+5

私は言いたい:(;;) { ます。Console.WriteLineため ( "クリス、ありがとうございます!"); } –

+4

クリス、私はあなたがすべてを別の方法でどのように置くのが好きです。 +1;) – Gleno

+0

'public string Str;'はプロパティではなく単なるフィールドであることに注意してください。 ["フィールドは一般的なメンバ変数またはクラスのメンバインスタンスです。プロパティはフィールド値を取得および設定するための抽象です" [http://www.c-sharpcorner.com/uploadfile/puranindia/fields-and-プロパティーのCシャープ/)なぜJsonValueProviderがフィールドの更新を拒否したのかは別の問題です。 – jpaugh

28

これは奇妙です。あなたの行動を再現することができません。ここに私のセットアップ(ASP。NET MVC 3 RTM):

モデル:

public class ItemViewModel 
{ 
    public string Str { get; set; } 
    public bool Enabled { get; set; } 
} 

public class ListViewModel 
{ 
    public List<ItemViewModel> ItemList { get; set; } 
    public float X { get; set; } 
    public float Y { get; set; } 
} 

コントローラー:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     return View(); 
    } 

    [HttpPost] 
    public ActionResult Save(ListViewModel list) 
    { 
     return Json(list); 
    } 
} 

ビュー:

@{ 
    ViewBag.Title = "Home Page"; 
} 

<script type="text/javascript"> 
    $(function() { 
     var data = { ItemList: [{ Str: 'hi', Enabled: true}], X: 1, Y: 2 }; 

     $.ajax({ 
      url: '@Url.Action("save", "home")', 
      data: JSON.stringify(data), 
      type: 'POST', 
      contentType: 'application/json', 
      dataType: 'json', 
      success: function (result) { 
       alert(result.ItemList[0].Str); 
      } 
     }); 
    }); 
</script> 

が、これは"hi"Save行動すべてが正しく初期化されている内に警告実行。

それだけでは動作しないものは辞書です。問題についてはopened a ticketです

+0

奇妙な。これを見ていただきありがとうございます。 MVCの価値があると私はここでMVCのバージョンを使用しています:http://www.asp.net/mvc/mvc3 - MVCのバージョンは違っていますが、最終版。私は物事をちょっと隔離し、私の質問のアサーションを確認してから、これを答えるかしないかをマークします。 –

+0

問題が見つかりました。内部モデルは取得/設定されていないパブリックプロパティを使用していました。私は問題を解決するために問題を解決します。 –

+5

EVERYONE:この行に注意してください>>> contentType: 'application/json' – Korayem

43

{ get; set; }に加えて、これらはJSONバインディングをサポートするための条件の一部です:

  1. このASP.NET MVC 3の新機能です(「JavaScript and AJAX Improvements」を参照)。
  2. JSONオブジェクトの文字列( 'X'、 'Y'、 'Str'、 'Enabled')は、ViewModelオブジェクトのプロパティと一致する必要があります。
  3. ViewModelオブジェクトのプロパティは、{ get; set; }メソッドである必要があります。
  4. 要求に「application/json」としてコンテンツタイプを指定する必要があります。
  5. まだ動作しない場合は、JSON文字列が有効であることを確認してください。

続きを読むmy postで続きます。

希望に役立ちます!

+0

これについての詳細をありがとう。私は、 'application/json'コンテンツタイプを指定していなかったことと、配列アイテムのプロパティに値を設定する例外がすべて発生したことを知っています。 – Annagram

+0

私の問題はcontentTypeでした。 –

+0

json bidingサポートがasp.net mvcで動作するための要件の絶対的、明確かつ簡潔な概要。貴重な参考資料と素晴らしい答え。 – nocarrier

3

私は同様の問題があり、複雑なオブジェクトの場合、数値が見逃されていることがわかりました。彼らはゼロとして入っていました。 即ち

var person = { 
     Name: "john", 
     Age: 9 
    } 

は特性がName=JohnAge=0として移入されたPersonオブジェクトとしてMVCコントローラによって受信されていました。

私はその後

var person = { 
     Name: "john", 
     Age: "9" 
    } 

すなわち

...文字列であることをJavaScriptで年齢値を作り、MVCバインダーは一種の吸うので、これはうまく...

0

そのを通じて来ました。しかし、すべてのJSON値が文字列として渡ってきてもうまく動作します。JSで

あなたはこの

var myObject = {thisNumber:1.6}; 

myObject.thisNumber=myObject.thisNumber-.6; 

を行う場合は、サーバーにそれを上に送られたとき、それはとても1にはない1.0

と評価されます、それはその名前のfloat型にバインドしようとしますと、 1.0の代わりに1になったので、それを見つけることはできません。 MSのエンジニアたちは、これに不満を抱き、狂ったことに、これに対するデフォルトの解決策を考え出していませんでした。私はバインディングが物事を見つけるのに十分スマートであるすべての文字列を検索します。

データを送信する前に、すべての値を文字列に変換する文字列を使用して実行します。

0

これまでのすべての回答は、私に同様の問題の解決を指摘してくれました。 application/jsonの代わりにPOST x-www-form-urlencoding(contentTypeパラメータがない場合のデフォルトのオプション)を__RequestVerificationTokenに渡す必要がありました。同時に、配列内のオブジェクトプロパティが値をバインドしないときに問題に直面しました。この問題を解決する方法は、MVCモデルバインダーの内部作業を理解することです。

基本的に、検証トークンを提供する必要がある場合、検証属性で制限されます。また、送信するJSONオブジェクトの一部ではないパラメータとしてトークンを指定する必要があります。 ValidateAntiForgeryTokenを使用しない場合は、JSON.stringifyを使用できます。しかし、あなたがするなら、あなたはトークンを渡すことができませんでした。

ContentTypex-www-form-urlencodingだったと私は複雑なオブジェクトの私の配列は、そのような何かに連載されたと述べたとき、私は、バックエンドへのトラフィックを傍受:klo[0][Count]=233&klo[0][Blobs]=94。この配列は、最初はルートオブジェクトの一部でしたが、いくつかのモデルを考えてみましょう。それはそのように見えました:model.klo = [{ Count: 233, Blobs: 94}, ...]

バックエンド側では、このkloプロパティは、MVCバインダーによって、送信した要素と同じ要素数で作成されていました。しかし、これらの要素自体は、そのプロパティの値を取得しませんでした。これに対処するには

SOLUTION

私は、クライアント側でのモデルオブジェクトからkloプロパティを除外しました。

data: $.param(model) + "&" + arrayOfObjectsToFormEncoding("klo", [{ Count: 233, Blobs: 94}, ...]) 
.... 

    function arrayOfObjectsToFormEncoding (modelPropertyName, arrayOfObjects) { 
     var result = ""; 
     if (arrayOfObjects && typeof arrayOfObjects == "object") { 
      for (var i = 0; i < arrayOfObjects.length; i++) { 
       var obj = arrayOfObjects[i]; 
       if (obj) { 
        for (var p in obj) { 
         if (obj.hasOwnProperty(p)) { 
          result += encodeURIComponent(modelPropertyName + "[" + i + "]." + p) + "=" + encodeURIComponent(obj[p]) + "&"; 
         } 
        } 
       } 
      } 
     } 

     if (result[result.length - 1] == "&") { 
      result = result.substr(0, result.length - 1); 
     } 

     return result; 
    } 

機能がMVC結合剤によって認識される形式に複雑なオブジェクトの配列を変換:ajax機能に私はこのコードを書きました。フォームはklo[0].Count=233&klo[0].Blobs=94です。

関連する問題