Il modo più comune di ricostruire una entity in una action di POST in ASP.NET Core MVC è quello di indicarla come parametro del metodo e lasciare al Model Binder il compito di popolarla:
public async Task<IActionResult> Edit(string id, Person person) { // .. altro codice qui .. }
Questo approccio, tuttavia, ha il pesante limite di creare ogni volta una nuova istanza di Person, che poi - se usiamo Entity Framework, per esempio - dobbiamo in qualche modo riagganciare al Context e marcare come modificata:
_context.Update(person); await _context.SaveChangesAsync();
Questo codice funziona benissimo con entità semplici, ma se l'oggetto Person è più complesso, e per esempio non tutte le proprietà vengono esposte sulla pagina che stiamo creando, rischiamo che queste ultime vengano tutte resettate al loro valore di default.
La ragione, lo ripetiamo, è molto semplice: Person viene ricreata dal model binder da zero, e pertanto conterrà solo le proprietà che effettivamente sono pervenute come parte della request in POST.
Un'alternativa molto valida, invece, è quella di utilizzare TryUpdateModelAsync: a differenza del precendente caso, infatti, questo metodo accetta come parametro un oggetto esistente, che magari abbiamo preventivamente recuperato dal database. In buona sostanza, possiamo scrivere la nostra action di POST come segue:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Edit(int id, Person person) { if (id != person.Id) { return NotFound(); } var original = await _context.Person.SingleAsync(x => x.Id == id); if (ModelState.IsValid && await this.TryUpdateModelAsync(original)) { await _context.SaveChangesAsync(); return RedirectToAction("Index"); } return View(person); }
Il codice in alto, dopo aver recuperato la entity originale dal database (incluse le proprietà non direttamente esposte in pagina), invoca TryUpdateModelAsync passando la entity stessa come parametro. Questo metodo aggiornerà le proprietà provenienti dalla request, lasciando inalterate le altre.
Successivamente, siccome la entity è già collegata al DbContext grazie al metodo SingleAsync, non dobbiamo far altro che invocare SaveChangesAsync per salvare le modifiche.
TryUpdateModelAsync supporta anche il whitelist delle proprietà, analogamente all'attributo Bind, utilizzando la sintassi basata su lambda expression seguente:
this.TryUpdateModelAsync(original, string.Empty, x => x.Name, x => x.Email)
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Eseguire una GroupBy per entity in Entity Framework
Generare token per autenicarsi sulle API di GitHub
Personalizzare l'errore del rate limiting middleware in ASP.NET Core
Utilizzare QuickGrid di Blazor con Entity Framework
Aggiungere interattività lato server in Blazor 8
Specificare il versioning nel path degli URL in ASP.NET Web API
Effettuare il deploy di immagini solo da container registry approvati in Kubernetes
Evitare la script injection nelle GitHub Actions
Utilizzare l'operatore GroupBy come ultima istruzione di una query LINQ in Entity Framework
Come migrare da una form non tipizzata a una form tipizzata in Angular
Utilizzare il trigger SQL con le Azure Function
I più letti di oggi
- Utilizzare Docker Compose con Azure App Service
- Utilizzare QuickGrid di Blazor con Entity Framework
- Modernizzare le applicazioni WPF e Windows Forms con Blazor
- ASP 3 per esempi
- annunciato #netstandard 2.1. .NET Core lo supporterà a partire da #netcore3, così come le prossime versione di #xamarin, #mono e #unity.il supporto per #netfx 4.8, invece, non ci sarà. https://aspit.co/bq2