C# 如何使MVC5中的单例特定于会话?

C# 如何使MVC5中的单例特定于会话?,c#,asp.net-mvc,asp.net-mvc-5,singleton,C#,Asp.net Mvc,Asp.net Mvc 5,Singleton,我的MVC应用程序中有一个单例模型类,用于确定登录的用户是否具有授权/管理权限(基于特定广告组的成员资格)。此模型类需要是单例,以便用户的访问权限可以在首次登录时建立一次,并在整个会话中使用: public sealed class ApplicationUser { // SINGLETON IMPLEMENTATION // from http://csharpindepth.com/articles/general/singleton.aspx#lazy publi

我的MVC应用程序中有一个单例模型类,用于确定登录的用户是否具有授权/管理权限(基于特定广告组的成员资格)。此模型类需要是单例,以便用户的访问权限可以在首次登录时建立一次,并在整个会话中使用:

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
}
此模式允许我在整个应用程序中使用
ApplicationUser.CurrentUser.Name
ApplicationUser.CurrentUser.IsAuthorized

然而,问题是:
Singleton拥有在web应用程序启动时登录的第一个用户的引用!所有后续登录的用户都会看到最早登录的用户的名称


如何使单例会话特定?

我想您正在寻找多例模式,其中每个实例都链接到一个键

这里有一个例子

使用System.Collections.Generic;
使用System.Linq;
命名空间设计模式
{
公共级多音频
{
//用于跟踪多音的只读字典
私有静态IDictionary _Tracker=新字典{};
私有多通()
{
}
公共静态Multiton GetInstance(int键)
{
//返回值
Multiton项=空;
//锁定集合以防止在操作过程中发生更改
锁定(_跟踪器)
{ 
//如果未找到值,则创建并添加
如果(!\u Tracker.TryGetValue(输入,输出项))
{
item=新的Multiton();
//计算下一个关键点
int newIdent=_Tracker.Keys.Max()+1;
//添加项
_添加(新标识,项目);
}
}
退货项目;
}
}
}
如何使单例会话特定

将导致您的问题如下

Singleton保存第一个登录用户的引用 在web应用程序启动时!所有后续登录的用户 查看最早登录的用户的名称

我认为您只需要将
ApplicationUser
对象存储在每个用户的会话中

机制应如下所示:

  • 为您的
    应用程序用户
    每个经过身份验证的用户创建一个实例
  • ApplicationUser
    实例存储在具有密钥的会话中。(不要担心每个用户拥有相同的密钥,因为ASP.NET将为您处理该密钥。)
  • 如果您想访问每个用户的
    应用程序用户
    对象,只需从中获取即可
  • 您可以选择在基本控制器中创建/重新创建会话
  • 如果希望设置过期或过期,请设置设置

  • 我希望这个解决方案对您有意义。:)

    我使用了混合单态多态方法(感谢@Kickaha的多态指针)


    在我的模型和其他任何地方,我都可以使用
    ApplicationUser.CurrentUser.Name
    ApplicationUser.CurrentUser.IsAuthorized
    等访问当前用户的属性。

    谢谢,您的指针帮助了我!我已经发布了我的工作解决方案。谢谢!我不需要依赖
    会话
    对象就可以完成。请参阅我的工作解决方案。注销后如何从applicationUsers对象中删除用户。否则它将在applicationUsers对象中保持可用。@Oasis:捕捉得好你能解决“绿洲”所指的问题吗?我也在研究类似的解决方案。。。
    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
    }
    
    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;
            }
        }
    }
    
    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
        }
    }
    
    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
    }