我的MVC应用程序中有一个Singleton模型类,用于确定登录的用户是否具有授权/ admin(基于某些AD组的成员身份)。此模型类需要是Singleton,以便用户的访问权限可以在首次登录时建立一次并在整个会话中使用:
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会话具体化?
答案 0 :(得分:3)
我使用混合的Singleton-Multiton方法(感谢@Kickaha用于Multiton指针)。
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 http://stackoverflow.com/a/32238734/979621)
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
等访问当前用户的属性。
答案 1 :(得分:1)
如何使Singleton会话具体化?
将在下面导致您的问题。
Singleton拥有第一个登录用户的引用 在Web应用程序的启动!登录的所有后续用户 查看最早登录用户的名字!
我认为您只需要将ApplicationUser
对象存储在每个用户的会话中。
机制应如下所示:
ApplicationUser
的实例。ApplicationUser
实例存储在带密钥的会话中。 (不要担心每个用户使用相同的密钥,因为ASP.NET HttpSessionState会为您处理它。)ApplicationUser
个对象,只需从HttpSessionState获取。我希望这个解决方案对你有意义。 :)