66 votes

Quand utiliser TempData ou Session en ASP.Net MVC ?

J'essaie de me familiariser avec le cadre MVC, alors soyez indulgent avec moi.

Pour l'instant, la seule chose que j'utilise dans le magasin de session est le stockage de l'utilisateur actuellement connecté. Mon site web est simple. Pour cet exemple, considérons trois objets de domaine : Personne, Réunion et Fichier. Les utilisateurs peuvent se connecter et afficher le profil "réservé aux membres" d'une réunion et y ajouter des fichiers, ou afficher le "profil" public d'une réunion s'ils ne sont pas connectés.

Ainsi, à partir du profil privé de la réunion, avec un utilisateur connecté, j'ai un lien "ajouter des fichiers". Ce lien mène à FileContoller.Add(int meetingId). À partir de cette action, j'obtiens la réunion à laquelle l'utilisateur veut ajouter des fichiers en utilisant l'identifiant de la réunion, mais une fois le formulaire affiché, j'ai toujours besoin de savoir à quelle réunion l'utilisateur ajoute des fichiers. C'est là que se situe ma question : dois-je transmettre la réunion "en cours d'interaction avec" par le biais de TempData, ou l'ajouter au magasin de session ?

C'est ainsi que j'ai actuellement configuré l'action Ajouter, mais cela ne fonctionne pas :

    public ActionResult Add(int meetingId)
    {
        try
        {
            var meeting = _meetingsRepository.GetById(meetingId);
            ViewData.Model = meeting;
            TempData[TempDataKeys.CurrentMeeting] = meeting; /* add to tempdata here */
        }
        catch (Exception)
        {
            TempData[TempDataKeys.ErrorMessage] = "Unable to add files to this meeting.";
            return RedirectToRoute("MeetingsIndex");
        }

        return View();
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Add(FormCollection form)
    {
        var member = Session[SessionStateKeys.Member] as Member;
        var meeting = TempData[TempDataKeys.CurrentMeeting] as Meeting; /* meeting ends up null here */

        if (member == null)
        {
            TempData[TempDataKeys.ErrorMessage] = "You must be logged in to add files to an meeting.";
            return RedirectToRoute("LoginPage");
        }

        if (meeting == null) 
        {
            TempData[TempDataKeys.ErrorMessage] = "An error occurred. No meeting selected.";
            return RedirectToRoute("MeetingsIndex");
        }

            // add files to meeting

        TempData[TempDataKeys.Notification] = "Successfully added.";
        return RedirectToRoute("AddFiles", new {meetingId = meeting.MeetingId});
}

Edita:

En se basant sur la plupart des réponses, quelqu'un peut-il fournir des exemples sur le type de données (autres que les messages) qui devraient être stockées dans TempData ou dans Session ?

0 votes

De quel type est TempDataKeys, juste une classe ? Ou un enum ?

0 votes

@Anon343224user il est trop tard mais j'écris pour ceux qui se posent des questions comme vous et moi. Je me suis aussi posé la question et j'ai trouvé un usage similaire chez github.com/Macht59/StenoCryptor/blob/master/ il s'agit d'une classe statique qui contient des champs de type consts string.

0 votes

Note aux lecteurs modernes : TempData fonctionne différemment à partir de .NET Core par rapport à la façon dont il est décrit dans de nombreuses réponses ici. Voir ma réponse ici pour les détails.

95voto

Craig Stuntz Points 95965

TempData est une session, ils ne sont donc pas totalement différents. Toutefois, la distinction est facile à comprendre, car TempData est pour les redirections, et uniquement les redirections. . Ainsi, lorsque vous définissez un message dans TempData et que vous effectuez ensuite une redirection, vous utilisez correctement TempData.

Cependant, il est extrêmement dangereux d'utiliser la session pour toute forme de sécurité. La session et l'adhésion sont entièrement distinctes dans ASP.NET. Vous pouvez "voler" des sessions à d'autres utilisateurs. et oui, les gens attaquent les sites web de cette façon. Donc, si vous voulez arrêter sélectivement l'information d'un message selon qu'un utilisateur est connecté ou non, regardez à IsAuthenticated et si vous voulez afficher sélectivement des informations en fonction du type d'utilisateur connecté, vous utilisez une balise Fournisseur de rôles . Étant donné que les GET peuvent être mis en cache, l'option seulement Le moyen d'autoriser de manière sélective l'accès à une action dans un GET est l'attribut AuthorizeAttribute.

Mise à jour En réponse à votre question éditée : Vous avez déjà un bon exemple d'utilisation de TempData dans votre question, à savoir le renvoi d'un simple message d'erreur après l'échec d'un POST. Pour ce qui est de ce que debe être stockées dans Session (au-delà de "pas grand chose"), je considère simplement Session comme un cache spécifique à l'utilisateur. Comme le Cache non spécifique à l'utilisateur, vous ne devriez pas y mettre des informations sensibles à la sécurité. Mais c'est un bon endroit pour stocker des informations dont la recherche est relativement coûteuse. Par exemple, le nom complet de l'utilisateur est affiché sur notre Site.Master. Cette information est stockée dans une base de données et nous ne voulons pas l'interroger à chaque page que nous affichons. (Une installation de notre application est utilisée dans une seule entreprise, donc le nom complet d'un utilisateur n'est pas considéré comme "sensible à la sécurité"). Donc si vous pensez à Session comme à un cache qui varie en fonction d'un cookie que possède l'utilisateur, vous n'aurez pas tout à fait tort.

0 votes

Je n'ai pas besoin de rôles, tout le monde a le même accès une fois connecté. Je vais faire mes recherches sur IsAuthenticated, merci.

2 votes

Le mécanisme d'authentification n'est-il pas basé sur un cookie et ne peut-il pas être volé de la même manière ?

3 votes

@Ismail, oui, un cookie est impliqué (par défaut). Non, il ne peut pas être volé d'une manière similaire. L'authentification est conçue pour être sécurisée. La session ne l'est pas. Ce sont deux choses différentes.

17voto

tvanfosson Points 268301

Le fournisseur de données temporelles par défaut utilise la session. Il n'y a donc pas vraiment de différence, si ce n'est que vos données temporelles sont effacées à la fin de la prochaine requête. Vous devriez utiliser TempData lorsque les données ne doivent persister qu'entre deux requêtes, de préférence la seconde étant une redirection pour éviter les problèmes avec d'autres requêtes de l'utilisateur -- d'AJAX, par exemple -- supprimant les données accidentellement. Si les données doivent persister plus longtemps que cela, vous devez soit repeupler la TempData, soit utiliser directement la session.

1 votes

Je comprends cela. Je place l'objet "réunion" dans TempData avec la méthode GET, puis lorsque l'utilisateur poste le formulaire, je devrais pouvoir le récupérer à nouveau dans TempData, n'est-ce pas ?

3 votes

Non, vous ne pouvez pas compter. TempData ne sert qu'à rediriger. Si vous définissez TempData dans un GET, puis que votre page effectue un appel AJAX, puis que l'utilisateur effectue un POST, la TempData est parti.

1 votes

"Non vous ne pouvez pas compter." -> ""Non, vous ne pouvez pas compter là-dessus."" Voir le lien dans ma réponse pour plus d'informations sur TempData et les redirections.

4voto

womp Points 71924

"Ça ne marche pas" n'est pas très descriptif, mais laissez-moi vous faire quelques suggestions.

Sous le capot, TempData utilise Session pour stocker les valeurs. Il n'y a donc pas de grande différence en termes de mécanismes de stockage ou autres. Cependant, TempData ne dure que jusqu'à la réception de la prochaine demande.

Si l'utilisateur fait une requête ajax entre deux messages du formulaire, TempData disparaît. Toute requête, quelle qu'elle soit, efface TempData. Il n'est donc vraiment fiable que lorsque vous effectuez une redirection manuelle.

Pourquoi ne pouvez-vous pas simplement rendre l'ID de la réunion dans un champ caché de votre formulaire de vue ? Vous l'ajoutez déjà au modèle. Vous pouvez aussi l'ajouter à votre itinéraire en tant que paramètre.

0 votes

Il y a deux commentaires qui décrivent ce qui ne fonctionne pas pour moi. Je suppose que je pourrais passer l'objet et ne pas avoir à le récupérer à nouveau dans la base de données, mais maintenant que j'y pense, cela ajouterait probablement beaucoup de problèmes de concurrence.

0voto

RedFilter Points 84190

Je préfère conserver ce type de données dans la page elle-même. Rendre meetingID comme une entrée cachée, pour qu'il soit soumis au contrôleur. Le contrôleur qui gère le message peut alors renvoyer l'ID de la réunion à la vue qui sera rendue, de sorte que l'ID de la réunion est transmis aussi longtemps que vous en avez besoin.

C'est un peu comme la différence entre stocker une valeur dans une variable globale avant d'appeler une méthode qui l'utilisera, et passer la valeur directement à la méthode.

0voto

queen3 Points 8810

Je suggère la solution de MvcContrib : http://jonkruger.com/blog/2009/04/06/aspnet-mvc-pass-parameters-when-redirecting-from-one-action-to-another/

Si vous ne voulez pas de MvcContrib complet, la solution est seulement 1 méthode + 1 classe que vous pouvez facilement récupérer des sources de MvcContrib.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X