valor - pasar datos de una clase a otra en c#
C#: Entonces, si una clase estática es una mala práctica para almacenar información de estado global, ¿cuál es una buena alternativa que ofrece la misma conveniencia? (3)
He estado notando que las clases estáticas reciben muchas malas repeticiones en SO con respecto a ser usadas para almacenar información global. (Y las variables globales son despreciadas en general) Me gustaría saber cuál es una buena alternativa para mi ejemplo a continuación ...
Estoy desarrollando una aplicación WPF, y muchas vistas de los datos recuperados de mi base de datos se filtran en función de la ID del usuario registrado actualmente. Del mismo modo, ciertos puntos en mi aplicación solo deberían ser accesibles para los usuarios que se consideran ''administradores''.
Actualmente estoy almacenando un loginInUserId y un isAdmin bool en una clase estática.
Varias partes de mi aplicación necesitan esta información y me pregunto por qué no es ideal en este caso, y cuáles son las alternativas. Parece muy conveniente ponerse en marcha.
Lo único que se me ocurre como alternativa es usar un Contenedor de IoC para inyectar una instancia de Singleton en las clases que necesitan esta información global, las clases podrían entonces hablar con esto a través de su interfaz. Sin embargo, ¿es esto excesivo / lo que me lleva a la parálisis del análisis?
Gracias de antemano por cualquier información.
Actualizar
Así que me estoy inclinando hacia la inyección de dependencia a través de IoC, ya que se prestaría mejor a la capacidad de prueba, ya que podría cambiar un servicio que proporciona información "global" con un simulacro si es necesario. Supongo que lo que queda es si el objeto inyectado debe ser un singleton o estático. :-)
Probablemente escogerá la respuesta de Mark aunque espere ver si hay más discusión. No creo que haya una manera correcta como tal. Solo me interesa ver alguna discusión que me ilumine ya que parece haber muchas declaraciones "esto es malo", "es malo" en algunas preguntas similares sin alternativas constructivas.
Actualización # 2 Así que elegí la respuesta de Robert, ya que es una gran alternativa (supongo que alternativa es una palabra extraña, probablemente la de One True Way, ya que está integrada en el marco). No me está forzando a crear una clase estática / singleton (aunque es hilo estático).
Lo único que todavía me da curiosidad es cómo se habría abordado esto si los datos "globales" que tenía que almacenar no tuvieran nada que ver con la Autenticación de usuario.
Hay muchas otras respuestas aquí en SO que explican por qué la estática (incluida Singleton) es mala para ti, así que no entraré en detalles (aunque sinceramente respaldo esos sentimientos).
Como regla general, DI es el camino a seguir. Luego puede inyectar un servicio que le puede decir todo lo que necesita saber sobre el medio ambiente.
Sin embargo, dado que se trata de información de usuario, Thread.CurrentPrincipal puede ser una alternativa viable (aunque es Thread Static).
Para su comodidad, puede ajustar una clase de usuario fuertemente tipada a su alrededor .
Intentaría un enfoque diferente. La clase de datos estáticos te meterá en problemas, esto es por experiencia. Podrías tener un objeto User (ver la respuesta de Robert Paulson para una excelente manera de hacerlo) y pasarlo a cada objeto a medida que lo construyes; podría funcionar para ti, pero obtendrás un código de plantilla que simplemente se repite en todas partes. .
Puede almacenar todos sus objetos en una base de datos / archivo cifrado con los permisos necesarios y luego cargarlos dinámicamente según sus permisos de usuario. Con un simple formulario de administrador en la base de datos, es bastante fácil de mantener (el archivo es un poco más difícil).
Puede crear un objeto RequiresAdminPermissionAttribute para aplicarlo a todos sus objetos sensibles y verificarlo en tiempo de ejecución frente a su objeto User para cargarlo de forma condicional.
Si bien la ruta en la que te encuentras ahora tiene sus méritos, creo que hay algunas opciones mejores para probar.
Olvídese de Singletons y datos estáticos. Ese patrón de acceso le va a fallar en algún momento.
Cree su propio IPrincipal personalizado y reemplace Thread.CurrentPrincipal con él en un punto donde el inicio de sesión sea apropiado. Por lo general, conserva la referencia al IIdentity actual.
En su rutina donde el usuario inicia sesión, por ejemplo, ha verificado sus credenciales, adjunte su principal personalizado al hilo.
IIdentity currentIdentity = System.Threading.Thread.CurrentPrincipal.Identity;
System.Threading.Thread.CurrentPrincipal
= new MyAppUser(1234,false,currentIdentity);
en ASP.Net también configuraría HttpContext.Current.User
al mismo tiempo
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
}
Esta es la forma preferida de hacerlo, y está en el marco por una razón. De esta forma puede llegar al usuario de forma estándar.
También hacemos cosas como agregar propiedades si el usuario es anónimo (desconocido) para admitir un escenario de escenarios mixtos de autenticación anónima / iniciada.
Adicionalmente:
- aún puede usar DI (Inyección de Dependencia) inyectando el Servicio de Membresía que recupera / verifica las credenciales.
- puede usar el patrón Repository para obtener acceso al MyAppUser actual (aunque podría decirse que está haciendo el casting a MyAppUser para usted, puede haber beneficios para esto)