如何使 MVC 5 会话中的 Singleton 特定?
How to make Singleton in MVC 5 session specific?
我的 MVC 应用程序中有一个单例模型 class 以确定登录的用户是否具有 authorization/admin(基于某些 AD 组的成员资格)。此模型 class 需要是单例,以便用户的访问权限可以在首次登录时建立一次并在整个会话期间使用:
public sealed class ApplicationUser
{
// SINGLETON IMPLEMENTATION
// from http://csharpindepth.com/articles/general/singleton.aspx#lazy
public static ApplicationUser CurrentUser { get { return lazy.Value; } }
private static readonly Lazy<ApplicationUser> lazy =
new Lazy<ApplicationUser>(() => new ApplicationUser());
private ApplicationUser()
{
GetUserDetails(); // determine if user is authorized/admin
}
// Public members
public string Name { get { return name; } }
public bool IsAuthorized { get { return isAuthorized; } }
public bool IsAdmin { get { return isAdmin; } }
// Private members
// more code
}
Singleton 在我的 EntryPointController 中首次实例化,所有其他控制器都派生自:
public abstract class EntryPointController : Controller
{
// this is where the ApplicationUser class in instantiated for the first time
protected ApplicationUser currentUser = ApplicationUser.CurrentUser;
// more code
// all other controllers derive from this
}
这个模式允许我在我的应用程序中使用 ApplicationUser.CurrentUser.Name
或 ApplicationUser.CurrentUser.IsAuthorized
等。
然而,问题是这样的:
Singleton 包含在启动 Web 应用程序时登录的第一个用户的引用!所有后续登录的用户都看到最早登录用户的名字!
如何使 Singleton 会话具体化?
我认为您正在寻找 Multiton 模式,其中每个实例都链接到一个键。
这里的例子
http://designpatternsindotnet.blogspot.ie/2012/07/multiton.html
using System.Collections.Generic;
using System.Linq;
namespace DesignPatterns
{
public class Multiton
{
//read-only dictionary to track multitons
private static IDictionary<int, Multiton> _Tracker = new Dictionary<int, Multiton> { };
private Multiton()
{
}
public static Multiton GetInstance(int key)
{
//value to return
Multiton item = null;
//lock collection to prevent changes during operation
lock (_Tracker)
{
//if value not found, create and add
if(!_Tracker.TryGetValue(key, out item))
{
item = new Multiton();
//calculate next key
int newIdent = _Tracker.Keys.Max() + 1;
//add item
_Tracker.Add(newIdent, item);
}
}
return item;
}
}
}
How can I make the Singleton session specific?
下面会导致你的问题。
The Singleton holds the reference of the very first user that logs in
at the launch of the web application! All subsequent users who log in
see the name of the earliest logged-in user!
我认为您只需要在每个用户的会话中存储 ApplicationUser
对象。
该机制应如下所示:
- 为您的
ApplicationUser
每个经过身份验证的用户创建一个实例。
- 使用密钥在会话中存储
ApplicationUser
个实例。 (不要担心每个用户使用相同的密钥,因为 ASP.NET HttpSessionState 会为您处理。)
- 如果您想访问每个用户的
ApplicationUser
对象,只需从 HttpSessionState. 获取它即可
- 您可以选择 create/re-create 在 Session_OnStart 或您的基本控制器中进行会话。
- 设置您的 session 设置是否要过期。
我希望这个解决方案对您有意义。 :)
我使用单例-多例混合方法(感谢@Kickaha 提供多例指针)。
public sealed class ApplicationUser
{
// SINGLETON-LIKE REFERENCE TO CURRENT USER ONLY
public static ApplicationUser CurrentUser
{
get
{
return GetUser(HttpContext.Current.User.Identity.Name);
}
}
// MULTITON IMPLEMENTATION (based on
private static Dictionary<string, ApplicationUser> applicationUsers
= new Dictionary<string, ApplicationUser>();
private static ApplicationUser GetUser(string username)
{
ApplicationUser user = null;
//lock collection to prevent changes during operation
lock (applicationUsers)
{
// find existing value, or create a new one and add
if (!applicationUsers.TryGetValue(username, out user))
{
user = new ApplicationUser();
applicationUsers.Add(username, user);
}
}
return user;
}
private ApplicationUser()
{
GetUserDetails(); // determine current user's AD groups and access level
}
// REST OF THE CLASS CODE
public string Name { get { return name; } }
public bool IsAuthorized { get { return isAuthorized; } }
public bool IsAdmin { get { return isAdmin; } }
private string name = HttpContext.Current.User.Identity.Name;
private bool isAuthorized = false;
private bool isAdmin = false;
// Get User details
private void GetUserDetails()
{
// Check user's AD groups and determine isAuthorized and isAdmin
}
}
我的模型和控制器没有变化。
当前用户的对象在 EntryPointController 中实例化:
public abstract class EntryPointController : Controller
{
// this is where the ApplicationUser class in instantiated for the first time
protected ApplicationUser currentUser = ApplicationUser.CurrentUser;
// more code
// all other controllers derive from this
}
在我的模型和其他地方,我可以使用 ApplicationUser.CurrentUser.Name
或 ApplicationUser.CurrentUser.IsAuthorized
等访问当前用户的属性
我的 MVC 应用程序中有一个单例模型 class 以确定登录的用户是否具有 authorization/admin(基于某些 AD 组的成员资格)。此模型 class 需要是单例,以便用户的访问权限可以在首次登录时建立一次并在整个会话期间使用:
public sealed class ApplicationUser
{
// SINGLETON IMPLEMENTATION
// from http://csharpindepth.com/articles/general/singleton.aspx#lazy
public static ApplicationUser CurrentUser { get { return lazy.Value; } }
private static readonly Lazy<ApplicationUser> lazy =
new Lazy<ApplicationUser>(() => new ApplicationUser());
private ApplicationUser()
{
GetUserDetails(); // determine if user is authorized/admin
}
// Public members
public string Name { get { return name; } }
public bool IsAuthorized { get { return isAuthorized; } }
public bool IsAdmin { get { return isAdmin; } }
// Private members
// more code
}
Singleton 在我的 EntryPointController 中首次实例化,所有其他控制器都派生自:
public abstract class EntryPointController : Controller
{
// this is where the ApplicationUser class in instantiated for the first time
protected ApplicationUser currentUser = ApplicationUser.CurrentUser;
// more code
// all other controllers derive from this
}
这个模式允许我在我的应用程序中使用 ApplicationUser.CurrentUser.Name
或 ApplicationUser.CurrentUser.IsAuthorized
等。
然而,问题是这样的:
Singleton 包含在启动 Web 应用程序时登录的第一个用户的引用!所有后续登录的用户都看到最早登录用户的名字!
如何使 Singleton 会话具体化?
我认为您正在寻找 Multiton 模式,其中每个实例都链接到一个键。
这里的例子
http://designpatternsindotnet.blogspot.ie/2012/07/multiton.html
using System.Collections.Generic;
using System.Linq;
namespace DesignPatterns
{
public class Multiton
{
//read-only dictionary to track multitons
private static IDictionary<int, Multiton> _Tracker = new Dictionary<int, Multiton> { };
private Multiton()
{
}
public static Multiton GetInstance(int key)
{
//value to return
Multiton item = null;
//lock collection to prevent changes during operation
lock (_Tracker)
{
//if value not found, create and add
if(!_Tracker.TryGetValue(key, out item))
{
item = new Multiton();
//calculate next key
int newIdent = _Tracker.Keys.Max() + 1;
//add item
_Tracker.Add(newIdent, item);
}
}
return item;
}
}
}
How can I make the Singleton session specific?
下面会导致你的问题。
The Singleton holds the reference of the very first user that logs in at the launch of the web application! All subsequent users who log in see the name of the earliest logged-in user!
我认为您只需要在每个用户的会话中存储 ApplicationUser
对象。
该机制应如下所示:
- 为您的
ApplicationUser
每个经过身份验证的用户创建一个实例。 - 使用密钥在会话中存储
ApplicationUser
个实例。 (不要担心每个用户使用相同的密钥,因为 ASP.NET HttpSessionState 会为您处理。) - 如果您想访问每个用户的
ApplicationUser
对象,只需从 HttpSessionState. 获取它即可
- 您可以选择 create/re-create 在 Session_OnStart 或您的基本控制器中进行会话。
- 设置您的 session 设置是否要过期。
我希望这个解决方案对您有意义。 :)
我使用单例-多例混合方法(感谢@Kickaha 提供多例指针)。
public sealed class ApplicationUser
{
// SINGLETON-LIKE REFERENCE TO CURRENT USER ONLY
public static ApplicationUser CurrentUser
{
get
{
return GetUser(HttpContext.Current.User.Identity.Name);
}
}
// MULTITON IMPLEMENTATION (based on
private static Dictionary<string, ApplicationUser> applicationUsers
= new Dictionary<string, ApplicationUser>();
private static ApplicationUser GetUser(string username)
{
ApplicationUser user = null;
//lock collection to prevent changes during operation
lock (applicationUsers)
{
// find existing value, or create a new one and add
if (!applicationUsers.TryGetValue(username, out user))
{
user = new ApplicationUser();
applicationUsers.Add(username, user);
}
}
return user;
}
private ApplicationUser()
{
GetUserDetails(); // determine current user's AD groups and access level
}
// REST OF THE CLASS CODE
public string Name { get { return name; } }
public bool IsAuthorized { get { return isAuthorized; } }
public bool IsAdmin { get { return isAdmin; } }
private string name = HttpContext.Current.User.Identity.Name;
private bool isAuthorized = false;
private bool isAdmin = false;
// Get User details
private void GetUserDetails()
{
// Check user's AD groups and determine isAuthorized and isAdmin
}
}
我的模型和控制器没有变化。
当前用户的对象在 EntryPointController 中实例化:
public abstract class EntryPointController : Controller
{
// this is where the ApplicationUser class in instantiated for the first time
protected ApplicationUser currentUser = ApplicationUser.CurrentUser;
// more code
// all other controllers derive from this
}
在我的模型和其他地方,我可以使用 ApplicationUser.CurrentUser.Name
或 ApplicationUser.CurrentUser.IsAuthorized
等访问当前用户的属性