2011-12-22 20 views
8

In parole semplici, cosa fa UpdateModel() e TryUpdateModel()? Non riesco a trovare (su SO o sul web) alcuna spiegazione chiara di ciò che effettivamente fa (in termini chiari), solo le persone che hanno problemi ad usarlo.Cosa fa UpdateModel()?

L'intellisense di VisualStudio non mi aiuta neanche. Il motivo per cui mi chiedo è perché, diciamo, se ho questo nel mio controller:

[HttpPost] 
public ActionResult Index(UserViewModel vm, FormCollection form) 
{  
    var statesCheckBoxes = form["StatesList"];  

    vm.BA.StatesTraveledTo = statesCheckBoxes.Split(',').ToList<string>(); 

    return View(vm); 
} 

non sono già aggiornare il mio modello impostando vm.BA.StatesTraveledTo? Perché devo eseguire UpdateModel? Inoltre, quando in realtà cerco di fare quanto segue:

[HttpPost] 
public ActionResult Index(UserViewModel vm, FormCollection form) 
{  
    var statesCheckBoxes = form["StatesList"];  

    vm.BA.StatesTraveledTo = statesCheckBoxes.Split(',').ToList<string>(); 

    UpdateModel(vm); // IS THIS REDUNDANT TO THE PREVIOUS LINE? 

    return View(vm); 
} 

nulla sembra accadere in quanto quando ho ispezionare il valore del ModelState (dopo corro UpdateModel()), non vedo nulla che indica che qualsiasi cosa è cambiato. Non vedo una nuova chiave nel dizionario ModelState.

Davvero confuso. Grazie!

Edit:

Distacco il codice sorgente per le classi ViewModel e modello:

public class UserViewModel 
{ 
    public BankAccount BA { get; set; } 
} 

public class BankAccount 
{ 
    public Person User { get; set; } 
    public List<string> StatesTraveledTo { get; set; } 
} 

public class Person 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public int Age { get; set; } 
} 
+1

Ecco il codice sorgente per esso: http://aspnet.codeplex.com/SourceControl/changeset/view/72551#266451 È piuttosto semplice, solo crea un ModelBindingContext e lo lega –

+1

Inoltre, è un po ' raro passare lo stesso oggetto che hai ricevuto come input in un'azione nella vista, succede ma è raro e questo non sembra uno di quegli usi. Solitamente si prende come input un oggetto che rappresenta i dati inviati e quindi si crea un modello separato per la vista –

+0

Grazie. Il motivo per cui sto restituendo il modello alla vista è a scopo di validazione. Quindi, nel caso in cui la validazione fallisca, voglio che il modello e i suoi valori siano passati alla vista in modo che i campi del modulo vengano ripopolati e venga visualizzato un messaggio di errore. Scusa, immagino che con il codice che ho mostrato, potrebbe non sembrare un esempio pratico. – SaltProgrammer

risposta

5

cosa succede quando si scrive

public ActionResult Index(UserViewModel vm) 
{ } 

e quando si controlla nel ActionResult si scopre che vm contiene i valori che hai postato dalla vista. è perché mvc indirizza il modelbinder a estrarre valori da diverse fonti (raccolta moduli, valori di instradamento, querystring ecc.) e popolare i valori del modello. Ma affinché ciò avvenga, le chiavi del modulo devono corrispondere al nome delle proprietà nel modello e, in tal caso, il modello viene compilato correttamente. ora arriviamo alla domanda vera: cosa fa UpdateModel? la semplice risposta non è altro che un modello vincolante. La differenza è solo che la chiami esplicitamente.Quanto sopra ActionResult può essere riscritta come l'utilizzo di UpdateModel

Public ActionResult Index() 
{ 
    UserViewModel vm = new UserViewModel(); 
    UpdateModel(vm);// it will do same thing that was previously handled automatically by mvc 
} 

Ora, ciò che non è stato gestito dal modello automatico vincolante non verranno trattati da modello esplicito legame così perché il suo non è il problema con il modello legante il suo problema con il vostro html . con i modelli di vista nested come la vostra, i nomi dei campi modulo devono essere realizzati con cura in modo MVC possono iniettare correttamente al modello senza dover scrivere qualcosa di simile

vm.BA.StatesTraveledTo = statesCheckBoxes.Split(',').ToList<string>(); 

e se non si vuole fare tale verifica cosa questo google search

2

Ecco il codice sorgente per esso: http://aspnet.codeplex.com/SourceControl/changeset/view/72551#266451

E 'piuttosto semplice,

protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IDictionary<string, ValueProviderResult> valueProvider) where TModel : class { 
     if (model == null) { 
      throw new ArgumentNullException("model"); 
     } 
     if (valueProvider == null) { 
      throw new ArgumentNullException("valueProvider"); 
     } 

     Predicate<string> propertyFilter = propertyName => BindAttribute.IsPropertyAllowed(propertyName, includeProperties, excludeProperties); 
    IModelBinder binder = Binders.GetBinder(typeof(TModel)); 

    ModelBindingContext bindingContext = new ModelBindingContext() { 
     Model = model, 
     ModelName = prefix, 
     ModelState = ModelState, 
     ModelType = typeof(TModel), 
     PropertyFilter = propertyFilter, 
     ValueProvider = valueProvider 
    }; 
    binder.BindModel(ControllerContext, bindingContext); 
    return ModelState.IsValid; 
} 

Thi s crea semplicemente un ModelBindingContext e lo lega. Credo che accada già di default prima che venga chiamata la tua azione. È raro doverlo chiamare manualmente.

Solo un'ipotesi, ma potresti ottenere risultati strani perché stai facendo le cose in modo atipico. Firma della tua azione:

public ActionResult Index(UserViewModel vm, FormCollection form) 

accetta un UserViewModel AND un FormCollection. Di solito le persone fanno l'una o l'altra (attualmente FormCollection è piuttosto raro al giorno d'oggi). Di nuovo, sto andando fuori memoria qui, ma suppongo che UpdateModel non faccia nulla perché quei valori sono già vincolati. Se è vuoto, forse è perché FormCollection riceve (associa) tutti i valori inviati e nessuno viene lasciato al viewmodel a cui legarsi.

+0

Grazie. Perdonate la mia noobness- state dicendo che UpdateModel() viene eseguito di default prima della mia azione quindi non c'è bisogno di eseguire esplicitamente dall'azione? – SaltProgrammer

+0

Il motivo per cui utilizzo FormCollection è perché il raccoglitore modello predefinito (utilizzato per ViewModel) non può associare un set di checkbox che ho sulla vista rispetto a una proprietà List che ho in un oggetto BankAccount all'interno dell'oggetto UserViewModel. Controlla il codice sorgente che ho appena aggiunto alla domanda. Per mappare correttamente quella proprietà nidificata profonda, la prendo direttamente da FormCollection. L'altro modo di non utilizzare l'oggetto FormCollection, che conosco, è la creazione di un raccoglitore modello personalizzato, ma non voglio renderlo più complicato di quello che è, o mi manca qualcosa? – SaltProgrammer

+1

Sì, basta creare una classe per gli altri valori desiderati con i tipi appropriati per le caselle di controllo. Se è possibile associarlo a FormCollection, dovrebbe essere in grado di associarlo a un tipo statico. Potresti anche estrarre materiale dall'oggetto Richiesta. –

0

Il modello di aggiornamento è fondamentalmente utilizzato per aggiornare nuovi valori nel modello esistente. non è necessario assegnare il valore in modo esplicito.

+0

Stai dicendo che non devo farlo ... vm.BA.StatesTraveledTo = statesCheckBoxes.Split (','). ToList (); ??? Se non devo farlo, qual è la sintassi che se volessi usare solo il metodo UpdateModel()? – SaltProgrammer