web-dev-qa-db-fra.com

Variables de session dans ASP.NET MVC

J'écris une application Web qui permettra à un utilisateur d'accéder à plusieurs pages Web du site Web en faisant certaines demandes. Toutes les informations saisies par l'utilisateur seront stockées dans un objet que j'ai créé. Le problème est que j'ai besoin que cet objet soit accessible à partir de n'importe quelle partie du site et je ne connais pas vraiment le meilleur moyen d'y parvenir. Je sais qu'une solution consiste à utiliser des variables de session, mais je ne sais pas comment les utiliser dans asp .net MVC. Et où devrais-je déclarer une variable de session? Est-ce qu'il y a un autre moyen?

167
Draco

Je pense que vous aurez envie de réfléchir si les choses doivent vraiment appartenir à un état de session. C’est quelque chose que je me trouve de temps en temps et c’est une approche très typée de Nice, mais vous devez faire attention lorsque vous placez les choses dans le contexte de la session. Tout ne devrait pas être là simplement parce qu'il appartient à un utilisateur.

dans global.asax accrocher l'événement OnSessionStart

void OnSessionStart(...)
{
    HttpContext.Current.Session.Add("__MySessionObject", new MySessionObject());
}

De n'importe où dans le code où la propriété HttpContext.Current! = Null, vous pouvez récupérer cet objet. Je fais cela avec une méthode d'extension.

public static MySessionObject GetMySessionObject(this HttpContext current)
{
    return current != null ? (MySessionObject)current.Session["__MySessionObject"] : null;
}

De cette façon, vous pouvez dans le code

void OnLoad(...)
{
    var sessionObj = HttpContext.Current.GetMySessionObject();
    // do something with 'sessionObj'
}
123
John Leidegren

La réponse est correcte, mais j’ai eu du mal à l’implémenter dans une application ASP.NET MVC 3. Je voulais accéder à un objet Session dans un contrôleur et je ne pouvais pas comprendre pourquoi je continuais à obtenir une "instance non définie sur une instance d'erreur d'objet". Ce que j'ai remarqué, c'est que dans un contrôleur, lorsque j'ai essayé d'accéder à la session en procédant comme suit, j'ai continué à obtenir cette erreur. Cela est dû au fait que this.HttpContext fait partie de l'objet Controller.

this.Session["blah"]
// or
this.HttpContext.Session["blah"]

Cependant, ce que je voulais, c’était le HttpContext qui fait partie de l’espace de noms System.Web, car c’est celui-ci que la réponse ci-dessus suggère d’utiliser dans Global.asax.cs. J'ai donc dû faire explicitement ce qui suit:

System.Web.HttpContext.Current.Session["blah"]

cela m'a aidé, pas sûr si j'ai fait quelque chose qui n'est pas M.O. par ici, mais j'espère que ça aide quelqu'un!

46
Tomasz Iniewicz

Parce que je n'aime pas voir "HTTPContext.Current.Session" à propos de l'endroit, j'utilise un modèle singleton pour accéder aux variables de session. Il est ainsi facile d'accéder à un sac de données fortement typé.

[Serializable]
public sealed class SessionSingleton
{
    #region Singleton

    private const string SESSION_SINGLETON_NAME = "Singleton_502E69E5-668B-E011-951F-00155DF26207";

    private SessionSingleton()
    {

    }

    public static SessionSingleton Current
    {
        get
        {
            if ( HttpContext.Current.Session[SESSION_SINGLETON_NAME] == null )
            {
                HttpContext.Current.Session[SESSION_SINGLETON_NAME] = new SessionSingleton();
            }

            return HttpContext.Current.Session[SESSION_SINGLETON_NAME] as SessionSingleton;
        }
    }

    #endregion

    public string SessionVariable { get; set; }
    public string SessionVariable2 { get; set; }

    // ...

alors vous pouvez accéder à vos données de n'importe où:

SessionSingleton.Current.SessionVariable = "Hello, World!";
21
Dead.Rabit

Si vous utilisez asp.net mvc, voici un moyen simple d'accéder à la session.

D'un contrôleur:

{Controller}.ControllerContext.HttpContext.Session["{name}"]

D'un point de vue:

<%=Session["{name}"] %>

Ce n'est certainement pas la meilleure façon d'accéder à vos variables de session, mais c'est un itinéraire direct. Utilisez-le donc avec prudence (de préférence lors du prototypage rapide) et utilisez un Wrapper/Container et OnSessionStart quand cela devient approprié.

HTH

14
robertz

Eh bien, à mon humble avis ..

  1. ne faites jamais référence à une session dans votre vue/page maître
  2. minimisez votre utilisation de la session. MVC fournit TempData obj pour cela, qui est essentiellement une session qui vit pour un seul voyage sur le serveur.

En ce qui concerne le point n ° 1, j'ai une vue principale fortement typée qui a une propriété permettant d'accéder à tout ce que l'objet Session représente ....

ViewMasterPage<AdminViewModel>

AdminViewModel
{
    SomeImportantObjectThatWasInSession ImportantObject
}

AdminViewModel<TModel> : AdminViewModel where TModel : class
{
   TModel Content
}

puis...

ViewPage<AdminViewModel<U>>
13
E Rolnicki

Il y a 3 façons de le faire.

  1. Vous pouvez accéder directement à HttpContext.Current.Session

  2. Vous pouvez vous moquer de HttpContextBase

  3. Créer une méthode d'extension pour HttpContextBase

Je préfère la 3ème voie. Ce lien est une bonne référence.

Méthodes de session Get/Set HttpContext dans BaseController vs Mocking de HttpContextBase pour créer des méthodes Get/Set

7
Mangesh Pimpalkar

Bien que je ne connaisse pas asp.net mvc, mais c’est ce que nous devrions faire dans un site Web .net normal. Cela devrait également fonctionner pour asp.net mvc.

YourSessionClass obj=Session["key"] as YourSessionClass;
if(obj==null){
obj=new YourSessionClass();
Session["key"]=obj;
}

Vous mettriez cela dans une méthode pour un accès facile. HTH

7
DotNET

Excellentes réponses des gars mais je vous déconseille de toujours compter sur la session. C'est rapide et facile à faire, et bien sûr, cela fonctionnerait mais ne serait pas génial dans toutes les circonstances.

Par exemple, si vous rencontrez un scénario dans lequel votre hébergement n'autorise pas l'utilisation de session, ou si vous êtes sur une batterie de serveurs Web, ou dans l'exemple d'une application SharePoint partagée.

Si vous voulez une solution différente, vous pouvez utiliser un conteneur IOC tel que Castle Windsor , créer une classe fournisseur en tant que wrapper, puis conserver une instance de votre classe à l'aide de la commande selon votre demande ou votre style de vie en fonction de vos besoins.

Le IOC garantit que la même instance est renvoyée à chaque fois.

Plus compliqué oui, si vous avez besoin d’une solution simple, utilisez simplement la session.

Voici quelques exemples d'implémentation ci-dessous par intérêt.

En utilisant cette méthode, vous pouvez créer une classe de fournisseur du type:

public class CustomClassProvider : ICustomClassProvider
{
    public CustomClassProvider(CustomClass customClass)
    { 
        CustomClass = customClass;
    }

    public string CustomClass { get; private set; }
}

Et enregistrez-le quelque chose comme:

public void Install(IWindsorContainer container, IConfigurationStore store)
{
    container.Register(
            Component.For<ICustomClassProvider>().UsingFactoryMethod(
                () => new CustomClassProvider(new CustomClass())).LifestylePerWebRequest());
    }
6
shenku

Ma façon d’accéder aux sessions consiste à écrire une classe d’aide qui encapsule les différents noms de champs et leurs types. J'espère que cet exemple aide:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.SessionState;

namespace dmkp
{
    /// <summary>
    /// Encapsulates the session state
    /// </summary>
    public sealed class LoginInfo
    {
        private HttpSessionState _session;
        public LoginInfo(HttpSessionState session)
        {
            this._session = session;
        }

        public string Username
        {
            get { return (this._session["Username"] ?? string.Empty).ToString(); }
            set { this._session["Username"] = value; }
        }

        public string FullName
        {
            get { return (this._session["FullName"] ?? string.Empty).ToString(); }
            set { this._session["FullName"] = value; }
        }
        public int ID
        {
            get { return Convert.ToInt32((this._session["UID"] ?? -1)); }
            set { this._session["UID"] = value; }
        }

        public UserAccess AccessLevel
        {
            get { return (UserAccess)(this._session["AccessLevel"]); }
            set { this._session["AccessLevel"] = value; }
        }

    }
}
5
Daniel

Vous pouvez utiliser ViewModelBase comme classe de base pour tous les modèles. Cette classe se chargera d'extraire les données de la session.

class ViewModelBase 
{
  public User CurrentUser 
  {
     get { return System.Web.HttpContext.Current.Session["user"] as User };
     set 
     {
        System.Web.HttpContext.Current.Session["user"]=value; 
     }
  }
}

Vous pouvez écrire une méthode d'extention sur HttpContextBase pour gérer les données de session.

T FromSession<T>(this HttpContextBase context ,string key,Action<T> getFromSource=null) 
{
    if(context.Session[key]!=null) 
    {
        return (T) context.Session[key];
    }
  else if(getFromSource!=null) 
  {
    var value = getFromSource();
   context.Session[key]=value; 
   return value; 
   }
  else 
  return null;
}

Utilisez ceci comme ci-dessous dans le contrôleur

User userData = HttpContext.FromSession<User>("userdata",()=> { return user object from service/db  }); 

Le deuxième argument est facultatif, il sera utilisé pour remplir les données de session pour cette clé lorsque aucune valeur n'est présente dans la session.

4
Ajay Kelkar