2011-01-25 15 views
65

Sto cercando una soluzione per il POST di un array di oggetti su MVC3 tramite JSON.Pubblica una matrice di oggetti tramite JSON su ASP.Net MVC3

codice di esempio sto lavorando fuori di: 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 
} 

Il risultato di questa POST:

elenco è impostato, ad un ListViewModel
sue proprietà X e Y sono impostati
La struttura ITEMLIST sottostante è impostata
L'ITEMLIST contiene un articolo, come dovrebbe
L'elemento in tale ItemList non è inizializzato. Str è nullo e Abilitato è falso.

In altre parole, questo è quello che ricevo da vincolante il modello di MVC3:

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

Sembrerebbe il MVC3 JsonValueProvider non funziona per gli oggetti complessi. Come faccio a far funzionare questo? Devo modificare l'attuale MVC3 JsonValueProvider e correggerlo? In tal caso, come posso ottenerlo e sostituirlo in un progetto MVC3?

domande

StackOverflow correlati ho già perseguiti senza alcun risultato:

Asp.net Mvc Ajax Json (post Array) Usi MVC2 e più vecchio di codifica basata su form - questo approccio non riesce con un oggetto che contiene un array di oggetti (JQuery non riesce a codificare in modo corretto).

Post an array of complex objects with JSON, JQuery to ASP.NET MVC Controller Utilizza un trucco Vorrei evitare dove il controller riceve invece una stringa semplice che poi deserializza manualmente da sé, invece di sfruttare il framework.

MVC3 RC2 JSON Post Binding not working correctly Non ha il suo set di tipi di contenuto - è impostato nel mio codice.

How to post an array of complex objects with JSON, jQuery to ASP.NET MVC Controller? Questo povero ragazzo ha dovuto scrivere un JsonFilter solo per analizzare un array. Un altro trucco che preferirei evitare.

Quindi, come posso farlo?

+0

Aggiornamento: ho scavato in JsonValueProviderFactory. Usa correttamente la proprietà "str" ​​e lo aggiunge al dizionario di supporto come Key = "ItemList [0] .Str", Value = "hi", che sembra corretto. ModelBinder? –

+1

Lei, signore, ha appena ricevuto un upvote e una stella per l'eccellente esecuzione di una domanda di overflow dello stack! :) – Moulde

+0

Anche qui, questo è stato finalmente quello che ha funzionato per me. Grazie! – Otake

risposta

30

Il problema era che le proprietà nei modelli che erano nell'Elenco non avevano get/set sulle loro proprietà pubbliche. In altre parole, l'associazione JSON automatica di MVC3 funziona solo sulle proprietà dell'oggetto che hanno ottenuto e impostato.

Questo non legherà:

public string Str; 

Questo si legano:

public string Str { get; set; } 
+5

Vorrei solo dire: for (;;) { Console.WriteLine ("Grazie, Chris!"); } –

+4

Chris, mi piace come metti tutto in un altro modo. +1;) – Gleno

+0

Si noti che 'public string Str;' non è una proprietà ma solo un campo. ["I campi sono variabili membro ordinarie o istanze membro di una classe.Le proprietà sono un'astrazione per ottenere e impostare valori (campo)."] (Http://www.c-sharpcorner.com/uploadfile/puranindia/fields-and- properties-in-C-Sharp /) Perché JsonValueProvider ha rifiutato di aggiornare i campi è un'altra domanda! – jpaugh

28

Questo è strano. Non riesco a riprodurre il tuo comportamento. Ecco la mia configurazione (ASP.NET MVC 3 RTM):

Modello:

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; } 
} 

Controller:

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

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

Vista:

@{ 
    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> 

L'esecuzione di questo avvisa "hi" e dentro il tutto Save azione viene inizializzato correttamente .

E per la cronologia ciò che non funziona sono dizionari. Ho opened a ticket sul problema.

+0

Strano. Grazie per aver esaminato questo. Per quello che vale, sto usando la versione di MVC qui: http://www.asp.net/mvc/mvc3 - È possibile che usiamo diverse versioni di MVC, anche se sarebbe strano se questo avesse WORSE in la versione finale. Cercherò di isolare le cose un po 'meglio e verificare le affermazioni della mia domanda prima di contrassegnare questa risposta o meno. –

+0

Ho trovato il problema. Il modello interno utilizzava proprietà pubbliche che non avevano get/set. Risolverò la domanda per espandere il problema. –

+5

TUTTI: Nota questa riga >>> contentType: 'application/json' – Korayem

43

Oltre a { get; set; }, queste sono alcune delle condizioni per JSON Binding Supporto:

  1. Questo è una nuova funzionalità di ASP.NET MVC 3 (vedere "JavaScript and AJAX Improvements").
  2. Le stringhe dell'oggetto JSON ('X', 'Y', 'Str' e 'Enabled') devono corrispondere alle proprietà dell'oggetto ViewModel.
  3. Le proprietà dell'oggetto ViewModel devono avere il metodo { get; set; }.
  4. Specificare il tipo di contenuto come "application/json" nella richiesta.
  5. Se non funziona ancora, controllare la stringa JSON per assicurarsi che sia valida.

Ulteriori informazioni allo my post.

Spero che questo aiuti!

+0

Grazie per i dettagli su questo. Risulta che ho avuto e chiamata ajax che non ha specificato il tipo di contenuto 'application/json', e tutto ha funzionato eccezionalmente popolando le proprietà degli elementi dell'array! Il problema – Annagram

+0

per me era il contentType, grazie –

+0

Panoramica assoluta, chiara e concisa dei requisiti per il supporto di json biding per lavorare fuori dalla scatola con asp.net mvc. Un riferimento prezioso e una grande risposta. – nocarrier

3

Avevo un problema simile e ho rilevato che per un oggetto complesso, i valori numerici venivano persi. Stavano entrando come zeri. cioè

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

veniva ricevuto dal controllore MVC come oggetto una persona in cui le proprietà venivano popolate come Name=John e Age=0.

Ho poi fatto il valore di validità in Javascript sia stringa ... cioè

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

E questo è venuto attraverso bene ...

0

suo perché i leganti MVC tipo di succhiare. Tuttavia, funzionano abbastanza bene se tutti i valori JSON vengono visualizzati come una stringa.

In JS se fate questo

var myObject = {thisNumber:1.6}; 

myObject.thisNumber=myObject.thisNumber-.6; 

valuterà di non 1-1,0

Quindi, quando hai inviato verso il server tenterà di legarsi ad un galleggiante di quel nome e non lo troverà da quando è arrivato come 1 invece di 1.0. È molto schifoso e pazzo che gli ingegneri MS non abbiano trovato una soluzione predefinita. Trovo che se stringa tutto il binding è abbastanza intelligente da trovare le cose.

Quindi, prima di inviare i dati, eseguirlo tramite un identificatore che convertirà anche tutti i valori in stringhe.

0

Tutte le risposte precedenti sono state ottime per indicarmi la soluzione del problema simile. Ho dovuto POST x-www-form-urlencoding anziché application/json (opzione predefinita se il parametro contentType è mancante) per poter passare __RequestVerificationToken e contemporaneamente affrontare il problema quando le proprietà dell'oggetto nell'array non associano i loro valori. Il modo per risolvere il problema è capire il lavoro interno del raccoglitore modello MVC.

Quindi, in pratica quando è necessario fornire un token di verifica, l'attributo di convalida è limitato. E devi fornire il token come parametro non come parte dell'oggetto JSON che stai inviando. Se non si usi ValidateAntiForgeryToken, è possibile andare d'accordo con JSON.stringify. Ma se vuoi, non potresti passare il token.

Ho annusato il traffico al backend quando ContentType era x-www-form-urlencoding e ho notato che la mia matrice di oggetti complessi era serializzata in qualcosa del genere: klo[0][Count]=233&klo[0][Blobs]=94. Inizialmente questa matrice era una parte dell'oggetto root, diciamo un po 'di modello. Sembrava così: model.klo = [{ Count: 233, Blobs: 94}, ...].

Sul lato posteriore questa proprietà klo creava da MVC binder con gli stessi conteggi degli elementi che ho inviato. Ma questi stessi elementi non hanno ottenuto valori per le loro proprietà.

SOLUZIONE

Per far fronte a questo ho escluso klo proprietà dall'oggetto modello al lato client. Nella funzione ajax ho scritto questo codice:

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; 
    } 

La funzione trasforma array di oggetto complesso in forma che è riconosciuto da MVC-legante. Il modulo è klo[0].Count=233&klo[0].Blobs=94.

Problemi correlati