Sitzungsvariablen in ASP.NET MVC

169

Ich schreibe eine Webanwendung, mit der ein Benutzer zu mehreren Webseiten innerhalb der Website navigieren kann, um bestimmte Anforderungen zu erfüllen. Alle Informationen, die der Benutzer eingibt, werden in einem von mir erstellten Objekt gespeichert. Das Problem ist, dass auf dieses Objekt von einem beliebigen Teil der Website aus zugegriffen werden muss und ich nicht wirklich weiß, wie dies am besten erreicht werden kann. Ich weiß, dass eine Lösung darin besteht, Sitzungsvariablen zu verwenden, aber ich weiß nicht, wie ich sie in asp .net MVC verwenden soll. Und wo würde ich eine Sitzungsvariable deklarieren? Gibt es einen anderen Weg?

Draco
quelle
3
Sie mischen die Website- und Webanwendungskonzepte ... sie sind nicht dasselbe.
Adripanico
1
Klingt nach einer Notwendigkeit für eine Datenbank
Coops
1
Mögliches Duplikat von Wie werden Sitzungen in einer ASP.NET MVC 4-Anwendung verwendet?
Michael Freidgeim

Antworten:

123

Ich würde denken, dass Sie darüber nachdenken möchten, ob die Dinge wirklich in einen Sitzungszustand gehören. Dies ist etwas, was ich hin und wieder mache und es ist eine nette, stark typisierte Herangehensweise an das Ganze, aber Sie sollten vorsichtig sein, wenn Sie Dinge in den Sitzungskontext stellen. Nicht alles sollte da sein, nur weil es einem Benutzer gehört.

In global.asax wird das OnSessionStart-Ereignis verknüpft

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

Von überall im Code, wo die Eigenschaft HttpContext.Current! = Null ist, können Sie dieses Objekt abrufen. Ich mache das mit einer Erweiterungsmethode.

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

Auf diese Weise können Sie in Code

void OnLoad(...)
{
    var sessionObj = HttpContext.Current.GetMySessionObject();
    // do something with 'sessionObj'
}
John Leidegren
quelle
32
Wenn ASP MVC verwendet wird, ist es vorzuziehen, nicht das eigentliche Sitzungsobjekt aus HttpContext.Current.Session zu verwenden, sondern die neue HttpSessionStateWrapper & HttpSessionStateBase aus System.Web.Abstractions.dll zu verwenden und dann eine Factory oder DI zu verwenden, um die Sitzung abzurufen.
Paul
6
Wie ordnen Sie der Sitzungsvariablen etwas zu? (im Gegensatz zu nur Zugriff)
Raklos
31
Informationen zu Personen, die herausfinden möchten, was das "OnSessionStart" -Ereignis ist und wie Sie es "einbinden", finden Sie unter stackoverflow.com/questions/1531125/…
Cephron,
5
@Paul Können Sie ein Beispiel geben? Ich kann anscheinend keine Beispiele für die Verwendung von HttpSessionStateWrapper finden.
Joseph Woodward
4
@AjayKelkar Dieser Kommentarthread schlug vor "Wenn ASP MVC verwendet wird, ist es vorzuziehen, nicht das eigentliche Sitzungsobjekt von HttpContext.Current.Session zu verwenden, sondern die neue HttpSessionStateWrapper & HttpSessionStateBase", was Ihre Antworten nicht besser vorschlägt
Coops
48

Die Antwort hier ist richtig, ich hatte jedoch Schwierigkeiten, sie in einer ASP.NET MVC 3-App zu implementieren. Ich wollte auf ein Sitzungsobjekt in einem Controller zugreifen und konnte nicht herausfinden, warum ich immer wieder die Meldung "Instanz nicht auf eine Instanz eines Objektfehlers festgelegt" erhielt. Was mir aufgefallen ist, ist, dass in einem Controller, als ich versuchte, wie folgt auf die Sitzung zuzugreifen, dieser Fehler immer wieder auftrat. Dies liegt an der Tatsache, dass this.HttpContext Teil des Controller-Objekts ist.

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

Was ich jedoch wollte, war der HttpContext, der Teil des System.Web-Namespace ist, da dies der ist, den die obige Antwort in Global.asax.cs vorschlägt. Also musste ich explizit Folgendes tun:

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

Das hat mir geholfen, ich bin mir nicht sicher, ob ich etwas getan habe, das hier nicht MO ist, aber ich hoffe, es hilft jemandem!

Tomasz Iniewicz
quelle
6
System.Web.HttpContext.Current.Session ["blah"] = Wert
Tomasz Iniewicz
21

Da ich "HTTPContext.Current.Session" nicht gerne über den Ort sehe, verwende ich ein Singleton-Muster, um auf Sitzungsvariablen zuzugreifen. Dadurch können Sie leicht auf stark typisierte Datenmengen zugreifen.

[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; }

    // ...

dann können Sie von überall auf Ihre Daten zugreifen:

SessionSingleton.Current.SessionVariable = "Hello, World!";
Dead.Rabit
quelle
2
Diese Klasse hat also zwei Verantwortlichkeiten: eine einzelne Instanz verwalten und Variablen speichern ... Ich würde einen IOC-Container verwenden, um einen Singleton zu haben.
Jowen
1
Wenn Sie bereits ein Setup haben, würde ich wahrscheinlich auch einen vollwertigen, injizierbaren Sitzungsdienst anbieten. Konsistenzen sind jedoch wahrscheinlich der größte Vorteil. Ich würde diesen Code eher für kleine Webapps mit Featuresets verwenden. Webwizards, wenn Sie so wollen.
Dead.Rabit
14

Wenn Sie asp.net mvc verwenden, haben Sie hier eine einfache Möglichkeit, auf die Sitzung zuzugreifen.

Von einem Controller:

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

Aus einer Sicht:

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

Dies ist definitiv nicht der beste Weg, um auf Ihre Sitzungsvariablen zuzugreifen, aber es ist ein direkter Weg. Verwenden Sie es daher mit Vorsicht (vorzugsweise während des Rapid Prototyping) und verwenden Sie einen Wrapper / Container und OnSessionStart, wenn es angebracht ist.

HTH

robertz
quelle
2
hm .. Was ist der beste Weg? Ich sollte Daten von der Sitzung auf dem Controller an ViewState übergeben, nicht wahr?
RredCat
2
und könnten Sie die Einschränkungen dieser Methode erklären?
RredCat
1
Ich denke, er meinte, dass es am besten ist, Lese- / Schreibmethoden zu haben. Abhängig von der Parallelität / Thread-Verwendung benötigen Sie möglicherweise auch Sperren für diese Lese- / Schreibmethoden, um eine Race-Bedingung zu vermeiden.
DeepSpace101
13

Nun, IMHO ..

  1. Verweisen Sie niemals auf eine Sitzung in Ihrer Ansicht / Masterseite
  2. Minimieren Sie Ihre Sitzungsnutzung. MVC stellt hierfür TempData obj zur Verfügung, bei dem es sich im Grunde um eine Sitzung handelt, die für eine einzelne Reise zum Server ausgeführt wird.

In Bezug auf # 1 habe ich eine stark typisierte Master-Ansicht, die eine Eigenschaft hat, auf alles zuzugreifen, was das Session-Objekt darstellt. In meinem Fall ist die stark typisierte Master-Ansicht generisch, was mir eine gewisse Flexibilität in Bezug auf stark typisierte Ansichtsseiten gibt

ViewMasterPage<AdminViewModel>

AdminViewModel
{
    SomeImportantObjectThatWasInSession ImportantObject
}

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

und dann...

ViewPage<AdminViewModel<U>>
E Rolnicki
quelle
7

Ich weiß zwar nichts über asp.net mvc, aber das sollten wir auf einer normalen .net-Website tun. Es sollte auch für asp.net mvc funktionieren.

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

Sie würden dies in eine Methode für den einfachen Zugriff einfügen. HTH

Punkt net
quelle
7

Meine Art, auf Sitzungen zuzugreifen, besteht darin, eine Hilfsklasse zu schreiben, die die verschiedenen Feldnamen und ihre Typen kapselt. Ich hoffe dieses Beispiel hilft:

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; }
        }

    }
}
Daniel
quelle
Ich mag Ihre Antwort ... könnten Sie näher erläutern, was los ist ... und warum dies ein besserer Ansatz ist als die anderen Antworten in diesem Thread.
Chef_Code
6

Tolle Antworten von den Jungs, aber ich möchte Sie davor warnen, sich immer auf die Sitzung zu verlassen. Dies ist schnell und einfach und würde natürlich funktionieren, wäre aber nicht unter allen Umständen großartig.

Zum Beispiel, wenn Sie auf ein Szenario stoßen, in dem Ihr Hosting die Verwendung von Sitzungen nicht zulässt, oder wenn Sie sich in einer Webfarm befinden oder im Beispiel einer freigegebenen SharePoint-Anwendung.

Wenn Sie eine andere Lösung wünschen, können Sie einen IOC-Container wie Castle Windsor verwenden , eine Provider-Klasse als Wrapper erstellen und dann je nach Ihren Anforderungen eine Instanz Ihrer Klasse unter Verwendung des Lebensstils pro Anforderung oder Sitzung beibehalten.

Das IOC würde sicherstellen, dass jedes Mal dieselbe Instanz zurückgegeben wird.

Komplizierter ja, wenn Sie eine einfache Lösung benötigen, verwenden Sie einfach die Sitzung.

Hier sind einige Implementierungsbeispiele aus Interesse.

Mit dieser Methode können Sie eine Anbieterklasse erstellen, die wie folgt aussieht:

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

    public string CustomClass { get; private set; }
}

Und registrieren Sie es so etwas wie:

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

Sie können ViewModelBase als Basisklasse für alle Modelle verwenden. Diese Klasse kümmert sich um das Abrufen von Daten aus der Sitzung

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

Sie können eine Erweiterungsmethode in HttpContextBase schreiben, um mit Sitzungsdaten umzugehen

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;
}

Verwenden Sie dies wie unten in der Steuerung

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

Das zweite Argument ist optional. Es wird verwendet, um Sitzungsdaten für diesen Schlüssel zu füllen, wenn in der Sitzung kein Wert vorhanden ist.

Ajay Kelkar
quelle