2009-08-26 4 views
2

Dans son magnifique livre MVC, Steven Sanderson donne un exemple de classeur de modèle personnalisé qui définit et récupère une variable de session, cachant l'élément de stockage de données du contrôleur. J'essaie d'étendre ceci pour répondre à un scénario assez courant: je stocke un objet Utilisateur dans la session et le rend disponible à chaque méthode d'action en tant que paramètre. La classe de Sanderson fonctionnait bien quand les détails de l'utilisateur ne changeaient pas, mais maintenant je dois laisser l'utilisateur éditer leurs détails et sauvegarder l'objet modifié dans la session. Mon problème est que je ne peux pas comprendre comment distinguer un GET d'un POST autrement qu'en vérifiant le nombre de clés dans bindingContext.ValueProvider.Keys, et cela semble si mauvais que je suis sûr que je suis malentendu quelque chose.Extension de mvc ModelBinder personnalisé de Sanderson pour un objet stocké en session

Quelqu'un peut-il me diriger dans la bonne direction? Fondamentalement, toutes les actions doivent avoir accès à l'utilisateur actuel, et l'action UpdateMyDetails doit mettre à jour le même objet, toutes sauvegardées par la session. Voici mon code ...

public class CurrentUserModelBinder : IModelBinder 
{ 
    private const string userSessionKey = "_currentuser"; 
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { 
     var user = controllerContext.HttpContext.Session[userSessionKey]; 
     if (user == null) 
      throw new NullReferenceException("The CurrentUser was requested from the CurrentUserModelBinder but no IUser was present in the Session."); 

     var currentUser = (CCL.IUser)user; 
     if (bindingContext.ValueProvider.Keys.Count > 3) 
     { 

      var firstName = GetValue<string>(bindingContext, "FirstName"); 
      if (string.IsNullOrEmpty(firstName)) 
       bindingContext.ModelState.AddModelError("FirstName", "Please tell us your first name."); 
      else 
       currentUser.FirstName = firstName; 

      var lastName = GetValue<string>(bindingContext, "LastName"); 
      if (string.IsNullOrEmpty(lastName)) 
       bindingContext.ModelState.AddModelError("LastName", "Please tell us your last name."); 
      else 
       currentUser.LastName = lastName; 

      if (bindingContext.ModelState.IsValid) 
       controllerContext.HttpContext.Session[userSessionKey] = currentUser; 

     } 
     return currentUser; 
    } 
    private T GetValue<T>(ModelBindingContext bindingContext, string key) 
    { 
     ValueProviderResult valueResult; 
     bindingContext.ValueProvider.TryGetValue(key, out valueResult); 
     bindingContext.ModelState.SetModelValue(key, valueResult); 
     return (T)valueResult.ConvertTo(typeof(T)); 
    } 
} 
+0

Avez-vous trouvé la réponse d'autre où? Je dois faire la même chose. – longday

+0

Je suis aussi allé dans la voie proposée par Steven Sanderson, mais maintenant je lis des opinions mitigées sur l'accès aux données dans les classeurs personnalisés. Je n'arrive pas à faire fonctionner mon injection de dépendance dans un classeur de modèle personnalisé. Apparemment, vous ne pouvez pas avoir IoC dans les classeurs de modèles personnalisés ... – autonomatt

Répondre

1

Essayez héritant de DefaultModelBinder au lieu de IModelBinder, vous pouvez appeler base.BindModel pour remplir bindingContext.Model pour mvc 1.0 ou 2.0 bindingContext.ModelMetadata.Model pour mvc

Pour déclenche bindingContext.Model pour remplir, appelez UpdateModel sur le contrôleur.

Vous devez ajouter la déclaration du livre de retour dans

if(bindingContext.Model != null) 
throw new InvalidOperationException("Cannot update instances"); 

mais changer pour remplir le modèle et enregistrer la session.

if(bindingContext.Model != null) 
{ 
    base.BindModel(controllerContext, bindingContext); 
    //save bindingContext.Model to session, overwriting current. 
    return bindingContext.Model 
} 
Questions connexes