ユーザーが特定のリクエストを行って、Webサイト内の複数のWebページを閲覧できるWebアプリケーションを作成しています。ユーザーが入力するすべての情報は、作成したオブジェクトに保存されます。問題は、このオブジェクトにWebサイトの任意の部分からアクセスする必要があり、これを実現する最善の方法が本当にわからないことです。 1つの解決策はセッション変数を使用することですが、asp .net MVCでそれらを使用する方法がわかりません。そして、セッション変数をどこで宣言しますか?他の方法はありますか?
本当に物事がセッション状態に属しているかどうかを考えたいと思うでしょう。これは私自身が時々していることであり、全体に対するニースの強く型付けされたアプローチですが、セッションコンテキストに物を置くときには注意が必要です。あるユーザーに属しているという理由だけですべてがそこにあるべきではありません。
global.asaxでOnSessionStartイベントをフックします
void OnSessionStart(...)
{
HttpContext.Current.Session.Add("__MySessionObject", new MySessionObject());
}
HttpContext.Currentプロパティ!= nullのコード内のどこからでも、そのオブジェクトを取得できます。これを拡張メソッドで行います。
public static MySessionObject GetMySessionObject(this HttpContext current)
{
return current != null ? (MySessionObject)current.Session["__MySessionObject"] : null;
}
この方法でコードでできる
void OnLoad(...)
{
var sessionObj = HttpContext.Current.GetMySessionObject();
// do something with 'sessionObj'
}
ここでの答えは正しいですが、ASP.NET MVC 3アプリに実装するのに苦労しました。コントローラーのSessionオブジェクトにアクセスしたかったのに、「オブジェクトエラーのインスタンスに設定されていないインスタンス」を取得し続けた理由がわかりませんでした。私が気づいたのは、次の操作を行ってセッションにアクセスしようとしたときにコントローラーでエラーが発生し続けたことです。これは、this.HttpContextがControllerオブジェクトの一部であるためです。
this.Session["blah"]
// or
this.HttpContext.Session["blah"]
ただし、System.Web名前空間の一部であるHttpContextが欲しかったのは、これが上記の回答でGlobal.asax.csでの使用が提案されているためです。そのため、次のことを明示的に行う必要がありました。
System.Web.HttpContext.Current.Session["blah"]
これは私を助けてくれました。この辺りですが、誰かの助けになることを願っています!
場所について「HTTPContext.Current.Session」が表示されるのが嫌いなので、シングルトンパターンを使用してセッション変数にアクセスします。これにより、強く型付けされたデータのバッグに簡単にアクセスできます。
[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; }
// ...
その後、どこからでもデータにアクセスできます。
SessionSingleton.Current.SessionVariable = "Hello, World!";
Asp.net mvcを使用している場合、セッションにアクセスする簡単な方法を次に示します。
コントローラーから:
{Controller}.ControllerContext.HttpContext.Session["{name}"]
ビューから:
<%=Session["{name}"] %>
これは間違いなくセッション変数にアクセスする最良の方法ではありませんが、直接的な方法です。したがって、慎重に(できればラピッドプロトタイピング中に)使用し、適切になったらWrapper/ContainerとOnSessionStartを使用してください。
HTH
まあ、私見..
#1に関して、私はセッションオブジェクトが表すものにアクセスするプロパティを持つ強く型付けされたマスタービューを持っています....私のインスタンスでは、強く型付けされたマスタービューはジェネリックであり、強く型付けされたビューページに関して柔軟性があります
ViewMasterPage<AdminViewModel>
AdminViewModel
{
SomeImportantObjectThatWasInSession ImportantObject
}
AdminViewModel<TModel> : AdminViewModel where TModel : class
{
TModel Content
}
その後...
ViewPage<AdminViewModel<U>>
それを行うには3つの方法があります。
HttpContext.Current.Session
に直接アクセスできます
HttpContextBase
をモックできます
HttpContextBase
の拡張メソッドを作成します
私は3番目の方法を好む。
BaseControllerのHttpContextセッションメソッドの取得/設定とHttpContextBaseのモックによるGet/Setメソッドの作成
Asp.net mvcについては知りませんが、これは通常の.net Webサイトですべきことです。 asp.net mvcでも機能するはずです。
YourSessionClass obj=Session["key"] as YourSessionClass;
if(obj==null){
obj=new YourSessionClass();
Session["key"]=obj;
}
簡単にアクセスできるように、メソッド内にこれを配置します。 HTH
みんなからのすばらしい答えですが、私は常にセッションに依存することに対して警告します。すばやく簡単に実行でき、もちろん動作しますが、すべての状況で素晴らしいとは限りません。
たとえば、ホスティングでセッションの使用が許可されていないシナリオに遭遇した場合、Webファームにいる場合、または共有SharePointアプリケーションの例です。
別のソリューションが必要な場合は、 IOC Container などの Castle Windsor を使用して、プロバイダークラスをラッパーとして作成し、クラスの1つのインスタンスを使用して、要求に応じて、リクエストまたはセッションのライフスタイルごとに。
IOCは、毎回同じインスタンスが返されるようにします。
もっと複雑です。単純なソリューションが必要な場合は、セッションを使用するだけです。
以下に、興味のない実装例をいくつか示します。
このメソッドを使用すると、次の行に沿ってプロバイダークラスを作成できます。
public class CustomClassProvider : ICustomClassProvider
{
public CustomClassProvider(CustomClass customClass)
{
CustomClass = customClass;
}
public string CustomClass { get; private set; }
}
そして、次のように登録します:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<ICustomClassProvider>().UsingFactoryMethod(
() => new CustomClassProvider(new CustomClass())).LifestylePerWebRequest());
}
セッションにアクセスする私の方法は、さまざまなフィールド名とそのタイプをカプセル化するヘルパークラスを作成することです。この例が役立つことを願っています:
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; }
}
}
}
ViewModelBaseをすべてのモデルの基本クラスとして使用できます。このクラスはセッションからのデータのプルを処理します
class ViewModelBase
{
public User CurrentUser
{
get { return System.Web.HttpContext.Current.Session["user"] as User };
set
{
System.Web.HttpContext.Current.Session["user"]=value;
}
}
}
セッションデータを処理するためにHttpContextBaseに拡張メソッドを書くことができます
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;
}
コントローラで以下のようにこれを使用してください
User userData = HttpContext.FromSession<User>("userdata",()=> { return user object from service/db });
2番目の引数はオプションであり、セッションに値が存在しない場合にそのキーのセッションデータを埋めるために使用されます。