C# : So if a static class is bad practice for storing global state info, what's a good alternative that offers the same convenience?

前端 未结 3 1949
野趣味
野趣味 2020-12-24 02:13

I\'ve been noticing static classes getting a lot of bad rep on SO in regards to being used to store global information. (And global variables being scorned upon in general)

3条回答
  •  暖寄归人
    2020-12-24 02:29

    Forget Singletons and static data. That pattern of access is going to fail you at some time.

    Create your own custom IPrincipal and replace Thread.CurrentPrincipal with it at a point where login is appropriate. You typically keep the reference to the current IIdentity.

    In your routine where the user logs on, e.g. you have verified their credentials, attach your custom principal to the Thread.

    IIdentity currentIdentity = System.Threading.Thread.CurrentPrincipal.Identity;
    System.Threading.Thread.CurrentPrincipal 
       = new MyAppUser(1234,false,currentIdentity);
    

    in ASP.Net you would also set the HttpContext.Current.User at the same time

    public class MyAppUser : IPrincipal
    {
       private IIdentity _identity;
    
       private UserId { get; private set; }
       private IsAdmin { get; private set; } // perhaps use IsInRole
    
       MyAppUser(userId, isAdmin, iIdentity)
       {
          if( iIdentity == null ) 
             throw new ArgumentNullException("iIdentity");
          UserId = userId;
          IsAdmin = isAdmin;
          _identity = iIdentity;          
       }
    
       #region IPrincipal Members
       public System.Security.Principal.IIdentity Identity
       {
          get { return _identity; }
       }
    
       // typically this stores a list of roles, 
       // but this conforms with the OP question
       public bool IsInRole(string role)
       {  
          if( "Admin".Equals(role) )
             return IsAdmin;     
    
          throw new ArgumentException("Role " + role + " is not supported");
       }
       #endregion
    }
    

    This is the preferred way to do it, and it's in the framework for a reason. This way you can get at the user in a standard way.

    We also do things like add properties if the user is anonymous (unknown) to support a scenario of mixed anonymous/logged-in authentication scenarios.

    Additionally:

    • you can still use DI (Dependancy Injection) by injecting the Membership Service that retrieves / checks credentials.
    • you can use the Repository pattern to also gain access to the current MyAppUser (although arguably it's just making the cast to MyAppUser for you, there can be benefits to this)

提交回复
热议问题