2010-11-16 4 views
3

J'ai un ViewModel comme ceci:Comment transférer des données ViewModel entre des requêtes POST dans ASP.NET MVC?

public class ProductEditModel 
{ 
    public string Name { get; set; } 
    public int CategoryId { get; set; } 
    public SelectList Categories { get; set; } 

    public ProductEditModel() 
    { 
     var categories = Database.GetCategories(); // made-up method 
     Categories = new SelectList(categories, "Key", "Value"); 
    } 
} 

J'ai deux méthodes de contrôleur qui utilise ce modèle:

public ActionResult Create() 
{ 
    var model = new ProductEditModel(); 
    return View(model); 
} 

[HttpPost] 
public ActionResult Create(ProductEditModel model) 
{ 
    if (ModelState.IsValid) 
    { 
     // convert the model to the actual entity 
     var product = Mapper.Map(model, new Product()); 
     Database.Save(product); 
     return View("Success"); 
    } 
    else 
    { 
     return View(model); // this is where it fails 
    } 
} 

La première fois que l'utilisateur va à la vue Create, ils sont présentés avec un liste des catégories. Cependant, s'ils échouent à la validation, la vue leur est renvoyée, sauf que cette fois la propriété Categories est null. Cela est compréhensible car le ModelBinder ne persiste pas Categories s'il ne figurait pas dans la demande POST. Ma question est, quelle est la meilleure façon de garder Categories persisté? Je peux faire quelque chose comme ceci:

[HttpPost] 
public ActionResult Create(ProductEditModel model) 
{ 
    if (ModelState.IsValid) 
    { 
     // convert the model to the actual entity 
     var product = Mapper.Map(model, new Product()); 
     Database.Save(product); 
     return View("Success"); 
    } 
    else 
    { 
     // manually populate Categories again if validation failed 
     model.Categories = new SelectList(categories, "Key", "Value"); 
     return View(model); // this is where it fails 
    } 
} 

Mais c'est une solution laide. Comment puis-je le conserver? Je ne peux pas utiliser un champ caché parce que c'est une collection.

Répondre

2

J'implémente généralement mes listes (pour les listes déroulantes) en tant que propriété readonly. Lorsque la vue obtient la valeur, la propriété est autonome sur ce dont elle a besoin pour renvoyer les valeurs.

public SelectList Categories 
{ 
    get 
    { 
     var categories = Database.GetCategories(); // made-up method 
     return new SelectList(categories, "Key", "Value"); 
    } 
} 

Si nécessaire, vous pouvez saisir l'élément sélectionné (à savoir la validation n'a pas) de la propriété contenant l'identifiant qui a été affiché et lié à l'instance de votre classe.

0

Dans mon cas, j'ai une classe BaseModel où je conserve toutes ces propriétés en tant qu'attributs de classe.

Comme dans l'exemple suivant:

public IEnumerable<SelectListItem> CountryList 
{ 
    get 
    { 
     return GetCountryList().Select(
      t => new SelectListItem { Text = t.Name, Value = Convert.ToString(t.CountryID) }); 
    } 
} 

GetCountryList() est une fonction qui demande un Singleton pour les données. Cela ne se produirait qu'une fois dans le cycle de vie de l'application

Une autre façon de faire cela, et si ces listes sont assez grandes, serait d'avoir une classe d'utilitaire statique avec la table de recherche qui retourne le SelectListItem.

Si vous avez besoin d'accéder à une liste qui change de temps en temps, n'utilisez simplement pas de classe Singleton.

+0

Donc, en d'autres termes, renseignez les listes manuellement? –

+0

Que voulez-vous dire par manuellement? – Lorenzo

+0

Oh whoops, je pensais que vous avez dit 'BaseController', pas' BaseModel'. –

2

Je voudrais utiliser le référentiel pour récupérer toutes les données nécessaires et ne pense pas que c'est une solution laide:

[HttpPost] 
public ActionResult Create(ProductEditModel model) 
{ 
    if (!ModelState.IsValid) 
    { 
     // manually populate Categories again if validation failed 
     model.Categories = Repository.GetCategories(); 
     return View(model); 
    } 

    // convert the model to the actual entity 
    var product = Mapper.Map(model, new Product()); 
    Database.Save(product); 

    // I would recommend you to redirect here 
    return RedirectToAction("Success"); 
} 

Pour refactorisons plus cela, je vous recommande de regarder l'excellente présentation Putting Your Controllers on a Diet vidéo par Jimmy Bogard.

+0

La raison pour laquelle je dis que c'est moche est parce qu'elle viole le principe de la responsabilité unique: le ViewModel devrait savoir comment obtenir les données qu'il doit envoyer à la vue. Si vous avez besoin de le configurer en externe, alors c'est juste un DTO. –

Questions connexes